Turing machines access their memory sequentially, one cell at a time. Register machines instead have a memory made of registers, each holding a natural number, accessed directly by their index. Several variants were introduced around 1960 by Melzak, Lambek, Minsky, and Shepherdson and Sturgis. We use the unlimited register machine (URM) of Shepherdson and Sturgis, in the form popularized by Cutland’s textbook. Its instruction set is small, which makes proofs about it short, and close to an assembly language, which makes it easy to program.
4.1 Definition
The machine has infinitely many registers , each containing a natural number. There is no bound on the size of these numbers.
A URM program is a finite sequence of instructions, each of one of the following four types:
| instruction | name | effect |
|---|---|---|
| zero | ||
| successor | ||
| transfer | ||
| jump | if , the next instruction is ; otherwise it is the following one |
where .
The operational semantics is defined through configurations.
A register state is a function with for all but finitely many . A configuration of is a pair where is the index of the next instruction and is a register state. It is halting if .
If , the successor of is given by:
- if : and ;
- if : and ;
- if : and ;
- if : , and if , otherwise.
Here denotes the state equal to except that register contains . The computation of from a configuration is the sequence of successive configurations, which is infinite or ends at the first halting configuration.
Jumping to an instruction index larger than is therefore a way of halting the program.
Let . The partial function computed by is defined as follows. Start from the configuration , where for and for . If the computation halts, in a configuration , then ; otherwise .
A partial function is URM-computable if it is for some program .
Note the asymmetries of the instruction set: registers can only be incremented, never decremented, and the only test is equality between two registers.
4.2 Examples
Addition. With in and in , the following program uses as a counter and increments until :
| if , halt | ||
| go to |
The instruction compares with itself and always jumps: it is an unconditional jump. By induction on , the configuration with , , is reached; for the program jumps to and halts with in .
Multiplication. The product is obtained by two nested loops. Register accumulates the result, counts the rounds of the outer loop and those of the inner loop.
| if , go to the end | ||
| if , leave the inner loop | ||
The program above computes .
We prove by induction on that the computation reaches the configuration where , , , , and for . For this is the initial configuration. Suppose it holds for . Since , the jump is not taken, and sets to . Then, by an inner induction on , the configuration with and is reached; for , the jump leads to , which increments , and returns to with and . For , jumps to , which copies into , and the program halts.
Write a URM program computing , where if and . Prove that it is correct.
Hint
There is no decrement instruction. Maintain two counters and in and .
Solution
| if , halt with output | ||
| , | ||
| if , go to | ||
| output |
If , the program halts at once with . If , one shows by induction on that the configuration with and is reached; for the jump is taken and is copied into . Without , the program would loop forever on input , since .
4.3 Combining programs
To build complex programs from simpler ones, we need to run one program after another, and to run a program on arguments stored in arbitrary registers. Two technical points must be handled: jumps that halt a program by jumping far beyond its end, and registers used as scratch space.
A program is in standard form if every jump of satisfies . We write for the largest register index mentioned in .
Every program is equivalent to a program in standard form, obtained by replacing every jump with by : the computations are the same, and when halts, the standard form program halts in the configuration with the same registers.
Let and be programs in standard form. The concatenation is the program where is with every jump target replaced by .
Let be in standard form and a register state. If the computation of from does not halt, neither does that of . If it halts with register state , then the computation of from continues as the computation of from , with instruction indices shifted by .
As long as the computation of is at an instruction , the computations of and coincide, since the first instructions are the same. Because is in standard form, when halts it is at instruction , which in is the first instruction of the shifted copy of . From there, a straightforward induction shows that a configuration of corresponds to the configuration of , since jump targets have been shifted accordingly.
To run a program on arguments located in arbitrary registers, and to place its result in a chosen register, we use the following notation. Let be a program in standard form computing a -ary function, and let be registers with indices greater than and . We write for the program
put in standard form (the concatenations being taken as above). It clears the registers used by , copies the arguments into , runs , and copies the result into .
Let compute . Started in any register state with , the program halts if and only if ; in that case it halts with in , and with all registers for , , unchanged.
Since the are larger than and , the zeroing instructions do not affect them, and after the transfers the registers contain exactly the initial configuration of on input restricted to these registers. The registers beyond are never mentioned by : they do not influence the computation and are not modified by it. Therefore the computation of proceeds as from its initial configuration on . The conclusion follows from Lemma 4.8.
4.4 Closure under composition
Let and be URM-computable. Then the partial function
is URM-computable.
Let be programs in standard form computing . Let be larger than , and the numbers , . We use the registers to save the input, and to store the values . Consider the program
(The last block copies its result into ; the definition of is adapted in the obvious way when .) By Lemma 4.9 and Lemma 4.8, if all converge, the program successively stores in — the saved input being left unchanged — and then runs on these values, halting with in if converges, and not halting otherwise. If some diverges, the program does not halt, in accordance with the convention that in that case.
4.5 Goto programs and assembly languages
The URM is a minimal example of a goto program: a numbered list of elementary instructions together with conditional jumps. Processors execute programs of this kind. Other common instruction sets, for instance with a decrement instruction and a test “if go to ”, lead to the same class of computable functions; this is a simple exercise in simulating one instruction set by another.
In the lesson LOOP and WHILE programs we consider structured programs, with for and while loops instead of jumps. They are more convenient to write, and the distinction between the two kinds of loops gives a characterization of the primitive recursive functions.
4.6 Exercises
Write a URM program computing the function , equal to if and to otherwise.
Solution
| if , halt (output ) | ||
| output |
Consider the variant of the URM without the transfer instruction . Show that it computes the same functions.
Solution
For , the instruction can be simulated with , and using as a counter a register with , where is the program being transformed: , , then the loop “if , exit; ; ; go back”, the backward jump being . The case is a no-op. Replacing each instruction by such a block, and shifting all jump targets accordingly, gives a program without whose computations follow those of on the registers . Since , the output register is never used as the counter, so both programs compute the same functions; the initial content of , possibly an input, is irrelevant because is zeroed before each use and is not mentioned by .
Prove that the URM-computable functions are closed under definition by cases: if are total URM-computable functions and is a set whose characteristic function is URM-computable, then if and otherwise is URM-computable.
Solution
Let compute the characteristic function of . Save the input in fresh registers, run on it with output in a fresh register , and use , where is a fresh register containing , to branch to a block computing on the saved input; otherwise continue with a block computing on the saved input, followed by an unconditional jump past the other block. Correctness follows from Lemma 4.9 and Lemma 4.8.
4.7 Notes and references
Register machines were introduced around 1960 in several variants, by Melzak, Lambek, Minsky, and Shepherdson and Sturgis. The URM and its notation follow Cutland’s textbook, which develops the whole of elementary computability theory on this model.
- J. C. Shepherdson, H. E. Sturgis, Computability of recursive functions, Journal of the ACM 10 (1963), 217–255.
- M. Minsky, Computation: Finite and Infinite Machines, Prentice-Hall, 1967.
- N. Cutland, Computability: An Introduction to Recursive Function Theory, Cambridge University Press, 1980.