Cite

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

/courses/fundamentals/programs-as-numbers
@misc{fundamentals-programs-as-numbers,
  title = {{Programs as numbers}},
  howpublished = {Lesson 1 of \emph{Fundamentals of computability}, Computability Theory course notes},
  url = {/courses/fundamentals/programs-as-numbers},
  note = {Unreleased working version}
}

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

Lesson 1 of 6

Programs as numbers

The enumeration Φₑ of the partial computable functions, its approximation by stages, and computable sets and relations.

35 min4 questions
Before this lesson:Equivalence of the models (Models of computation)
Fundamentals of computability · lesson 1 of 6
  1. Programs as numbers
  2. The universal function and the SMN theorem
  3. The halting problem
  4. Computably enumerable sets
  5. Kleene's fixed point theorem
  6. Rice's theorem

The course on models of computation ends with an enumeration of all partial computable functions: machines are coded by integers, and the function computed by the machine of code ee is obtained from ee by a single unbounded search (Kleene's normal form). The whole of computability theory is built on this enumeration. This lesson fixes it once and for all, together with its approximation by stages, and sets up the notions of computable set and computable relation. From now on, algorithms are described in words or pseudo-code, following the practice explained in The Church–Turing thesis.

1.1 The enumeration

Recall that Tk(e,x⃗,s)T_k(e, \vec x, s) is the primitive recursive predicate ”ss codes the complete computation of the machine of code ee on input x⃗=(x1,…,xk)\vec x = (x_1, \dots, x_k)”, that for given ee and x⃗\vec x at most one ss satisfies it, and that U(s)U(s) is the primitive recursive function reading the output on the last configuration of the computation coded by ss. Integers that do not code a machine are treated as coding a fixed machine that never halts, so that every integer is the code of a machine.

Notation 1.1.#

For e∈Ne \in \nat and k≥1k \geq 1, Φe(k)\Phi^{(k)}_e is the kk-ary partial function

Φe(k)(x⃗)≃U(μs Tk(e,x⃗,s)),\Phi^{(k)}_e(\vec x) \simeq U\big(\mu s\ T_k(e, \vec x, s)\big),

computed by the machine of code ee. The integer ee is an index of Φe(k)\Phi^{(k)}_e. The superscript is omitted when the number of arguments is clear, and Φe\Phi_e stands for Φe(1)\Phi^{(1)}_e. For an input x⃗\vec x:

  • Φe(x⃗) ⁣ ⁣↓\Phi_e(\vec x)\converge means that the computation halts in a standard configuration, so that Φe(x⃗)\Phi_e(\vec x) is defined; Φe(x⃗) ⁣ ⁣↑\Phi_e(\vec x)\diverge means that it is undefined;
  • Φe(x⃗) ⁣ ⁣↓=y\Phi_e(\vec x)\converge = y means that it is defined, with value yy.

By Universal function, the sequence Φ0,Φ1,Φ2,…\Phi_0, \Phi_1, \Phi_2, \dots contains every unary partial computable function, and the map (e,x⃗)↦Φe(x⃗)(e, \vec x) \mapsto \Phi_e(\vec x) is itself partial computable. These two facts — every partial computable function has an index, and the enumeration is computable — are the only properties of the enumeration used in most of the theory. The next lesson adds a third one, the SMN theorem.

Notation 1.2.#

As in the course on models of computation (Notation 1.2 of “Algorithms and partial functions”), α≃β\alpha \simeq \beta between two expressions denoting possibly undefined values means: either both are defined and equal, or both are undefined. For partial functions, f=gf = g means f(x⃗)≃g(x⃗)f(\vec x) \simeq g(\vec x) for every x⃗\vec x: the two functions have the same domain and agree on it.

The domain of a partial function ff is dom(f)={x⃗:f(x⃗) ⁣ ⁣↓}\mathrm{dom}(f) = \{ \vec x : f(\vec x)\converge \}, and its graph is {(x⃗,y):f(x⃗) ⁣ ⁣↓=y}\{ (\vec x, y) : f(\vec x)\converge = y \}. A partial function is total if its domain is the set of all inputs.

1.2 Approximation by stages

The computation of Φe(x)\Phi_e(x) can be followed for a while. The following definition makes this precise, with conventions that make the approximations finite objects.

Definition 1.3.#

For e,x,s∈Ne, x, s \in \nat, let

Φe(x)[s]≃{U(t)if e,x<s and T1(e,x,t) for some t<s,undefinedotherwise.\Phi_e(x)[s] \simeq \begin{cases} U(t) & \text{if } e, x < s \text{ and } T_1(e, x, t) \text{ for some } t < s,\\ \text{undefined} & \text{otherwise.}\end{cases}

We say that Φe(x)\Phi_e(x) converges at stage ss when Φe(x)[s] ⁣ ⁣↓\Phi_e(x)[s]\converge. The same notation is used for several arguments, with TkT_k in place of T1T_1.

Since a computation of tt steps has a code larger than tt, convergence at stage ss implies that the computation halts in fewer than ss steps. The precise relation between stages and steps is irrelevant: what matters is the following.

Proposition 1.4.#
  1. The relation Φe(x)[s] ⁣ ⁣↓=y\Phi_e(x)[s]\converge = y, of the variables e,x,s,ye, x, s, y, is primitive recursive. In particular, given ee, xx and ss, one can decide whether Φe(x)[s] ⁣ ⁣↓\Phi_e(x)[s]\converge, and compute its value if so.
  2. If Φe(x)[s] ⁣ ⁣↓=y\Phi_e(x)[s]\converge = y and s′≥ss' \geq s, then Φe(x)[s′] ⁣ ⁣↓=y\Phi_e(x)[s']\converge = y.
  3. Φe(x) ⁣ ⁣↓=y\Phi_e(x)\converge = y if and only if Φe(x)[s] ⁣ ⁣↓=y\Phi_e(x)[s]\converge = y for some ss.
Proof of Proposition 1.4.
  1. Φe(x)[s] ⁣ ⁣↓=y\Phi_e(x)[s]\converge = y holds if and only if e<s∧x<s∧∃t<s (T1(e,x,t)∧U(t)=y)e < s \wedge x < s \wedge \exists t < s\, \big(T_1(e, x, t) \wedge U(t) = y\big). This is obtained from primitive recursive predicates by Boolean operations and a bounded quantifier, hence it is primitive recursive (Corollary 5.10 of “Primitive recursive functions”). The value, when defined, is U(μt<s T1(e,x,t))U(\mu t < s\ T_1(e, x, t)), a bounded minimization.
  2. The witness t<st < s is also smaller than s′s', and the conditions e,x<se, x < s are preserved.
  3. If Φe(x) ⁣ ⁣↓=y\Phi_e(x)\converge = y, let tt be the code of the computation; then T1(e,x,t)T_1(e, x, t) and U(t)=yU(t) = y, so Φe(x)[s] ⁣ ⁣↓=y\Phi_e(x)[s]\converge = y for s=max⁡(e,x,t)+1s = \max(e, x, t) + 1. Conversely, if Φe(x)[s] ⁣ ⁣↓=y\Phi_e(x)[s]\converge = y with witness tt, then tt is the unique tt with T1(e,x,t)T_1(e, x, t), so μu T1(e,x,u)=t\mu u\, T_1(e, x, u) = t and Φe(x)=U(t)=y\Phi_e(x) = U(t) = y.

The contrast between items 1 and 3 is the central phenomenon of the theory. Convergence at a given stage is decidable; convergence is the existence of a stage, a question with an unbounded quantifier, and it is not decidable, as the lesson on the halting problem shows. Divergence is never confirmed at a finite stage: Φe(x) ⁣ ⁣↑\Phi_e(x)\diverge means Φe(x)[s] ⁣ ⁣↑\Phi_e(x)[s]\diverge for every ss.

1.3 Computable sets and relations

Definition 1.5.#

A relation R⊆NkR \subseteq \nat^k is computable (or decidable) if its characteristic function, equal to 11 on RR and 00 outside, is computable: there is an ee such that Φe(k)\Phi^{(k)}_e is total and Φe(k)(x⃗)=1\Phi^{(k)}_e(\vec x) = 1 if x⃗∈R\vec x \in R, Φe(k)(x⃗)=0\Phi^{(k)}_e(\vec x) = 0 otherwise. For k=1k = 1 one speaks of computable sets.

Computable sets were called recursive in older texts, after the partial recursive functions, and the expressions recursion theory and recursive set are still used. We freely identify a relation R⊆NkR \subseteq \nat^k with the set {⟨x1,…,xk⟩:x⃗∈R}\{ \langle x_1, \dots, x_k \rangle : \vec x \in R \}, obtained through the pairing function; one is computable if and only if the other is.

Proposition 1.6.#
  1. The computable relations are closed under complement, finite union and finite intersection, and under substitution of total computable functions: if R⊆NmR \subseteq \nat^m is computable and g1,…,gm:Nk→Ng_1, \dots, g_m : \nat^k \to \nat are total computable, then {x⃗:(g1(x⃗),…,gm(x⃗))∈R}\{ \vec x : (g_1(\vec x), \dots, g_m(\vec x)) \in R \} is computable.
  2. They are closed under bounded quantification: if R⊆Nk+1R \subseteq \nat^{k+1} is computable, so are {(x⃗,y):∃z<y R(x⃗,z)}\{ (\vec x, y) : \exists z < y\ R(\vec x, z) \} and {(x⃗,y):∀z<y R(x⃗,z)}\{ (\vec x, y) : \forall z < y\ R(\vec x, z) \}.
  3. Definition by cases: if R1,…,RnR_1, \dots, R_n are computable relations partitioning Nk\nat^k and g1,…,gng_1, \dots, g_n are partial computable, then f(x⃗)≃gi(x⃗)f(\vec x) \simeq g_i(\vec x) for x⃗∈Ri\vec x \in R_i defines a partial computable function.
  4. Unbounded search: if R⊆Nk+1R \subseteq \nat^{k+1} is computable, then f(x⃗)≃μy R(x⃗,y)f(\vec x) \simeq \mu y\, R(\vec x, y) is partial computable, and total if for every x⃗\vec x there is some yy with R(x⃗,y)R(\vec x, y).
Proof of Proposition 1.6.

By Equivalence of the models, the computable partial functions are the partial recursive functions, which contain the primitive recursive functions and are closed under composition, primitive recursion and minimization. Let χR\chi_R denote the characteristic function of RR.

  1. χNk∖R=1−˙χR\chi_{\nat^k \setminus R} = 1 \dotminus \chi_R, χR∩S=χR⋅χS\chi_{R \cap S} = \chi_R \cdot \chi_S, and unions are complements of intersections of complements. Substitution is composition: the characteristic function of the new relation is χR(g1(x⃗),…,gm(x⃗))\chi_R(g_1(\vec x), \dots, g_m(\vec x)), which is total.
  2. The function (x⃗,y)↦∑z<yχR(x⃗,z)(\vec x, y) \mapsto \sum_{z < y} \chi_R(\vec x, z) is defined by primitive recursion from χR\chi_R, hence computable, and ∃z<y R(x⃗,z)\exists z < y\ R(\vec x, z) holds exactly when it is non-zero. The bounded universal quantifier is the complement of a bounded existential quantifier applied to the complement.
  3. On input x⃗\vec x, compute χR1(x⃗),…,χRn(x⃗)\chi_{R_1}(\vec x), \dots, \chi_{R_n}(\vec x), which are all defined, find the unique ii with x⃗∈Ri\vec x \in R_i, and compute gi(x⃗)g_i(\vec x). Only the branch that applies is evaluated, so the result is undefined exactly when gi(x⃗)g_i(\vec x) is.
  4. f(x⃗)≃μy [1−˙χR(x⃗,y)=0]f(\vec x) \simeq \mu y\, [1 \dotminus \chi_R(\vec x, y) = 0] is a minimization of a total computable function. It is defined exactly when some yy satisfies R(x⃗,y)R(\vec x, y).

In item 3, the evaluation of only one branch matters: in the primitive recursive definition by cases of the course on models of computation, all branches are computed, which is harmless for total functions but not for partial ones.

1.4 Uniformity

A typical statement of computability theory asserts that some object is obtained uniformly from others: for instance, “the set AxA_x is computable, uniformly in xx” means that the relation {(x,y):y∈Ax}\{ (x, y) : y \in A_x \} is computable, and not only that each AxA_x is computable. The difference is essential. Let ∅′={e:Φe(e) ⁣ ⁣↓}\emptyset' = \{ e : \Phi_e(e)\converge \} be the halting set, which is not computable (Theorem 3.2, in the lesson on the halting problem). Each set Ax={0}A_x = \{ 0 \} if x∈∅′x \in \emptyset' and Ax=∅A_x = \emptyset otherwise is finite, hence computable; but the relation y∈Axy \in A_x is not, since x∈∅′x \in \emptyset' if and only if 0∈Ax0 \in A_x. Similarly, an index ee “obtained uniformly in xx” is the value of a total computable function of xx.

1.5 Exercises

Exercise 1.7 ★.

Let f:N→Nf : \nat \to \nat be total. Show that ff is computable if and only if its graph is computable.

Solution

If ff is computable, f(x)=yf(x) = y is decided by computing f(x)f(x) and comparing with yy. Conversely, if the graph GG is computable, then f(x)=μy G(x,y)f(x) = \mu y\ G(x, y), a search that terminates since ff is total; it is computable by Proposition 1.6.

Exercise 1.8 ★.

Show that the set {e:Φe(0)[e] ⁣ ⁣↓}\{ e : \Phi_e(0)[e]\converge \} is computable, and that the function s↦∣{e<s:Φe(e)[s] ⁣ ⁣↓}∣s \mapsto |\{ e < s : \Phi_e(e)[s]\converge \}| is total computable.

Solution

Both follow from item 1 of Proposition 1.4. The first set is defined by substituting (e,0,e)(e, 0, e) in a primitive recursive relation. The function is ∑e<sχ(e,s)\sum_{e < s} \chi(e, s), where χ(e,s)\chi(e, s) is the characteristic function of the primitive recursive relation Φe(e)[s] ⁣ ⁣↓\Phi_e(e)[s]\converge; it is primitive recursive.

Exercise 1.9 ★★.

Show that a partial computable function with a computable domain has a total computable extension. Show by an example that a partial computable function may have a total computable extension and a non-computable domain.

Solution

If D=dom(f)D = \mathrm{dom}(f) is computable, let g(x)≃f(x)g(x) \simeq f(x) for x∈Dx \in D and g(x)=0g(x) = 0 for x∉Dx \notin D, a definition by cases (Proposition 1.6); gg is total since f(x) ⁣ ⁣↓f(x)\converge for x∈Dx \in D. For the converse, consider the partial function defined by f(e)≃0f(e) \simeq 0 if Φe(e) ⁣ ⁣↓\Phi_e(e)\converge, undefined otherwise. It is partial computable, its domain ∅′\emptyset' is not computable (Theorem 3.2), and the constant function 00 is a total computable extension.

1.6 Notes and references

The enumeration of the partial recursive functions by indices, and the normal form theorem on which it rests, are due to Kleene (1936, 1938). The notation Φe\Phi_e follows Soare’s textbook; Rogers writes φe\varphi_e. The approximation by stages and its conventions are standard in modern texts, where they are the basis of all constructions by stages.

  • S. C. Kleene, General recursive functions of natural numbers, Mathematische Annalen 112 (1936), 727–742.
  • S. C. Kleene, On notation for ordinal numbers, Journal of Symbolic Logic 3 (1938), 150–155.
  • H. Rogers, Theory of Recursive Functions and Effective Computability, McGraw-Hill, 1967.
  • R. I. Soare, Turing Computability: Theory and Applications, Springer, 2016.