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