26

In January 2022, MathOverflow user pregunton commented that it is possible to enumerate all rational numbers using iterated maps of the form $f(x) = x+1$ or $\displaystyle g(x) = -\frac 1x$, starting from $0$.

Let $X_n$ be the rational numbers can be generated from $n$ steps of this process (and no fewer) and let $|X_n|$ be the size of this set.

For instance $-2 \in X_5$ because there is a length-$5$ chain of these functions that maps $0$ to $-2$: $g\circ f\circ g\circ f\circ f(0) = -2$. $$0 \overset{f}{\longmapsto} 1 \overset{f}{\longmapsto} 2 \overset{g}{\longmapsto} -\frac12 \overset{f}{\longmapsto} \frac 12 \overset{g}{\longmapsto} -2$$

A tree and a table of $X_n$.

Here's an illustration of the growth process.

Tree showing growth of X_n

Here are the numbers in a table: $$ \begin{array}{c|l|c} n & X_n & |X_n| \\ \hline n=0 & \{0\} & 1 \\ n=1 & \{1\} & 1 \\ n=2 & \{-1, 2\} & 2 \\ n=3 & \{-\frac12, 3\} & 2 \\ n=4 & \{-\frac13,\frac12,4\} & 3 \\ n=5 & \{-2,-\frac14,\frac23,\frac32, 5\} & 5 \\ n=6 & \{-\frac32,-\frac23,-\frac15,\frac34, \frac53, \frac52, 6\} & 7 \\ n=7 & \{-\frac43,-\frac35,-\frac25,-\frac16,\frac13,\frac45,\frac74,\frac83,\frac72,7\} & 10 \end{array} $$


The first $26$ terms of the $0$-indexed sequence of $|X_n|$ begins $$1, 1, 2, 2, 3, 5, 7, 10, 15, 22, 32, 47, 69, 101, 148, 217, 318, 466, 683, 1001, 1467, 2150, 3151, 4618, 6768, 9919, \dots,$$

which for $n\geq4$ satisfies the recurrence $$|X_n| = |X_{n-1}| + |X_{n-3}|.$$

Question: why this recurrence?

A reasonable conjecture is that the sequence of $|X_n|$ always satisfies the above linear recurrence. Is there a combinatorial (or non-combinatorial) way to see why?

(Note: a similar conjecture appears in OEIS sequence A226136.)

Peter Kagey
  • 5,438
  • A small mistake/typo: it should be $g \circ f \circ g\circ f \circ f(0) =-2$ in your example – Tri Apr 20 '25 at 02:27
  • Fixed. Thank you! – Peter Kagey Apr 20 '25 at 06:22
  • 1
    Have you looked at how many new $X_n$ are generated by $f$, by $g$ and by both? – Michael T Apr 20 '25 at 10:07
  • @MichaelT—This is a really insightful question!

    For $n > 1$, let $F_n$ and $G_n$ be the number of terms in $X_n$ that were generated by $f$ and $g$ respectively. Then it appears that for $n \ge 2$, $|F_n| = |G_{n+1}| = A000930(n-1)$, where A000930 is Narayana's cows sequence: $a(0) = a(1) = a(2) = 1$; thereafter $a(n) = a(n-1) + a(n-3)$.

    Still curious for an explanation why!

    – Peter Kagey Apr 20 '25 at 16:09
  • 4
    Possibly related (Calkin-Wilf sequence): https://en.m.wikipedia.org/wiki/Calkin%E2%80%93Wilf_tree Basically, we have the following amazing fact -- the recurrence $a_0=0$, $a_{n+1}=\frac{1}{\lfloor x\rfloor-{x}+1}$ contains each non-negative rational number exactly once! – richrow Apr 21 '25 at 19:48

1 Answers1

14

You can show this recurrence holds as follows.

First, the actions of the maps $f$ and $g$ correspond to elements in $\mathrm{PSL}_2(\mathbb{Z})$. Consider the generators

  • $\begin{bmatrix}1 & 1 \\ 0 & 1\end{bmatrix}$ which corresponds to $f(x) = \frac{x + 1}{1}$ and
  • $\begin{bmatrix}0 & -1 \\ 1 & 0\end{bmatrix}$ which corresponds to $g(x) = \frac{-1}{x}$.

From the relations in $\mathrm{PSL}_2(\mathbb{Z})$, we know:

  • $g \circ g = \text{id}$ hence $g \circ g(x) = x$
  • $g \circ f \circ g \circ f \circ g \circ f = \text{id}$, hence $f\circ g \circ f \circ g \circ f(x) = g(x)$

(See https://groupprops.subwiki.org/wiki/Projective_special_linear_group:PSL(2,Z))

These identities imply that in a minimal-length composition of maps to produce a rational number:

  • No two g's can appear consecutively (because they could be removed)
  • The pattern fgfgf must not appear, since it could be replaced with a shorter sequence (g).

If we encode f as 1 and g as 0, these correspond to avoiding the patterns 00 and 10101.

Additionally, in your setup $g(0)$ is undefined and $f \circ g \circ f$ maps $0$ to $0$. This corresponds to avoiding the literal strings '0' and '101'.

There are 14 valid binary suffixes of length less than 5.

'', '1', '10', '11', '110',
'111', '0101', '0110', '0111', '1010',
'1011', '1101', '1110', '1111'

We can use this to construct a transfer matrix $M$ where $M_{i,j} = 1$ if there is a valid transition from suffix $i$ to $j$ and $0$ otherwise.

The number of valid strings of length n is $$|X_n| = \boldsymbol{1}^{\intercal} M^n v_0$$ where $v_0$ is a 1 followed by 0s. Thus the rational generating function for this is $$|X_x| = A(x) = \boldsymbol{1}^{\intercal} (I - xM)^{-1} v_0.$$

When we compute it (with the script below), the result is $$A(x) = \frac{x^3 - x^2 - 1}{x^3 + x - 1}$$ The numerator determines the initial conditions, the denominator precisely matches your conjectured recurrence of $|X_n| = |X_{n-1}| + |X_{n-3}|$, and when combined together we get the sequence $1,1,2,2,3,5,7,10,\ldots$ precisely matching your calculations.

Python script:

import sympy as sp
from itertools import product

invalid strings are literally 0 or 101 or they contain 00 or 10101

we also eliminate strings of length 3 or smaller that start with 0

def is_invalid(s): return '0' == s or '101' == s or '00' in s or '10101' in s or (len(s) <= 3 and s[0] == '0')

gather all suffixes of length at most 4

valid_suffixes = [''] for n in range(1, 5): for p in product('01', repeat=n): s = ''.join(p) if not is_invalid(s): valid_suffixes.append(s)

suffix_index = {s: i for i, s in enumerate(valid_suffixes)}

collect transitions

transitions = {s: [] for s in valid_suffixes} for s in valid_suffixes: for c in '01': new = (s + c) if not is_invalid(new): next_state = new[-4:] # keep suffix of length at most 4 transitions[s].append(next_state)

construct transition matrix

x = sp.symbols('x') k = len(valid_suffixes) M = sp.Matrix.zeros(k, k)

for i, s in enumerate(valid_suffixes): for t in transitions[s]: j = suffix_index[t] M[j, i] = 1

initial vector: only the empty string is 1

v0 = sp.Matrix.zeros(k, 1) v0[suffix_index['']] = 1

ones row vector to sum over all valid end states

ones_row = sp.Matrix([[1] * k])

generating function A(x) = 1 * (I - xM)^-1 * v0

I = sp.eye(k) A_x = ones_row * (I - x * M).inv() * v0 A_x = sp.simplify(A_x[0]) print("Generating function A(x) =", A_x)

  • What does “$\boldsymbol{1}^{\intercal}$” mean? – MJD Apr 22 '25 at 15:58
  • That is the all 1s vector (transposed so dimensions line up). It appears here to sum the elements of a vector containing the number of occurrences of each suffix. – mathmasterzach Apr 22 '25 at 16:20