add interactive page for p-adics
This commit is contained in:
parent
4f09c75006
commit
9786cb0f61
56
interactive/p-adics/index.qmd
Normal file
56
interactive/p-adics/index.qmd
Normal file
@ -0,0 +1,56 @@
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
```{ojs}
|
||||
{{< include ./showAdic.ojs >}}
|
||||
```
|
||||
|
||||
About
|
||||
-----
|
||||
|
||||
The Wikipedia article on the [*p*-adic valuation](https://en.wikipedia.org/wiki/P-adic_valuation)
|
||||
contains [a figure](https://commons.wikimedia.org/wiki/File:2adic12480.svg) whose description
|
||||
provides a way to map *p*-adics into the complex numbers[^1].
|
||||
The gist is to construct a Fourier series over truncations of numbers.
|
||||
Each term of the series is weighted by a geometrically decreasing coefficient *c*.
|
||||
|
||||
$$
|
||||
[...d_2 d_1 d_0]_p \mapsto e^{2\pi i [d_0] / p}
|
||||
+ c e^{2\pi i [d_1 d_0] / p^2}
|
||||
+ c^2 e^{2\pi i [d_2 d_1 d_0] / p^2}
|
||||
+ ... \\
|
||||
f_N(d; p) = \sum_{n = 0}^N c^n e^{2\pi i \cdot [d_{n:0}]_p / p^{n + 1}}
|
||||
$$
|
||||
|
||||
Assuming the first term dominates, one way of interpreting this is that we place numbers
|
||||
around the unit circle according to their one's place.
|
||||
Then, we offset each by smaller circles, each centered on the last, using more and more digits.
|
||||
This produces a fractal pattern that looks like a wheel with *p* spokes.
|
||||
At each point on where the spokes meet the rim, there is another smaller wheel with *p* spokes,
|
||||
ad infinitum.
|
||||
|
||||
This is somewhat visible in the Wikimedia diagram.
|
||||
All of the odd numbers are at the left side of the diagram, since the leading term of the series for them
|
||||
is negative one.
|
||||
The odd numbers are further split into those of the forms $4k + 1$ and $4k + 3$.
|
||||
|
||||
Each of the inputs corresponds to something from the above formula.
|
||||
|
||||
- *b*, the base of the expansions.
|
||||
- Integers are converted to their representations in base *b*,
|
||||
which are sequences of digits (*d* in the above formula).
|
||||
- *p*, the base used in the embedding.
|
||||
- The same *p* that appears in the above formula.
|
||||
- Truncations of digit sequences ($d_{n:0}$) are interpreted as strings in base *p*,
|
||||
then divided by $p^{n+1}$.
|
||||
- *c*, the geometric constant.
|
||||
- Smaller *c* means more tightly packed points.
|
||||
|
||||
Additionally, instead of using an integer base, you can also use either *κ*-adic representation.
|
||||
If using an integer base, only one thousand twenty four (1024) points will be calculated.
|
||||
Note also that only fifteen terms of the series are used ($N = 15$).
|
||||
|
||||
|
||||
[^1]: Taken from the paper "Fractal geometry for images of continuous embeddings of p-adic
|
||||
numbers and solenoids into Euclidean spaces" (DOI: 10.1007/BF02073866).
|
||||
69
interactive/p-adics/showAdic.ojs
Normal file
69
interactive/p-adics/showAdic.ojs
Normal file
@ -0,0 +1,69 @@
|
||||
// Convert x into its expansion in base b, as an array of integers (ascending powers of b)
|
||||
toBase = (b, x) => {
|
||||
if (x == 0) { return [0] }
|
||||
|
||||
let ret = [];
|
||||
while (x > 0) {
|
||||
ret.push(x % b);
|
||||
x = Math.floor(x / b);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
// Interpret xs as an expansion in base b (ascending powers of b)
|
||||
fromBase = (b, xs) => {
|
||||
let plval = 1
|
||||
return xs.reduce((a, x) => {
|
||||
let new_a = x * plval;
|
||||
plval *= b;
|
||||
return a + new_a;
|
||||
}, 0)
|
||||
}
|
||||
|
||||
// Map an expansion to a complex number (as a 2-array).
|
||||
// The expansion is interpreted in base `b`.
|
||||
// `n` terms of the series are used, with geometric ratio `c`
|
||||
adicAngles = (expansion, b, n, c) => {
|
||||
return d3.range(n).reduce((a, i) => {
|
||||
let angle = fromBase(b, expansion.slice(null, i + 1)) / (b ** (i + 1));
|
||||
let x = c**i * Math.cos(2 * Math.PI * angle);
|
||||
let y = c**i * Math.sin(2 * Math.PI * angle);
|
||||
return [a[0] + x, a[1] + y];
|
||||
}, [0, 0]);
|
||||
}
|
||||
|
||||
pointCount = 1024;
|
||||
expansions = d3.range(pointCount).map((x) => toBase(base, x));
|
||||
|
||||
embedding = expansions.map(
|
||||
(x) => adicAngles(x, embedBase, 15, geometric)
|
||||
);
|
||||
|
||||
viewof base = Inputs.range([2, 10], {
|
||||
value: 2,
|
||||
step: 1,
|
||||
label: "Base of expansions (b)",
|
||||
});
|
||||
|
||||
viewof embedBase = Inputs.range([2, 10], {
|
||||
value: 2,
|
||||
step: 0.2,
|
||||
label: "Embedding base (p)",
|
||||
});
|
||||
|
||||
viewof geometric = Inputs.range([0.005, 0.995], {
|
||||
value: 0.9,
|
||||
step: 0.005,
|
||||
label: "Geometric ratio (c)",
|
||||
});
|
||||
|
||||
plot = Plot.plot({
|
||||
grid: true,
|
||||
inset: 10,
|
||||
// aspectRatio: 1,
|
||||
width: 640,
|
||||
height: 480,
|
||||
marks: [
|
||||
Plot.dot(embedding, { r: 1 })
|
||||
]
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user