281 lines
9.7 KiB
Plaintext
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"}
|
|

|
|
|
|

|
|
:::
|
|
|
|
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.
|