add interactive section to 4.appendix

This commit is contained in:
queue-miscreant 2025-03-02 01:09:07 -06:00
parent 9786cb0f61
commit e5946df6ec
5 changed files with 2164 additions and 36 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,8 @@ date: "2021-02-09"
date-modified: "2025-02-12" date-modified: "2025-02-12"
categories: categories:
- algebra - algebra
- python - haskell
- interactive
execute: execute:
eval: false eval: false
--- ---
@ -30,7 +31,7 @@ A more unusual consequence of this is that despite the initial choice of alphabe
[negative numerals could be cleared](../#all-positive) [negative numerals could be cleared](../#all-positive)
from the expansion by using an extra-greedy borrow. from the expansion by using an extra-greedy borrow.
These choices actually only differ in only one significant way: the choice of integer division function. There is only one significant difference in how the two are implemented: the choice of integer division function.
In Haskell, there exists both `quotRem` and `divMod`, with the two disagreeing on negative remainders: In Haskell, there exists both `quotRem` and `divMod`, with the two disagreeing on negative remainders:
::: {.row layout-ncol="2"} ::: {.row layout-ncol="2"}
@ -43,13 +44,13 @@ divMod (-27) 5
``` ```
::: :::
We can factor our choice out of our two digit-wide carry function by presenting it as an argument: We can factor our choice out of our two digit-wide carry function by passing it as an argument:
```{haskell} ```{haskell}
-- Widened carry of a particular repeated amount -- Widened carry of a particular repeated amount
-- i.e., for carry qr 2, the carry is 22 = 100 -- i.e., for carry qr 2, the carry is 22 = 100
carry2' qr b = carry' [] carry2 qr b = carry2' []
where carry' zs (x:y:z:xs) where carry2' zs (x:y:z:xs)
| q == 0 = carry' (x:zs) (y:z:xs) -- try carrying at a higher place value | q == 0 = carry' (x:zs) (y:z:xs) -- try carrying at a higher place value
| otherwise = foldl (flip (:)) ys zs -- carry here | otherwise = foldl (flip (:)) ys zs -- carry here
where ys = r : y-x+r : z+q : xs where ys = r : y-x+r : z+q : xs
@ -61,8 +62,8 @@ We happen to know the root for $\langle 2, 2|$ is $\sqrt 3 + 1$, so using an app
we can check that we get a roughly constant value by evaluating at each step. we can check that we get a roughly constant value by evaluating at each step.
```{haskell} ```{haskell}
{-| layout-ncol: 2 -} -- | layout-ncol: 2
{-| code-fold: true -} -- | code-fold: true
import IHaskell.Display import IHaskell.Display
@ -74,8 +75,8 @@ pairEval x = (,) <*> hornerEval x . map fromIntegral
-- Directly expand the integer `n`, using the `carry` showing each step for `count` steps -- Directly expand the integer `n`, using the `carry` showing each step for `count` steps
expandSteps count carry n = take count $ iterate carry $ n:replicate count 0 expandSteps count carry n = take count $ iterate carry $ n:replicate count 0
cendree4QuotRem10Steps = map (pairEval (sqrt 3 + 1)) $ expandSteps 10 (carry2' quotRem 2) 4 cendree4QuotRem10Steps = map (pairEval (sqrt 3 + 1)) $ expandSteps 10 (carry2 quotRem 2) 4
cendree4DivMod10Steps = map (pairEval (sqrt 3 + 1)) $ expandSteps 10 (carry2' divMod 2) 4 cendree4DivMod10Steps = map (pairEval (sqrt 3 + 1)) $ expandSteps 10 (carry2 divMod 2) 4
markdown "`quotRem`" markdown "`quotRem`"
markdown "`divMod`" markdown "`divMod`"
@ -101,14 +102,14 @@ Since the `divMod` implementation clears negative numbers from expansions, we ca
The result is another chaotic series: The result is another chaotic series:
```{haskell} ```{haskell}
cendree2DivModCycleExpansion = take 11 $ iterate (carry2' divMod 2) $ take 15 $ 0:0:cycle [1,-1] cendree2DivModCycleExpansion = take 11 $ iterate (carry2 divMod 2) $ take 15 $ 0:0:cycle [1,-1]
putStrLn . unlines . map show $ cendree2DivModCycleExpansion putStrLn . unlines . map show $ cendree2DivModCycleExpansion
``` ```
We get the same series if we expand 2 directly (which we can also use to check its validity): We get the same series if we expand 2 directly (which we can also use to check its validity):
```{haskell} ```{haskell}
cendree2DivMod15Steps = map (pairEval (sqrt 3 + 1)) $ expandSteps 15 (carry2' divMod 2) 2 cendree2DivMod15Steps = map (pairEval (sqrt 3 + 1)) $ expandSteps 15 (carry2 divMod 2) 2
putStrLn . unlines . map show $ cendree2DivMod15Steps putStrLn . unlines . map show $ cendree2DivMod15Steps
``` ```
@ -116,7 +117,7 @@ We can *also* use this to get a series for negative one, a number which has a te
in the balanced alphabet. in the balanced alphabet.
```{haskell} ```{haskell}
cendreeNeg1DivMod15Steps = map (pairEval (sqrt 3 + 1)) $ expandSteps 15 (carry2' divMod 2) (-1) cendreeNeg1DivMod15Steps = map (pairEval (sqrt 3 + 1)) $ expandSteps 15 (carry2 divMod 2) (-1)
putStrLn . unlines . map show $ cendreeNeg1DivMod15Steps putStrLn . unlines . map show $ cendreeNeg1DivMod15Steps
``` ```
@ -126,7 +127,7 @@ If we take the last iterate of this, increment the zeroth place value, and apply
```{haskell} ```{haskell}
cendree0FromNeg1DivMod = (\(x:xs) -> (x + 1):xs) $ snd $ last cendreeNeg1DivMod15Steps cendree0FromNeg1DivMod = (\(x:xs) -> (x + 1):xs) $ snd $ last cendreeNeg1DivMod15Steps
cendree0IncrementSteps = map (pairEval (sqrt 3 + 1)) $ take 15 $ iterate (carry2' divMod 2) cendree0FromNeg1DivMod cendree0IncrementSteps = map (pairEval (sqrt 3 + 1)) $ take 15 $ iterate (carry2 divMod 2) cendree0FromNeg1DivMod
putStrLn . unlines . map show $ cendree0IncrementSteps putStrLn . unlines . map show $ cendree0IncrementSteps
``` ```
@ -139,27 +140,34 @@ Actually demonstrating this and proving it is left as an exercise.
Are these really -adic? Are these really -adic?
----------------------- -----------------------
Perhaps it is still unconvincing that expanding the integers in this way gives something that is Perhaps it is still unconvincing that expanding the integers in this way gives something
indeed related to *p*-adics. indeed related to *p*-adics.
The Wikipedia article on the [*p*-adic valuation](https://en.wikipedia.org/wiki/P-adic_valuation) In fact, since the expansions are in binary or (balanced) ternary, the integers should just
contains [a figure](https://commons.wikimedia.org/wiki/File:2adic12480.svg) whose description be a subset of the 2-adics or 3-adics.
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*.
$$ Still, wanted to see what these numbers actually "look" like, so I whipped up an interactive diagram.
[...d_2 d_1 d_0]_p \mapsto e^{2\pi i [d_0] / p} You should definitely see [this page](/interactive/adic/) for more information, but
+ c e^{2\pi i [d_1 d_0] / p^2} the gist is that *p*-adics can be sent into the complex plane in a fractal-like way.
+ c^2 e^{2\pi i [d_2 d_1 d_0] / p^2}
+ ... \\
f(d; p) = \sum_{n = 0}^N c^n e^{2\pi i \cdot [d_{n:0}] / 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 wheel with *p* spokes, ad infinitum.
[^1]: Taken from the paper "Fractal geometry for images of continuous embeddings of p-adic ```{ojs}
numbers and solenoids into Euclidean spaces" (DOI: 10.1007/BF02073866). // | echo: false
{{< include ./showAdicWithKappa.ojs >}}
```
First, notice that with $b = 2$ and $p = 2$, switching between the "b-adic" option
and the "*κ*-adic" option appears cause some points to appear and disappear.
This is easiest to see when $c \approx 0.5$.
Next, notice that when plotting the *κ*-adics, some self-similarity different from the 2- and 3-adics
can be observed for $c \approx 0.75$.
There appear to be four clusters of points, with the topmost and rightmost appearing to be
similar to one another.
Within these two clusters, the rightmost portion of them appears to be the same shape
as the larger figure.
This is actually great news -- if you switch between the *κ*-adics and the "random binary" option,
you can see that the latter option tends to the same pattern as the 2-adics.
Thus, even if the expansions for the integers are individually chaotic, together they possess a
much different structure than pure randomness.

View File

@ -0,0 +1,66 @@
/*
FileAttachments:
./cendree_DivMod_count_1024_256_digits.csv: ./cendree_DivMod_count_1024_256_digits.csv
./cendree_QuotRem_count_1024_256_digits.csv: ./cendree_QuotRem_count_1024_256_digits.csv
*/
// Import expansions from file.
// Odd numbers are injected by replacing the first entry of each row with "1"
asIntegers = (x) => {
let xs = x.split("\n").map((y) => y.split(",").map((z) => +z))
return [...xs, ...(xs.map((ys) => ys.with(0, 1)))]
};
adicExpansionsDivMod = FileAttachment(
"./cendree_DivMod_count_1024_256_digits.csv"
).text().then(asIntegers);
adicExpansionsQuotRem = FileAttachment(
"./cendree_QuotRem_count_1024_256_digits.csv"
).text().then(asIntegers);
import { expansions as oldExpansions } with { base as base } from "../../../../interactive/p-adics/showAdic.ojs";
expansionsOrAdics = baseSelector == "b-adic"
? oldExpansions
: baseSelector == "κ-adic, balanced"
? adicExpansionsDivMod
: baseSelector == "κ-adic, binary"
? adicExpansionsQuotRem
: d3.range(adicExpansionsQuotRem.length / 10).map(() => d3.range(15).map(() => +(Math.random() > 0.5)))
import { plot } with {
expansionsOrAdics as expansions,
embedBase as embedBase,
geometric as geometric,
} from "../../../../interactive/p-adics/showAdic.ojs";
viewof baseSelector = Inputs.radio([
"b-adic",
"κ-adic, balanced",
"κ-adic, binary",
"Random Binary",
], {
value: "b-adic",
label: "Expansions",
});
viewof base = Inputs.range([2, 5], {
value: 2,
step: 1,
label: "Base of expansions (b)",
disabled: baseSelector != "b-adic",
});
viewof embedBase = Inputs.range([2, 5], {
value: 2,
step: 0.1,
label: "Embedding base (p)",
});
viewof geometric = Inputs.range([0.005, 0.995], {
value: 0.9,
step: 0.005,
label: "Geometric ratio (c)",
});
plot

View File

@ -1,3 +1,5 @@
import Data.List (intercalate)
-- Widened borrow of a particular repeated amount -- Widened borrow of a particular repeated amount
-- i.e., for borrow2 qr 2, the borrow is 22 = 100 -- i.e., for borrow2 qr 2, the borrow is 22 = 100
-- `qr` is an integer division function returning the quotient and remainder. -- `qr` is an integer division function returning the quotient and remainder.
@ -65,7 +67,11 @@ data QRMethod = QuotRem | DivMod deriving Show
qrMethod QuotRem = quotRem qrMethod QuotRem = quotRem
qrMethod DivMod = divMod qrMethod DivMod = divMod
cendreeEvens :: QRMethod -> Int -> Int -> IO () cendreeEvens' :: QRMethod -> Int -> Int -> [[Int]]
cendreeEvens qr m n = writeFile fn $ unlines $ take m $ map show $ evensQR qr' n 2 $ truncadicQR qr' (n + 2) 2 $ 2:repeat 0 cendreeEvens' qr m n = take m $ evensQR qr' n 2 $ truncadicQR qr' (n + 2) 2 $ 2:repeat 0
where qr' = qrMethod qr where qr' = qrMethod qr
fn = "cendree_" ++ show qr ++ "_count_" ++ show m ++ "_" ++ show n ++ "_digits.txt"
cendreeEvens :: QRMethod -> Int -> Int -> IO ()
cendreeEvens qr m n = writeFile fn $ display $ cendreeEvens' qr m n
where display = unlines . map (intercalate "," . map show)
fn = "cendree_" ++ show qr ++ "_count_" ++ show m ++ "_" ++ show n ++ "_digits.csv"