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,… for the primes and (x)i for the exponent of pi in x≥1; both are primitive recursive by the previous lesson.
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), has a different code from (5): indeed [5]=26 while [5,0]=26⋅3. The coding is not surjective — 0, 3 or 10 are not codes — but the set of codes is primitive recursive.
The exponents of a code are non-zero exactly on an initial segment of the primes, so lh(s)=μi<s((s)i=0). The bound is correct since s≥2lh(s)>lh(s) for a code s.
(s)i′=(s)i−˙1.
Seq(s)⟺s≥1∧∀i<s((s)i=0↔i<lh(s)). The quantifier can be bounded by s since (s)i=0 for pi>s, and pi>i.
s∗t=s⋅∏j<lh(t)plh(s)+j(t)j.
s↾m=∏i<mpi(s)i.
set(s,i,v)=⌊s/pi(s)i⌋⋅piv+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) from the single previous value f(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.
The equation determines f(x,y) by induction on y, since fˉ(x,y) only involves values at arguments smaller than y. The function fˉ satisfies the primitive recursion
so fˉ is primitive recursive. Finally f(x,y)=(fˉ(x,y+1))y′.
As an example, the Fibonacci sequence satisfies fib(y)=h(y,fib(y)) where h(y,s)=y if y≤1 and 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.
Let m=max(n,a0,…,an−1) and d=m!. We claim that the moduli ui=1+(i+1)d, for i<n, are pairwise coprime. Suppose that a prime q divides ui and uj with i<j<n. Then q divides uj−ui=(j−i)d, so q divides j−i or d. Since 1≤j−i≤n≤m, the integer j−i divides m!=d; in both cases q divides d. But then q divides ui−(i+1)d=1, which is absurd.
By the Chinese remainder theorem there is c such that c≡ai(modui) for all i<n. Since ai≤m≤d<ui, the remainder of c modulo ui is exactly ai, that is β(c,d,i)=ai.
The function β is defined from +, ⋅ and the remainder, and the relation β(c,d,i)=a is expressible by the arithmetic formula ∃q≤c(c=q⋅(1+(i+1)d)+a∧a<1+(i+1)d). 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: ”s codes a strictly increasing sequence”; ”s codes a prefix of the sequence coded by t”.
Solution
Seq(s)∧∀i<lh(s)∀j<lh(s)(i<j→(s)i′<(s)j′). For prefixes: Seq(s)∧Seq(t)∧lh(s)≤lh(t)∧∀i<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 s, and search for it.
Solution
The sorted sequence has the same length n and the same entries, so its code is at most ∏i<npiM+1 where M=maxi(s)i′, a primitive recursive function b(s) of s. The sorted code is μt<b(s)+1(Seq(t)∧lh(t)=lh(s)∧t is non-decreasing∧∀v≤M#v(t)=#v(s)), where #v(s)=∑i<lh(s)χ=((s)i′,v) counts the occurrences of v. All of this is primitive recursive.
Exercise 6.9★★.
Define a bijective coding of finite sequences: show that the function ⟨⟨⋅⟩⟩ given by ⟨⟨⟩⟩=0 and ⟨⟨a0,…,an⟩⟩=1+⟨a0,⟨⟨a1,…,an⟩⟩⟩ is a bijection between finite sequences and N, and that its length and projection functions are primitive recursive.
Solution
By induction on z: z=0 codes only the empty sequence, and z≥1 codes exactly the sequences with first element π0(z−1) followed by a sequence coded by π1(z−1), which is smaller than z since ⟨x,y⟩≥y; by the induction hypothesis there is exactly one such sequence, which gives existence and uniqueness. The length satisfies lh(0)=0 and lh(z)=1+lh(π1(z−1)) for z≥1, a course-of-values recursion since π1(z−1)<z; by Theorem 6.4, 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 and tl(z,i+1)=π1(tl(z,i)−˙1), a primitive recursion on i. If z codes (a0,…,an) and i≤n, then tl(z,i) codes (ai,…,an), so ai=π0(tl(z,i)−˙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.