extra revisions to number-number.2
This commit is contained in:
parent
3fe47b2af3
commit
118657d2fc
@ -1,13 +1,15 @@
|
||||
-- Functions from the previous post (../1/index.qmd)
|
||||
module Previous where
|
||||
|
||||
import Data.Tree
|
||||
import Data.List (nubBy)
|
||||
|
||||
|
||||
-- Breadth-first search on a tree
|
||||
bfs (Node root children) = bfs' root children where
|
||||
bfs' v [] = [v]
|
||||
bfs' v ((Node y ys):xs) = v:bfs' y (xs ++ ys)
|
||||
|
||||
-- Tree of all binary (dyadic) fractions
|
||||
binFracTree = unfoldTree make $ (1,1) where
|
||||
make v@(vn, vd)
|
||||
= (v, [
|
||||
@ -15,6 +17,7 @@ binFracTree = unfoldTree make $ (1,1) where
|
||||
(2*vn + 1, 2*vd)
|
||||
])
|
||||
|
||||
-- Stern-Brocot Tree, as (numerator, denominator) pairs
|
||||
sternBrocot = unfoldTree make $ ((1,1), (0,1), (1,0)) where
|
||||
make (v@(vn, vd), l@(ln, ld), r@(rn, rd))
|
||||
= (v, [
|
||||
@ -22,9 +25,13 @@ sternBrocot = unfoldTree make $ ((1,1), (0,1), (1,0)) where
|
||||
(((vn + rn), (vd + rd)), v, r)
|
||||
])
|
||||
|
||||
-- Build a list of pairs which sum to n
|
||||
listPairs n = [ (k, n - k) | k <- [0..n] ]
|
||||
|
||||
-- "Triangular" enumeration of all pairs of positive integers
|
||||
allPairs = concat $ map listPairs [0..]
|
||||
|
||||
-- Equality for rational numbers expressed as pairs of positive integers
|
||||
ratEqual (a, b) (c, d) = a * d == b * c
|
||||
-- All positive rational numbers in least terms, as pairs of positive integers
|
||||
allRationals = nubBy ratEqual $ map (\(a,b) -> (a+1, b+1)) allPairs
|
||||
|
||||
@ -1,16 +1,15 @@
|
||||
---
|
||||
title: "Numbering Numbers, Part 2: Ordering Obliquely"
|
||||
description: |
|
||||
How do we count an infinitude of numbers?
|
||||
How do we construct an irrational number from rational ones?
|
||||
format:
|
||||
html:
|
||||
html-math-method: katex
|
||||
date: "2023-12-31"
|
||||
date-modified: "2025-07-26"
|
||||
date-modified: "2025-07-29"
|
||||
categories:
|
||||
- algebra
|
||||
- question-mark function
|
||||
- haskell
|
||||
- diagonal argument
|
||||
---
|
||||
|
||||
|
||||
@ -63,17 +62,19 @@ Because rationals -- and even some irrationals -- can be enumerated, we might im
|
||||
that it would be nice to enumerate *all* irrational numbers.
|
||||
Unfortunately, we're not very lucky this time.
|
||||
|
||||
Let's start by making what we mean by "number" more direct.
|
||||
Let's start by making what we mean by "number" more concrete
|
||||
We've already been exposed to infinite expansions, like 1/3 in binary (and conveniently, also decimal).
|
||||
In discussing the question mark function, I mentioned the utility of repeating expansions as a means of
|
||||
accessing quadratic rationals in the Stern-Brocot tree.
|
||||
A general sequence need not repeat, so we choose to treat these extra "infinite expansions" as numbers.
|
||||
A general sequence need not repeat, so we can choose to treat these extra "infinite expansions" as numbers.
|
||||
Proving that a rational number must have a repeating expansion is difficult, but if we accept this premise,
|
||||
then the new non-repeating expansions are our irrationals.
|
||||
For example, $2 - \varphi \approx 0.381966...$, which we encountered last time, is such a number.
|
||||
|
||||
Doing this introduces a number of headaches, the least of which is attempting to do arithmetic with such quantities.
|
||||
However, we're only concerned with the contents of these sequences to show why we can't list out all irrationals.
|
||||
Doing this introduces a number of headaches, the least of which is that of
|
||||
the definition of arithmetic on such quantities.
|
||||
However, we need only be concerned with the contents of these sequences to show why
|
||||
we can't list out all irrationals.
|
||||
|
||||
|
||||
### Diagonalization
|
||||
@ -86,8 +87,9 @@ Suppose that we have an enumeration of every infinite sequence on this list -- n
|
||||
[Cantor's diagonal argument](https://en.wikipedia.org/wiki/Cantor%27s_diagonal_argument) shows that
|
||||
a new sequence can be found by taking the sequence on the diagonal
|
||||
and changing each individual digit to another one.
|
||||
The new sequence differs in at least one place from every element on the list, so it cannot be on the list,
|
||||
showing that such an enumeration cannot exist.
|
||||
The new sequence differs in at least one place from every element on the list,
|
||||
so the new sequence cannot be on the list.
|
||||
Therefore, such an enumeration cannot exist.
|
||||
|
||||
This is illustrated for binary sequences in this diagram:
|
||||
|
||||
@ -107,26 +109,27 @@ This is illustrated for binary sequences in this diagram:
|
||||
It's fairly common to show this argument without much further elaboration,
|
||||
but there are a few problems with doing so:
|
||||
|
||||
- We're using infinite sequences of digits, not numbers
|
||||
- Equality between sequences is defined by having all elements coincide
|
||||
- We're using infinite sequences of digits, not numbers.
|
||||
- Equality between sequences is defined by having all elements coincide.
|
||||
- We assume we have an enumeration of sequences to which the argument applies.
|
||||
The contents of the enumeration are a mystery.
|
||||
- We have no idea where the rational numbers are, or if we'd construct one
|
||||
by applying the diagonal argument
|
||||
- We have no idea which sequences are rational numbers, or if we'd construct one
|
||||
by applying the diagonal argument.
|
||||
|
||||
|
||||
### Equality
|
||||
|
||||
The purpose of the diagonal argument is to produce a new sequence which was not previously enumerated.
|
||||
The sequence is different in all positions, but what we actually want is equality with respect to the base.
|
||||
In base ten, we have the peculiar identity that [$0.\overline{9} = 1$](https://en.wikipedia.org/wiki/0.999...).
|
||||
This means that if the diagonal argument (applied to base ten sequences) constructs a new sequence with the digit 9 repeating forever,
|
||||
it might be equivalent to a sequence which was already in the list:
|
||||
In base ten, we have the peculiar identity that
|
||||
[$0.\overline{9} = 1$](https://en.wikipedia.org/wiki/0.999...).
|
||||
This means that if the diagonal argument (applied to base ten sequences) constructs a new sequence
|
||||
with the digit 9 repeating forever, it might be equivalent to a sequence which was already in the list:
|
||||
|
||||
```{haskell}
|
||||
--| code-fold: true
|
||||
--| classes: plain
|
||||
--| fig-cap: A case in which the diagonal argument could construct a number already on the list.
|
||||
--| fig-cap: "A case in which the diagonal argument could construct a number already on the list."
|
||||
|
||||
diagData = rowsOmega [
|
||||
[1, 2, 3, 4, 5, 6],
|
||||
@ -151,16 +154,16 @@ In the enumeration given, the diagonal continues with 9's forever, so we end up
|
||||
### Picking a Sequence and Ensuring Rationals
|
||||
|
||||
"No problem, just pick another enumeration," you might say.
|
||||
Indeed, the example given relies on a simple function applied on the diagonal and an enumeration
|
||||
Indeed, the example given relies on a simple function and an enumeration
|
||||
to which it is particularly ill-suited.
|
||||
|
||||
Instead, let's focus on something we *can* do.
|
||||
Instead of assuming we have all irrational numbers listed out already, let's start smaller.
|
||||
As of last post, we already have several ways to enumerate all rational numbers between 0 and 1.
|
||||
If we take this enumeration, convert rational numbers to their expansions in a base, and apply the diagonal argument,
|
||||
the resulting quantity *should* be an irrational number.
|
||||
We can take this enumeration and convert each rational number to positional expansions in a base.
|
||||
Then after applying the diagonal argument, the resulting quantity *should* be an irrational number.
|
||||
|
||||
For convenience, we'll use the binary expansions of rationals as our sequences.
|
||||
For convenience, we'll use binary expansions of rationals as our sequences.
|
||||
That way, to get a unique sequence on the diagonal, we only have to worry
|
||||
about changing "0"s to "1"s (and vice versa).
|
||||
Since we have less flexibility in our digits, it also relieves us from some of the responsibility
|
||||
@ -171,8 +174,8 @@ However, it's still possible the argument constructs a number already equal to s
|
||||
Into Silicon
|
||||
------------
|
||||
|
||||
Before going any further, let's convert the diagonal argument into a function.
|
||||
We want to, given an enumeration of binary sequences, produce a new sequence not on the list.
|
||||
Before going any further, let's write a function for applying the diagonal argument to
|
||||
a list of binary sequences.
|
||||
This can be implemented in Haskell fairly easily:
|
||||
|
||||
|
||||
@ -236,7 +239,7 @@ oneFifth = fromBinSeq 64 $ tail $ binDiv 1 5
|
||||
print oneFifth
|
||||
```
|
||||
|
||||
The precision `p` here is mostly useless, since we intend to take this to as far as doubles will go.
|
||||
The precision `p` here is mostly useless, since we intend to take this to as far as `Double` will go.
|
||||
`p` = 100 will do for most sequences, since it's rare that we'll encounter more than a few zeroes
|
||||
at the beginning of a sequence.
|
||||
|
||||
@ -245,7 +248,8 @@ Some Enumerations
|
||||
-----------------
|
||||
|
||||
Now, for the sake of argument, let's look at an enumeration that fails.
|
||||
Using the tree of binary fractions from the last post, we use a breadth-first search to create a list of terminating binary expansions.
|
||||
Using the tree of binary fractions from the last post, we use a breadth-first search to create
|
||||
a list of terminating binary expansions.
|
||||
|
||||
![
|
||||
Tree of binary fractions, as the tree of terminating binary expansions. <br>
|
||||
@ -282,8 +286,8 @@ renderDiagTable badDiag 8
|
||||
Computing the diagonal sequence, it quickly becomes apparent that we're going
|
||||
to keep getting "0"s along the diagonal.
|
||||
This is because we're effectively just counting in binary some number of digits to the right.
|
||||
The length of a binary expansion grows logarithmically rather than linearly; in other words,
|
||||
we can't count fast enough by just adding 1 (or adding any number, really).
|
||||
The length of a binary expansion grows logarithmically, but going down the diagonal is a linear process.
|
||||
In other words, we can't count fast enough by just adding 1 (or adding any number, really).
|
||||
|
||||
Even worse than this, we get a sequence which is equal to sequence 1 as a binary expansion.
|
||||
We can't even rely on the diagonal argument to give us a new number that *isn't* equal
|
||||
@ -346,6 +350,13 @@ This new number can just be tacked onto the beginning of the list.
|
||||
Then, we re-apply the diagonal argument to obtain a new number.
|
||||
And so on ad infinitum.
|
||||
|
||||
```{haskell}
|
||||
transform :: [[Int]] -> [[Int]]
|
||||
-- Emit the new diagonal sequence, then recurse with the new sequence
|
||||
-- prepended to the original enumeration
|
||||
transform xs = let ds = diagonalize xs in ds:transform (ds:xs)
|
||||
```
|
||||
|
||||
```{haskell}
|
||||
--| code-fold: true
|
||||
--| classes: plain
|
||||
@ -379,13 +390,9 @@ renderTransformTable n = renderTable
|
||||
renderTransformTable 8 $ take 8 $ sbDiag id
|
||||
```
|
||||
|
||||
For completeness's sake, the decimal expansions of the first few numbers which pop are as follows:
|
||||
|
||||
```{haskell}
|
||||
transform :: [[Int]] -> [[Int]]
|
||||
-- Emit the new diagonal sequence, then recurse with the new sequence
|
||||
-- prepended to the original enumeration
|
||||
transform xs = let ds = diagonalize xs in ds:transform (ds:xs)
|
||||
|
||||
sbDiagSeq = let (Node _ (tree:__)) = sternBrocot in
|
||||
transform $ map (tail . uncurry binDiv) $ bfs tree
|
||||
|
||||
@ -393,8 +400,10 @@ mapM_ print $ take 10 $ map (fromBinSeq 100) sbDiagSeq
|
||||
```
|
||||
|
||||
Does this list out "all" irrational numbers? Not even close.
|
||||
In fact, this just gives us a bijection between the original enumeration and a new one containing our irrationals.
|
||||
The new numbers we get depend heavily on the order of the original sequence.
|
||||
In fact, this just gives us a bijection between the original enumeration
|
||||
and a new one containing our irrationals.
|
||||
|
||||
The new numbers we get also depend heavily on the order of the original sequence.
|
||||
This is obvious just by looking at the first entry produced by our two good enumerations.
|
||||
Perhaps if we permuted the enumeration of rationals in all possible ways, we would end up listing
|
||||
all irrational numbers, but we'd also run through
|
||||
@ -403,7 +412,7 @@ Perhaps if we permuted the enumeration of rationals in all possible ways, we wou
|
||||
The fact that "bad" enumerations exist tells us that it's not even guaranteed that we don't collide
|
||||
with any rationals.
|
||||
I conjecture that the good enumerations won't do so, since we shouldn't ever encounter
|
||||
an infinite sequence of "0"s, and a sequence should eventually differ
|
||||
an infinite sequence of "0"s or "1"s, and a sequence should eventually differ
|
||||
in at least one position from one already listed.
|
||||
|
||||
|
||||
@ -411,7 +420,7 @@ I conjecture that the good enumerations won't do so, since we shouldn't ever enc
|
||||
|
||||
Since the function has the same input and output type, you may wonder what happens when
|
||||
it's applied multiple times.
|
||||
Perhaps you assume that, since `\x -> 1 - x` swaps 0 and 1, we'll get the original sequence back again.
|
||||
Perhaps it is possible that since `\x -> 1 - x` is an involution, so too is this new function.
|
||||
Alas, experimentation proves us wrong.
|
||||
|
||||
```{haskell}
|
||||
@ -428,7 +437,8 @@ mapM_ putStrLn [ "1/2", "1/3", "11/12", "1/8", "57/80", "23/80",
|
||||
The fraction forms of the above numbers are my best guesses.
|
||||
Either way, it only matches for the first two terms before going off the rails.
|
||||
|
||||
Even stranger than this distorted reflection is the fact that going through the mirror again doesn't take us anywhere new
|
||||
Even stranger than this distorted reflection is the fact that going through the mirror again
|
||||
doesn't take us anywhere new:
|
||||
|
||||
```{haskell}
|
||||
sbDiagSeq3 = transform sbDiagSeq2
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user