Cite

This course has no released version yet: the text at this address may change. Cite a released version when one exists.

/courses/models-of-computation/coding-sequences
@misc{models-of-computation-coding-sequences,
  title = {{Coding finite sequences}},
  howpublished = {Lesson 6 of \emph{Models of computation}, Computability Theory course notes},
  url = {/courses/models-of-computation/coding-sequences},
  note = {Unreleased working version}
}

To cite a single statement, use the # link that appears next to its heading.

Lesson 6 of 13

Coding finite sequences

Primitive recursive coding of finite sequences of integers, operations on codes, course-of-values recursion, and Gödel's β-function.

35 min5 questions
Models of computation · lesson 6 of 13
  1. Algorithms and partial functions
  2. Turing machines
  3. Programming Turing machines
  4. Register machines
  5. Primitive recursive functions
  6. Coding finite sequences
  7. The Ackermann function
  8. Minimization and partial recursive functions
  9. LOOP and WHILE programs
  10. The λ-calculus
  11. Computing with λ-terms
  12. Equivalence of the models
  13. The Church–Turing thesis

Programs manipulate lists, stacks and arrays of unbounded size, while the functions we study take a fixed number of integer arguments. We now show that finite sequences of integers can be coded by single integers, in such a way that all the usual operations on sequences become primitive recursive. This coding is used constantly: to describe configurations of machines, to code programs and formulas, and to define functions by recursion on all previous values.

Cantor’s pairing function already codes pairs, and by iteration tuples of a fixed length. Here the length is part of the data.

6.1 Prime power coding

We write p0=2,p1=3,p2=5,…p_0 = 2, p_1 = 3, p_2 = 5, \dots for the primes and (x)i(x)_i for the exponent of pip_i in x≥1x \geq 1; both are primitive recursive by the previous lesson.

Definition 6.1.#

The code of the finite sequence (a0,…,an−1)(a_0, \dots, a_{n-1}) of integers is

[a0,…,an−1]=∏i<npi ai+1=2a0+1⋅3a1+1⋯pn−1 an−1+1.[a_0, \dots, a_{n-1}] = \prod_{i < n} p_i^{\,a_i + 1} = 2^{a_0 + 1} \cdot 3^{a_1 + 1} \cdots p_{n-1}^{\,a_{n-1} + 1}.

The empty sequence has code [ ]=1[\,] = 1.

By the uniqueness of prime factorizations, the coding is injective. The exponents are shifted by one so that a sequence ending with zeros, such as (5,0)(5, 0), has a different code from (5)(5): indeed [5]=26[5] = 2^6 while [5,0]=26⋅3[5, 0] = 2^6 \cdot 3. The coding is not surjective — 00, 33 or 1010 are not codes — but the set of codes is primitive recursive.

Proposition 6.2.#

The following functions and predicates are primitive recursive:

  1. the length lh(s)\mathrm{lh}(s), equal to nn if s=[a0,…,an−1]s = [a_0, \dots, a_{n-1}];
  2. the projection (s)i′(s)'_i, equal to aia_i if s=[a0,…,an−1]s = [a_0, \dots, a_{n-1}] and i<ni < n;
  3. the predicate Seq(s)\mathrm{Seq}(s): ”ss is the code of a sequence”;
  4. the concatenation s∗ts * t, with [a0,…,an−1]∗[b0,…,bm−1]=[a0,…,an−1,b0,…,bm−1][a_0, \dots, a_{n-1}] * [b_0, \dots, b_{m-1}] = [a_0, \dots, a_{n-1}, b_0, \dots, b_{m-1}];
  5. the restriction s↾ms \upharpoonright m, equal to [a0,…,am−1][a_0, \dots, a_{m-1}] for m≤nm \leq n;
  6. the update set(s,i,v)\mathrm{set}(s, i, v), equal to the code of the sequence obtained by replacing aia_i with vv, for i<ni < n.

(The values on arguments that are not codes, or out of range, are irrelevant; the definitions below give some primitive recursive value.)

Proof of Proposition 6.2.
  1. The exponents of a code are non-zero exactly on an initial segment of the primes, so lh(s)=μi<s ((s)i=0)\mathrm{lh}(s) = \mu i < s\ ((s)_i = 0). The bound is correct since s≥2lh(s)>lh(s)s \geq 2^{\mathrm{lh}(s)} > \mathrm{lh}(s) for a code ss.
  2. (s)i′=(s)i−˙1(s)'_i = (s)_i \dotminus 1.
  3. Seq(s)  ⟺  s≥1∧∀i<s ((s)i≠0↔i<lh(s))\mathrm{Seq}(s) \iff s \geq 1 \wedge \forall i < s\ \big( (s)_i \neq 0 \leftrightarrow i < \mathrm{lh}(s) \big). The quantifier can be bounded by ss since (s)i=0(s)_i = 0 for pi>sp_i > s, and pi>ip_i > i.
  4. s∗t=s⋅∏j<lh(t)plh(s)+j (t)js * t = s \cdot \prod_{j < \mathrm{lh}(t)} p_{\mathrm{lh}(s) + j}^{\,(t)_j}.
  5. s↾m=∏i<mpi (s)is \upharpoonright m = \prod_{i < m} p_i^{\,(s)_i}.
  6. set(s,i,v)=⌊s/pi(s)i⌋⋅pi v+1\mathrm{set}(s, i, v) = \lfloor s / p_i^{(s)_i} \rfloor \cdot p_i^{\,v + 1}.

Each expression is built from primitive recursive functions using bounded sums, products and minimization.

6.2 Course-of-values recursion

Primitive recursion defines f(x⃗,y+1)f(\vec x, y + 1) from the single previous value f(x⃗,y)f(\vec x, y). Many natural definitions use all previous values — the Fibonacci sequence uses two of them, and the definition of the code of a formula uses the codes of all its subformulas. Sequence coding reduces such definitions to primitive recursion.

Definition 6.3.#

For f:Nk+1→Nf : \nat^{k+1} \to \nat, its course-of-values function is

fˉ(x⃗,y)=[f(x⃗,0),f(x⃗,1),…,f(x⃗,y−1)].\bar f(\vec x, y) = [f(\vec x, 0), f(\vec x, 1), \dots, f(\vec x, y - 1)].
Theorem 6.4 (Course-of-values recursion).#

Let h:Nk+2→Nh : \nat^{k+2} \to \nat be primitive recursive. Then the function ff defined by

f(x⃗,y)=h(x⃗,y,fˉ(x⃗,y))f(\vec x, y) = h(\vec x, y, \bar f(\vec x, y))

is primitive recursive.

Proof of Theorem 6.4.

The equation determines f(x⃗,y)f(\vec x, y) by induction on yy, since fˉ(x⃗,y)\bar f(\vec x, y) only involves values at arguments smaller than yy. The function fˉ\bar f satisfies the primitive recursion

fˉ(x⃗,0)=1,fˉ(x⃗,y+1)=fˉ(x⃗,y)⋅py h(x⃗,y,fˉ(x⃗,y))+1,\begin{gathered} \bar f(\vec x, 0) = 1, \\ \bar f(\vec x, y + 1) = \bar f(\vec x, y) \cdot p_y^{\,h(\vec x, y, \bar f(\vec x, y)) + 1}, \end{gathered}

so fˉ\bar f is primitive recursive. Finally f(x⃗,y)=(fˉ(x⃗,y+1))y′f(\vec x, y) = (\bar f(\vec x, y + 1))'_y.

As an example, the Fibonacci sequence satisfies fib(y)=h(y,fib‾(y))\mathrm{fib}(y) = h(y, \overline{\mathrm{fib}}(y)) where h(y,s)=yh(y, s) = y if y≤1y \leq 1 and h(y,s)=(s)y−1′+(s)y−2′h(y, s) = (s)'_{y-1} + (s)'_{y-2} otherwise.

6.3 Gödel’s β-function

The prime power coding uses exponentiation. In the proof of the incompleteness theorems, Gödel needed to code sequences using only addition and multiplication, because these are the only operations of the language of arithmetic. His solution relies on the Chinese remainder theorem.

Definition 6.5.#

Gödel’s β-function is β(c,d,i)=c mod (1+(i+1)d)\beta(c, d, i) = c \bmod \big(1 + (i + 1) d\big).

Lemma 6.6 (Gödel).#

For every finite sequence a0,…,an−1a_0, \dots, a_{n-1} of integers there exist c,dc, d such that β(c,d,i)=ai\beta(c, d, i) = a_i for all i<ni < n.

Proof of Lemma 6.6.

Let m=max⁡(n,a0,…,an−1)m = \max(n, a_0, \dots, a_{n-1}) and d=m!d = m!. We claim that the moduli ui=1+(i+1)du_i = 1 + (i+1)d, for i<ni < n, are pairwise coprime. Suppose that a prime qq divides uiu_i and uju_j with i<j<ni < j < n. Then qq divides uj−ui=(j−i)du_j - u_i = (j - i) d, so qq divides j−ij - i or dd. Since 1≤j−i≤n≤m1 \leq j - i \leq n \leq m, the integer j−ij - i divides m!=dm! = d; in both cases qq divides dd. But then qq divides ui−(i+1)d=1u_i - (i+1)d = 1, which is absurd.

By the Chinese remainder theorem there is cc such that c≡ai(modui)c \equiv a_i \pmod{u_i} for all i<ni < n. Since ai≤m≤d<uia_i \leq m \leq d < u_i, the remainder of cc modulo uiu_i is exactly aia_i, that is β(c,d,i)=ai\beta(c, d, i) = a_i.

The function β\beta is defined from ++, ⋅\cdot and the remainder, and the relation β(c,d,i)=a\beta(c, d, i) = a is expressible by the arithmetic formula ∃q≤c (c=q⋅(1+(i+1)d)+a∧a<1+(i+1)d)\exists q \leq c\ \big(c = q \cdot (1 + (i+1) d) + a \wedge a < 1 + (i+1) d\big). This is how sequences, and hence computations, are represented in first-order arithmetic.

6.4 Exercises

Exercise 6.7 ★.

Show that the following predicates are primitive recursive: ”ss codes a strictly increasing sequence”; ”ss codes a prefix of the sequence coded by tt”.

Solution

Seq(s)∧∀i<lh(s) ∀j<lh(s) (i<j→(s)i′<(s)j′)\mathrm{Seq}(s) \wedge \forall i < \mathrm{lh}(s)\ \forall j < \mathrm{lh}(s)\ (i < j \rightarrow (s)'_i < (s)'_j). For prefixes: Seq(s)∧Seq(t)∧lh(s)≤lh(t)∧∀i<lh(s) (s)i′=(t)i′\mathrm{Seq}(s) \wedge \mathrm{Seq}(t) \wedge \mathrm{lh}(s) \leq \mathrm{lh}(t) \wedge \forall i < \mathrm{lh}(s)\ (s)'_i = (t)'_i.

Exercise 6.8 ★★.

Show that the function which maps the code of a sequence to the code of the same sequence sorted in non-decreasing order is primitive recursive.

Hint

Bound the code of the sorted sequence in terms of ss, and search for it.

Solution

The sorted sequence has the same length nn and the same entries, so its code is at most ∏i<npiM+1\prod_{i < n} p_i^{M + 1} where M=max⁡i(s)i′M = \max_i (s)'_i, a primitive recursive function b(s)b(s) of ss. The sorted code is μt<b(s)+1 (Seq(t)∧lh(t)=lh(s)∧t is non-decreasing∧∀v≤M #v(t)=#v(s))\mu t < b(s) + 1\ \big(\mathrm{Seq}(t) \wedge \mathrm{lh}(t) = \mathrm{lh}(s) \wedge t \text{ is non-decreasing} \wedge \forall v \leq M\ \#_v(t) = \#_v(s)\big), where #v(s)=∑i<lh(s)χ=((s)i′,v)\#_v(s) = \sum_{i < \mathrm{lh}(s)} \chi_=((s)'_i, v) counts the occurrences of vv. All of this is primitive recursive.

Exercise 6.9 ★★.

Define a bijective coding of finite sequences: show that the function ⟨ ⁣⟨⋅⟩ ⁣⟩\langle\!\langle \cdot \rangle\!\rangle given by ⟨ ⁣⟨ ⟩ ⁣⟩=0\langle\!\langle \, \rangle\!\rangle = 0 and ⟨ ⁣⟨a0,…,an⟩ ⁣⟩=1+⟨a0,⟨ ⁣⟨a1,…,an⟩ ⁣⟩⟩\langle\!\langle a_0, \dots, a_{n} \rangle\!\rangle = 1 + \langle a_0, \langle\!\langle a_1, \dots, a_n \rangle\!\rangle \rangle is a bijection between finite sequences and N\nat, and that its length and projection functions are primitive recursive.

Solution

By induction on zz: z=0z = 0 codes only the empty sequence, and z≥1z \geq 1 codes exactly the sequences with first element π0(z−1)\pi_0(z - 1) followed by a sequence coded by π1(z−1)\pi_1(z - 1), which is smaller than zz since ⟨x,y⟩≥y\langle x, y \rangle \geq y; by the induction hypothesis there is exactly one such sequence, which gives existence and uniqueness. The length satisfies lh(0)=0\mathrm{lh}(0) = 0 and lh(z)=1+lh(π1(z−1))\mathrm{lh}(z) = 1 + \mathrm{lh}(\pi_1(z - 1)) for z≥1z \geq 1, a course-of-values recursion since π1(z−1)<z\pi_1(z - 1) < z; by Theorem 6.4, lh\mathrm{lh} is primitive recursive. For the projections, the parameter changes along the recursion, so it is simpler to iterate the tail: let tl(z,0)=z\mathrm{tl}(z, 0) = z and tl(z,i+1)=π1(tl(z,i)−˙1)\mathrm{tl}(z, i + 1) = \pi_1(\mathrm{tl}(z, i) \dotminus 1), a primitive recursion on ii. If zz codes (a0,…,an)(a_0, \dots, a_n) and i≤ni \leq n, then tl(z,i)\mathrm{tl}(z, i) codes (ai,…,an)(a_i, \dots, a_n), so ai=π0(tl(z,i)−˙1)a_i = \pi_0(\mathrm{tl}(z, i) \dotminus 1).

6.5 Notes and references

The β-function lemma appears in Gödel’s incompleteness paper of 1931, where it is used to express definitions by recursion in the language of arithmetic. Coding finite sequences by prime powers is also due to Gödel. Course-of-values recursion is treated in detail in Péter’s monograph.

  • K. Gödel, Über formal unentscheidbare Sätze der Principia Mathematica und verwandter Systeme I, Monatshefte für Mathematik und Physik 38 (1931), 173–198.
  • S. C. Kleene, Introduction to Metamathematics, North-Holland, 1952.