add interactive page for p-adics

This commit is contained in:
queue-miscreant 2025-03-02 01:08:50 -06:00
parent 4f09c75006
commit 9786cb0f61
2 changed files with 125 additions and 0 deletions

View 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).

View 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 })
]
});