Alan Turing, a British mathematician better known for his contribution to decoding the German Nazi ENIGMA machine and for his philosophic thesis, first appearing in the prestigious British philosophy journal Mind, about the machine nature of thinking6.1, proposed a model of effective computation in 1936 that still defines the limits of electronic computing machines. The naive 19th Century belief that all mathematical theory could be reduced to a set of mechanical processes, or algorithms, was dealt a crippling blow by the Czech logician Kurt Gödel in 1928 and a knockout punch by Alan Turing 8 years later. Thus, it is encumbant upon the student of information to learn what sorts of problems are amenable to mechanical processes and which are not.
In his effort to formalize mathematics with mechanical rules to solve a famous mathematical problem propounded by the German mathematician David Hilbert, Turing developed an abstract model of a computer. A Turing machine is basically a super typewriter6.2 with a sophisticated set of internal states (not just ``upper case'' and ``lower case''). Just as a typewriter is capable of moving about a page a supertypewriter moves back and forth on a tape. It turns out that the added dimension of movement is extraneous and that the tape model captures the essence of randomly seeking a position to posit a mark, or write upon the page. In this way the typewriter is able to store information on a random-access basis. Abstracting from the page structure, the super typewriter writes upon an unlimited one-dimensional tape.
Turing's super typewriter could carry out one additional function that was very restrictive for mechanical typewriters: it could read as well as write. Thus it is a kind of super automaton, i.e. one that can read as well as write onto its tape. Because it can write, e.g. erase symbols, its tape head is allowed to move freely in both directions. It is thus equipped with an (unlimited) memory of sorts upon which it performs its computations.
In a paper entitled `On Computable Numbers, with an application to the Entscheidungsproblem' (see below) Turing proposed such a machine or automaton, equipped with the logical equivalent of a random- access memory, to determine how far one can go in mechanising mathematics, i.e. solve hard problems using a device like the one described above.
The really astonishing thing is that this machine, or model of computation is still with us today. Taking his cue from Gödel Turing surmised that if it were possible to describe any particular machine by means of a formalized state transition table, then it must be possible to create a machine, a universal machine, that operates on such tables in such a manner to simulate any thusly constructed machine. Such a machine could actually be built using discrete electronic circuitry. Indeed, von Neumann's stored program, called ENIAC was one step in this direction, Babbage's Analytical Engine (conceived in 1837!) yet another. Turing further resolved to ``build a brain'' that could simulate neuronal processes in the human brain and thus, like Humpty-Dumpty, explain the Jabberwocky. Thus was initiated the EDVAC project at Cambridge under Turing's auspices. When we understand this machine, we will understand what computers are capable of. I dare say that this is the fundamental question of the newborn discipline that has come to be know as `Informatics' or `Computer Science'.6.3
As with automata an output function could be defined, but is of no theoretical interest here. The
transition function f is not defined on the states of H because the machine halts there. Some
authors use a set ZF of acceptance states instead of H, but this detracts from the primary
motivation behind Turing machines. Finally, blanks `
' initially occupy all cells on the input
tape where there is no input or end marker. In particular, the first blank denotes the end of the
input (at least initially).
Note that Turing machines are by definition deterministic.
| f ($, zA) | = | ($, zA, R) | |
| f (0, zA) | = | (0, zA, R) | |
| f (1, zA) | = | (1, z1, R) | |
| f ( |
= | (1, z1, R) | |
| f (0, z1) | = | (1, hA) |
A Turing machine differs from an automaton in several points. One worth mentioning here is that after
the input is presented on the input tape the Turing machine can read from or write onto the
tape. Thus the tape serves as a primitive type of memory or store. Contrary to concrete machines the
Turing machine's memory is unbounded. A Turing machine may also write a blank `
' over any
x
Xinput on the tape. This operation is called erasing.
As with automata a configuration of a Turing machine is to be defined: if
= (X, Z, H, f, zA) is a Turing machine then a configuration of
is an element of
$ . X*×Z×(X* . (X - {
}))
{
}. Intuitively, a configuration
of a Turing machine is a state, the current contents of the tape and a head position. It is convenient
to represent this information by dividing the tape into two halves: the first half consists of the
symbols from the initial tape symbol `$' up to but not including the symbol under the tape head, and
the second half consists either of nothing (i.e. the rest of the tape is blank) or a string of
tape symbols that ends with a non-blank character. The symbol under the tape head always belongs
to the second half. A configuration of a Turing machine can thus be written (x, z, x', where z is the
state of the configuration, x the first half of the tape's contents and x' the rest. If z
H
then the Turing machine is in a halted configuration. The initial configuration is $zA (thus we
need not bother about the action of the transition function at the outset.
A configuration
C1 : ($ua, z1, bv) (a, b
X) yields configuration
C2 : ($u, z2, acv) (c
X)
with a left head movement, written
C1
C2, if
f (b, z1) = (c, z2, L). For a right move configuration
C1 : ($u, z1, abv) yields configuration
C2 : ($uc, z2, bv) with a right head movement, written
C1
C2,
if
f (a, z1) = (c, z2, L). For stationary head moves
C1
C2 we just have
($u, z1, av)
yields
($u, z2, bv) with stationary head movement if
f (a, z1) = (b, z2,
).
There are still two special cases
worthy of mention: if
v =
and
b = `
, then
($ua, z1,
)
($u, z2, a)
if
f (
, z1) moves left into state z2. If
f (a, z1) = (
, z2, R) then
($u, z1, a)
($u
, z2,
). Note the position of the tape head in this
case. For
an interpretation of the concept `configuration' consult the illustrations in Fig. 6.2
In all cases we write C1
A computation of a Turing machine
is a sequence of configurations
Finally,
accepts
x
Xinput* if
($, zA, x)
(x', hA, x''). Note
that it is only required that
be in the acceptance state hA using the input symbols. If,
on the other hand
($, zA, x)
(x', hR, x''), then
rejects
x.
decides a language
L
X*input, if for each x
L
accepts x
and for each
x
X*input - L,
rejects x. For historical reasons then language L is
then called recursive, i.e. there is some Turing machine that decides L.
One final remark. There is one other possibility for a Turing machine that did not occur for automata: a Turing machine may never halt on some input. This eventuality is very important for the sequel.
This section will now be concluded by constructing a Turing machine that recognizes the language of all strings that have an even number of 1's.
| f ($, zA) | = | ($, zA, R) | |
| f (1, zA) | = | (1, z1, R) | |
| f (1, z1) | = | (1, zA, R) | |
| f ( |
= | ( |
|
| f ( |
= | ( |
|
| f (1, z2) | = | (1, hA) | |
| f (1, z3) | = | (1, hR) | |
| f ($, z2) | = | ($, hA) |
This is indeed the approach that Turing took when he set out to define his universal machine, i.e. one that takes any Turing machine as input. One of the problems Turing faced was how to encode that data upon which a given Turing machine operates into a string of neutral data, e.g. 0's and 1's, that can then be represented on a ``computer's'', or, better, universal Turing machine's, input tape. Ignoring for the nonce the problem of encoding states, concentrate upon that of encoding data on the input string.
There are two easy encodings for data. The first so-called unary encoding deals with a specific enumeration of the input
symbols
x1, x2,..., xn. Then these specific symbols can be encoded by encoding the subscripts. By
using just one data symbol, call it `|', it is possible to encode strings consisting of any number
of symbols simply be repeating that symbol sufficiently often. In addition, Turing required an
abstract symbol `#' to separate input symbols and a blank symbol `
' to denote the end of the input.
Another natural, more efficient encoding for natural numbers would be to employ binary sequences
to represent these values: if
x = x1x2 ... xn
{0, 1}* then define
In this way a Turing machine
can also be regarded as an embodiment of a numerical function
n = f (n1, n2,..., nk): if
xi
{0, 1}* with
val(xi) = ni (i = 1,..., n) and
y
{0, 1}* with
val(y) = n
The control for machines having this kind of input is then described in the seven programming statement given in Table 6.1.
| Nr. | Statement | Tape |
| 1 | Right |
$ |
| 2 | if | goto 1 |
$|| |
| 3 | Write | |
$|| |
| 4 | Right |
$||| |
| 5 | if | goto 4 |
$|||||| |
| 6 | Left |
$||||| |
| 7 | Write |
$||||| |
| 8 | Left |
$|||| |
| 9 | halt |
Lest it be thought that the level of abstraction used in Turing programs is not realizable on the rather
simplistic model given for Turing machines, it is now intended to demonstrate how to realize each of
the seven statements to Turing machines that are constructed by concatenating Turing machines of a
similar type.
With these elementary operations the preceding Turing program could be written as drawn in Fig. 6.4.
Note this this machine halts and accepts automatically after the last shift.
It goes without saying that every time a Turing machine is repeated in such diagrams a new machine is generated, having distinct states from all other such generated machines. This procedure was been left out for aesthetic reasons.
Employing the binary numerical value representation of data from the previous section, a Turing machine
can also be regarded as an embodiment of a numerical function
n = f (n1, n2,...nk): if
xi
{0, 1}* with
val(xi) = ni (i = 1,..., n) and
y
{0, 1}* with
val(y) = n
In this way,
x
L(
) can be represented as an argument for the function f. Generalizing
this procedure one can assume that initially the input tape has the unary representation
#
# ... #
Consider yet another recursive definition, this time for the multiplication of two natural numbers:
| mult(x, 0) | = | 0 | |
| mult(x,succ(y)) | = | (plus(mult(x, y), x)). |
Thus, f is defined firstly in terms of its first k variables and 0. Then f is defined for the same k arguments and (k + 1)st argument succ(nk+1) as a function h having k + 2 arguments.
The class of such functions
f :
is formally obtained as follows:
The class of primitive recursive functions actually provides a very rich, but enumerable class of numerical functions. For example, in addition to the canonical functions of numerical addition, subtraction, multiplication, numerical predecessor, numerical successor, any polynomial with natural number coefficients, any exponential with natural number arguments such as
As an example of a Turing computable, but not primitive, function consider the Ackermann function
A :
×
defined by
Note that there is no obvious way to compute this function.
Note that it is irrelevant in wich halting state
ends up in; the term semi decides is
often used for this type of acceptance. Note also that every recursive language is also recursively
enumerable.
Thus the class of Turing-computable functions is remarkably large. It is also a remarkable fact that this class cannot be enlarged by introducing more than one input tape, an input tape that is open in both directions or even by allowing random, instead of sequential, access to the machine's memory cells. Even more unexpected is the fact that the class of computable functions is not enlarged if nondeterminism, i.e. allowing a relation instead of a function when describing the state transitions, is introduced. The concept of `Turing machine' thus seems to be the appropriate mathematical model for a stored-program computer. The next section is devoted to showing that Turing machines, despite their great generality, cannot compute everything. In our constructive euphoria one important fact has been neglected: a Turing machine may never halt on some input, or, even worse, we may never know whether it will eventually halt or not.
Assuming an algorithm can be identified with a specific-purpose Turing machine, it did not take long for the mathematical community to discover the naive optimism behind Hilbert's conjecture. It has, for instance, been demonstrated that even very simply-stated conjectures, e.g. the feasibility of a general testing procedure to determine whether a polynomial in several variables has one or more integral roots, are algorithmically undecidable. Perversely enough, the algorithm for polynomials in one variable is known to most any first-year student in Computer Science. It is, however, interesting that many of these problems, including the one mentioned, are recursively enumerable. For instance, given a polynomial, just feed it integers. If there is an integral root then polynomial evaluation mechanism, i.e. the relevant Turing machine, will eventually halt and answer `yes.' If not, then it will never halt. The problem is thus recursively enumerable, but not decidable.
If an algorithm is identified with a computer program then the existence or non-existence of algorithms takes on a compelling relevance. If there are easily stateable mathematical problems that are algorithmically undecidable, then there are problems - easily stateable problems - for whose solutions computers offer little or no help.
Consider the following socially relevant problem: can one write a computer program that validates software? The input to this hypothetical program is a complete specification of a given program's allowable input. Then the program is run on this input and it is determined whether it computes its results correctly. It turns out that this is a mere pipe dream, a chimera.
What is the problem here? Just this: given a Turing and an allowable input, it is impossible to decide whether the Turing machine accepts the input. Of course there may be some specific input and some specific Turing machine for which there is indeed some ad hoc method, but there is no procedure that works in general.
Analogous to the idea of a stored-program computer, it is necessary first of all to define a Turing machine that takes as its input a Turing machine and an input string for the latter Turing machine. Then the decidability of the above problem reduces to the decidability of this Turing machine.
The neutral encoding of a general Turing machine
requires a little more care. The main
problem is how to devise a neutral encoding of a Turing machine's state transition table. Because there
are extra symbols involved the following table is offered to encode the general transition function:
| Symbol | Description | Code |
| si | State Symbol | |i+1 |
| xi | Alphabet Symbol | |i+3 |
| $ | Start Tape Symbol | | |
| Blank | || | |
| L | Move Left | | |
| R | Move Right | || |
| 0 | Don't Move | ||| |
| h | Halt State Reached | |||| |
The extra symbol h is required to facilitate a uniform code for all state transitions. Indeed, for
any Turing machine
with state transition function f (x, z) can be written
| ###|#|#|#|#||##|||#|#|||#|#||##||||#|#||||#||#||##||||#||#||||#||#|| | |||
| ###|||#||#||||#|||#||||### |
In general
must keep track of at least the three quantities
Thus, a three head machine would be the easiest way to construct
, but one can also proceed
explicitly as follows: divide
's input tape into three sectors containing 1) the (read only)
machine description ``
'', 2) the input string x with a properly marked P indicating the
current reading position (sort of a program counter) and 3)
's private work area set off from
the previous two sections with an M. This latter contains
's current state si and the
current input symbol xj.
operates according to the following paradigm:
Notice the tedious shift operations required when writing on the input tape. Owing to the unary
representation the input symbols will vary greatly in length and room needs to be made to accomodate
the new symbols in write operations. This could even involve shifting the entire tape to the right to make
enough space. The same holds true for
's work area. Finally, note
the uncanny resemblance to a ``real'' stored-memory computer program.
If we were to identify a Turing machine with an algorithm (so-called Church-Turing Thesis) then the Halting Problem asks whether there is some general algorithm that incorporates only properties general to all Turing machines and determines whether any given Turing machine will eventually halt on some given input machine. Of course, this ``only'' asks after a general algorithm. If a specific Turing machine is analyzed there may well be some ad hoc method to settle that particular question one way or the other.
Now use
1 to construct another Turing machine
2 as follows: in
2
the halting state hA is demoted to just another non-halting state. Thus, if
1 halts in
hA then
2 will go into an infinite loop:
Now apply
1 to itself to point up the inner contradiction of
1's very existence.
To this end, construct the Turing machine
3 from
2 as follows: given an
input string
= (``
'',``x'') the very first thing
3 does is to
duplicate it to
(
,
) and then sets
2 loose on
(
,
).
If
3 halts on ``
3'' then
2 halts on
(``
3'',
3''),
i.e.
1 halts in hR with the input
(``
3'',``
3''). But if
1 halts on some input, then, by construction,
2 cannot halt on that input
and hence
3 cannot halt on
``
3''. (
3'' is already
unary encoded.) This is a contradiction.
If, on the other hand,
3 does not halt on ``
3'', then
2 does not
halt on the input
(``
3'',``
3''), i.e.
1 halts in state hA on the
input
(``
3'',``
3''), which by definition means that
3 halts on the input
``
3'' - another contradiction.
Prof. Raymond Zavodnik, July 2002