The Recursion Theorem#
This section generalizes the existence of self-writing programs to prove one of the cornerstone results of computability theory, Kleene’s Second Recursion Theorem.
Theorem 9
For every word \(p\) there is some word \(q^*\) so that for all \(r\),
The basic idea in this proof is that \(q^*\) should be a word of the form \(\semantics{\hat{q}}(\hat{q})\). We make this leap of faith based on what we saw with the self-writing program in the last section.
We first write a program \(\hat{q}\) so that for all \(r\) and all programs \(x\) which mention only the first three registers,
We want to be sure that our program \(\hat{q}\) itself only uses the first three registers. Then we set \(x = \hat{q}\) to see that for all \(r\)
When we take \(q^* = [\![\hat{q}]\!](\hat{q})\) in \(\eqref{recursion-theorem}\), we see that \(\eqref{eq:K2}\) holds.
Thus, we reduce everything to the matter of writing \(\hat{q}\) as in \(\eqref{qhat}\). We take
We’ll see in a minute where the 4 comes from as we check that \(\eqref{qhat}\) holds. Note that \(\hat{q}\) only mentions R1, R2, and R3. (The program \(\diagprog\) mentions these three registers only, and every program of the form \(\semantics{\writeprog}(y)\) only mentions R1, no matter what \(y\) is.) Then for all \(x\),
So
This last point is exactly where we use the assumption that \(x\) mentions only the first three registers: when we run the program \(\semantics{\diagprog}(x)\) there is nothing in the first three registers and \(r\) is in R4, so this computation gives \(\semantics{x}(x)\), as desired. This completes the proof.
Recall that a self-writing program is a program \(q\) such that \(\semantics{q}(\ ) \simeq q\). Our program \( \selfprog\) is such a program. Our proof of the Recursion Theorem was not so far from our derivation of \(\selfprog\), so it is not surprising that the theorem is more general and implies easily that self-writing programs exist.
Example: quines derived from the Recursion Theorem
Take \(p\) to be a program computing the first projection on two variables, so \([\![ p ]\!](q,r) \simeq q\) for all \(q\), \(r\). By the Recursion Theorem, there is some \(q^*\) so that for all \(r\),
In particular, \([\![ q^* ]\!](\ )\simeq q^*\).
Exercise 81
Show that there are infinitely many non-equivalent quines by showing that for all \(n\), there is a program \(q_n\) such that
Exercise 82
Write two “twin” programs \(s\) and \(t\) with the properties that \(s\) and \(t\) are different programs; running \(s\) with all registers empty gives \(t\) in R1; and running \(t\) with all registers empty gives \(s\) in R1.
“Different” here means that \(s\) and \(t\) are not symbol-for-symbol the same.
Exercise 83
Write a program \(\tradeprog\) which trades places with its input in R1. That is, for all \(x\),
Kleene’s proof#
The proof of Theorem 9 above begins with the idea that the program \(q^*\) should be of the form \([\![\hat{q}]\!] (\hat{q})\). The original proof, due to Kleene, goes a little differently. It starts with the idea that \(q^*\) should be of the form
for some program \(p'\) which is built from \(p\). Indeed, we take \(p'\) to be a program with the property that
Exercise 84
Show that this works: Let \(p'\) be any program with the property in (1), and let \(q^* = [\![s^1_1]\!] (p',p')\). Show that this program \(q^*\) satisfies the equation \([\![ q^*]\!](r) \simeq [\![ p]\!](q^*,r)\).
Another form of the Recursion Theorem#
Here is a second form of the Recursion Theorem, due to Hartley Rogers.
Theorem 10
For every computable \(f: \Words \to \Words\) there is a program \(p^*\) so that \([\![p^*]\!] = [\![f(p^*)]\!]\).
Here is the proof. Let \(y\) be a program which computes \(f\). That is, for all \(x\),
Let \(z\) be a program so that for all \(p\) and \(r\), \(\semantics{z}(p,r) = \semantics{\semantics{y}(p)}(r)\). For example, \(z\) could be
where \(k\) is large enough so that \(y\) does not mention Rk, and \(u_1\) is as in our work on the universal program.
By Theorem 9, we have some \(p^*\) so that
This completes the proof.
Here is a corollary which illustrates the power of this form of the Recursion Theorem.
Corollary 2
There is a word \(p^*\) so that for all \(r\), \([\![p^*]\!](r) = r + p^*\).
Proof. Take \(f\) to be \([\![\writeprog]\!]\). Then \(f\) is total. By Theorem 10, let \(p^*\) be such that \([\![p^*]\!] = [\![ [\![\writeprog]\!](p^*) ]\!]\). Then for all \(r\),
Exercise 85
Show that Theorem 9 follows from Theorem 10.
Computability of functions defined by recursion#
One important application of the Recursion Theorem is that functions may be defined by recursion in ways that go beyond primitive recursion. Here is what we have in mind. Consider the following three function definitions:
In the first of these, \(rem(x,y)\) is the remainder when \(y\) is divided by \(x\).
In all three function definitions, the right-hand side includes calls to the same function which is being defined, but those calls are more complicated than what is allowed by primitive recursion. So from the form in which we have written them, it is not clear from first principles that any of these are computable in the first place.
In the case of \(gcd\), we can reformulate the function to see that it is primitive recursive:
Indeed, this is the usual definition of the function \(gcd\), whereas the recursive expression comes later. But suppose that we started with the recursion. Better yet, suppose that we modified it to change \(rem\) to some other two-place computable function, say \(A(x,y)\). Then it would not be so clear that the modified function were computable.
Turning to \(A(x,y)\) itself, we have argued that it is not primitive recursive in the first place. Now is the time to check that it is computable and also total. Finally, \(collatz(n)\) is computable, as we shall see shortly. Put more accurately, there is a computable partial function that satisfies the recursion equation for \(collatz\) that we see above. The issue is that we do not know whether the computable partial function that we are going to see is total or not.
The details which show that all three example functions are computable are similar. We illustrate with \(A(x,y)\). Let \(f\) be a total computable function so that for all programs \(p\), \(f(p)\) is a program with the property that
It should be clear how to get a computable \(f\) with this property, using the universal function.
Now by Theorem 10, there is some \(p^*\) such that \([\![p^*]\!] = [\![f(p^*)]\!]\). This function would satisfy
In other words, it would satisfy the same recursion equations as \(gcd\). Now it is a separate mathematical fact that the function \(gcd\) is the unique function that satisfies the recursion equations above. Then the uniqueness implies that \(gcd = [\![p^*]\!]\). And since we already know that \(gcd\) is computable (even primitive recursive), the treatment using the Recursion Theorem does not add much.
(On the other hand, it does add a complexity fact. Indeed, the Euclidean algorithm is known to be the best, in some precise (but technical) sense.)
Now we turn to \(A(x,y)\). In this case, what we have seen with the Recursion Theorem implies that there is a computable function that satisfies the recursion equations of \(A(x,y)\). It does not imply that there is a unique such function. However, a separate result would indeed show that. Here is a way to state that result. Suppose we have two functions \(A\) and \(B\), and
We would prove by induction on \(x\) that
For \(x = 0\), we have \(A(0,y) = y+1 = B(0,y)\).
Assuming our result for \(x\), we show our goal statement about \(x+1\) by induction on \(y\). For \(y = 0\),
And assuming \(A(x+1,y) = B(x+1, y)\), we have
Finally, we come to the Collatz function. The Recursion Theorem implies that there is a computable funcction satisfying the recursion equations for \(collatz\). It does not tell us that this function is total. Indeed, the totality of this function is equivalent to the Collatz conjecture, and this is an open question. We also do not know whether there is just one partial function that satisfies the recursion equations, but this, too, is equivalent to the Collatz conjecture.
It is also easy to think of examples where there are more than one partial function satisfying a set of recursion equations. One is
Here all of the constant functions are solutions (and vice-versa). The most natural solution would seem to be the empty function, and surely this is what our way of proving the Recursion Theorem would give.