281 lines
9.7 KiB
Plaintext

---
title: "Polynomial Counting 4, Addendum"
description: |
Additional notes on irrational -adic expansions, including complex embeddings thereof.
format:
html:
html-math-method: katex
date: "2025-03-03"
categories:
- algebra
- haskell
- interactive
---
```{haskell}
-- | echo: false
import IHaskell.Display
```
After converting my original [Two 2's post](../), I grew pleased with making its diagrams
and content more reproducible.
However, I noticed some things which required further examination.
First, let's write out a double-width carry function more concretely in Haskell.
```{haskell}
-- | echo: true
-- Widened carry of a particular repeated amount
-- i.e., for carry2 2, the carry is 22 = 100
carry2 b = carry2' []
where carry2' zs (x:y:z:xs)
| q == 0 = carry2' (x:zs) (y:z:xs) -- try carrying at a higher place value
| otherwise = foldl (flip (:)) ys zs -- carry here
where ys = r : y-x+r : z+q : xs
(q, r) = x `quotRem` b
```
In the parent post, it was discussed that the integer four has a non-repeating expansion
when expressed as an *κ*-adic integer.
Let's put this to the test by writing out each step for producing expansions of two and four.
We'll also test these expansions by evaluating them at an approximation of $\kappa = \sqrt 3 + 1$.
We should roughly get two and four at each step.
```{haskell}
-- | code-fold: true
-- | layout-ncol: 2
-- 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
-- Horner evaluation on polynomials of ascending powers
hornerEval x = foldr (\c a -> a * x + c) 0
-- Pair a polynomial with its evaluation at x
pairEval x = (,) <*> hornerEval x . map fromIntegral
adicTwoSteps = map (pairEval (sqrt 3 + 1)) $ expandSteps 10 (carry2 2) 2
adicFourSteps = map (pairEval (sqrt 3 + 1)) $ expandSteps 10 (carry2 2) 4
markdown "Iteratively carrying \"2\""
markdown "Iteratively carrying \"4\""
putStrLn . unlines . map show $ adicTwoSteps
putStrLn . unlines . map show $ adicFourSteps
```
Note that when an list is displayed in this post, it should be interpreted as an expansion
in increasing powers.
Expansions of *κ*-adics
-----------------------
In the original post, we ignored expansions other than the chaotic expansions of four.
Consider that we can use *two different* expansions for three, since we are using a balanced alphabet:
```{haskell}
-- | code-fold: true
-- | layout-ncol: 2
markdown "Increment two:"
markdown "Decrement three:"
adicThree = (1:) $ tail $ fst $ last adicTwoSteps
print adicThree
adicThree' = ((-1):) $ tail $ fst $ last adicFourSteps
print adicThree'
```
For convenience (and correctness), we'll retain the carry heads rather than truncating them.
How can we be sure that both of these are expansions of three?
Easy. Just negate every term of one of them, then add them together to see if they cancel.
```{haskell}
maybeZero = take 10 $ iterate (carry2 2) $ zipWith (+) adicThree (map negate adicThree')
putStrLn . unlines . map show $ maybeZero
```
As you can see, eventually we completely clear the number and just get list of zeros.
Which of these expansions is more valid?
I would argue that we should prefer expansions obtained by incrementing, since the natural numbers
are built in the same way.
This is flimsy, though. By doing this, negative one will never appear in the one's place.
It's also worth pointing out that we only have this choice at odd numbers.
At even numbers, the one's place is always zero.
It's easy to see why this is the case -- if there's a "2" in the one's place, it can be carried,
just like in binary.
Balanced vs. Binary *κ*-adics
-----------------------------
A more unusual consequence of the carry is that despite the initial choice of alphabet,
[negative numerals can be cleared](../#all-positive)
from the expansion by using an extra-greedy borrow.
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.
```{haskell}
-- | code-fold: true
-- | layout-ncol: 2
markdown "`quotRem`"
markdown "`divMod`"
print $ quotRem (-27) 5
print $ divMod (-27) 5
```
We can factor our choice out of our two digit-wide carry function by passing it as an argument:
```{haskell}
-- | echo: true
carry2QR qr b = carry2QR' []
where carry2QR' zs (x:y:z:xs)
| q == 0 = carry2QR' (x:zs) (y:z:xs) -- try carrying at a higher place value
| otherwise = foldl (flip (:)) ys zs -- carry here
where ys = r : y-x+r : z+q : xs
(q, r) = x `qr` b
```
Now, let's compare the iterates of the two options by applying them to "4":
```{haskell}
-- | code-fold: true
-- | layout-ncol: 2
cendree4QuotRem10Steps = map (pairEval (sqrt 3 + 1)) $ expandSteps 10 (carry2QR quotRem 2) 4
cendree4DivMod10Steps = map (pairEval (sqrt 3 + 1)) $ expandSteps 10 (carry2QR divMod 2) 4
markdown "`quotRem`"
markdown "`divMod`"
putStrLn . unlines . map show $ cendree4QuotRem10Steps
putStrLn . unlines . map show $ cendree4DivMod10Steps
```
Fortunately, regardless of which function we pick, the evaluation roughly gives four at each step.
Note that since `quotRem` allows negative remainders, implementing the carry with it causes
negative numbers to show up in our expansions.
Conversely, negative numbers *cannot* show up if we use `divMod`.
### Chaos before Four
Recall again the series for two in the *κ*-adics:
$$
2 = ...1\bar{1}1\bar{1}1\bar{1}100_{\kappa}
$$
Since the `divMod` implementation clears negative numbers from expansions, we can try using it on this series.
The result is another chaotic series:
```{haskell}
cendree2DivModCycleExpansion = take 11 $
iterate (carry2QR divMod 2) $ take 15 $ 0:0:cycle [1,-1]
putStrLn . unlines . map show $ cendree2DivModCycleExpansion
```
Note that in this case, we're truncating the alternating series!
This means that naively evaluating the series as before will not give the correct value.
To check the validity of this series, we can check that we get the same series before the truncated elements
by expanding 2 directly:
```{haskell}
cendree2DivMod15Steps = map (pairEval (sqrt 3 + 1)) $
expandSteps 15 (carry2QR divMod 2) 2
putStrLn . unlines . map show $ cendree2DivMod15Steps
```
Up to the carry head, the series are the same.
We can do the same thing to get a series for negative one, a number which has a terminating expansion
in the balanced alphabet.
```{haskell}
cendreeNeg1DivMod15Steps = map (pairEval (sqrt 3 + 1)) $
expandSteps 15 (carry2QR divMod 2) (-1)
putStrLn . unlines . map show $ cendreeNeg1DivMod15Steps
```
The most natural property of negative one should be that if we add one to it, we get zero.
If we take the last iterate of this, increment the zeroth place value, and apply the carry,
we find that everything clears properly.
```{haskell}
cendree0FromNeg1DivMod = (\(x:xs) -> (x + 1):xs) $ fst $ last cendreeNeg1DivMod15Steps
cendree0IncrementSteps = map (pairEval (sqrt 3 + 1)) $ take 15 $
iterate (carry2QR divMod 2) cendree0FromNeg1DivMod
putStrLn . unlines . map show $ cendree0IncrementSteps
```
Naturally, it should be possible to use the the expansions of negative one and two in tandem on any
series in the balanced alphabet to convert it to the binary alphabet.
Actually demonstrating this and proving it is left as an exercise.
Are these really -adic?
-----------------------
Perhaps it is still unconvincing that expanding the integers in this way gives something
indeed related to *p*-adics.
In fact, since the expansions are in binary or (balanced) ternary, the integers should just
be a subset of the 2-adics or 3-adics.
Still, I wanted to see what these numbers actually "look" like, so I whipped up an interactive diagram.
You should definitely see [this page](/interactive/adic/) for more information, but
the gist is that *p*-adics can be sent into the complex plane in a fractal-like way.
```{ojs}
// | 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.
It is easiest to see this when $c \approx 0.5$.
This corresponds with the intuition that these are subsets of the 2- and 3-adics.
Next, notice that when plotting the *κ*-adics, there is some self-similarity different
from the 2- and 3-adics.
To see this, try setting $c \approx 0.75$.
There appear to be four clusters, 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.
If you try switching between the *κ*-adic options, you can even see the smaller
and larger shapes changing in the same way as one another.
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.
If you prefer not to use JavaScript, I also prepared a [Python script](./kadic.py) using Matplotlib.[^1]
Here are a couple of screenshots from the script, which demonstrates the self-similarity mentioned above.
:::: {.row}
::: {layout-ncol="2"}
![`quotRem`](./cendree_quotrem_fractal.png)
![`divMod`](./cendree_divmod_fractal.png)
:::
Clusters of *κ*-adics, with self-similar patterns boxed in red.
::::
[^1]: You will also need the [`divMod`](./cendree_DivMod_count_1024_256_digits.csv)
and [`quotRem`](./cendree_QuotRem_count_1024_256_digits.csv) data files.