Turing Machines (TMs)
We saw that finite automata recognize regular languages
and pushdown automata recognize context-free languages, but
both models have fundamental limitations. The Turing machine, introduced by Alan Turing,
removes these limitations by providing an infinite tape that serves as both input and unbounded read/write memory.
It is the standard model for defining what it means to compute.
Definition: Turing Machine
A Turing machine is a 7-tuple \((Q, \Sigma, \Gamma, \delta, q_0, q_{\mathrm{accept}}, q_{\mathrm{reject}})\) where
\(Q, \Sigma, \Gamma\) are finite sets and
- \(Q\) is the set of states,
- \(\Sigma\) is the input alphabet, not containing the blank symbol \(\sqcup\),
- \(\Gamma\) is the tape alphabet, where \(\sqcup \in \Gamma\) and \(\Sigma \subseteq \Gamma\),
- \(\delta: Q \times \Gamma \to Q \times \Gamma \times \{L, R\}\) is the transition function,
- \(q_0 \in Q\) is the start state,
- \(q_{\mathrm{accept}} \in Q\) is the accept state,
- \(q_{\mathrm{reject}} \in Q\) is the reject state, where \(q_{\mathrm{accept}} \neq q_{\mathrm{reject}}\).
The key differences between a Turing machine and a finite automaton are:
- The tape has infinite length. Initially it contains the input string,
with blank symbols (\(\sqcup\)) filling all remaining cells.
- A Turing machine can both read symbols from the tape and write symbols on it.
- The read-write head can move both left (L) and right (R).
To store information, the machine writes it on the tape. To retrieve it later, the head
moves back to where it was written.
- The accept and reject states take effect immediately upon entry.
A computation therefore has three possible outcomes: accept, reject, or loop
(run forever without halting).
A Turing machine is strictly more powerful than any finite automaton or pushdown automaton, and is believed to capture the
full power of any real computer. By the Church-Turing thesis discussed below, a problem that no Turing machine can
solve cannot be solved by any algorithm.
Definition: TM Configuration, Computation, and Acceptance
Let \(M = (Q, \Sigma, \Gamma, \delta, q_0, q_{\mathrm{accept}}, q_{\mathrm{reject}})\) be a Turing machine. A
configuration of \(M\) is a triple \((q, t, i)\) consisting of the current state \(q \in Q\), the
current tape contents \(t \in \Gamma^{\mathbb{N}}\) (with all but finitely many cells equal to the blank symbol
\(\sqcup\)), and the current head position \(i \in \mathbb{N}\). Positions are 1-indexed throughout, in keeping with
our convention \(\mathbb{N} = \{1, 2, 3, \ldots\}\).
We write configurations in the linear notation \(u\, q\, v\). This notation means that the tape contents are \(uv\)
(followed by infinitely many blanks), the machine is in state \(q\), and the head is positioned on the first symbol of
\(v\). If \(v\) is empty, the head is on the blank cell immediately to the right of \(u\). For example, the
configuration \(1001\, q_5\, 0110\) represents a tape containing \(10010110\), with \(M\) in state \(q_5\) and the head
on the fifth symbol (the first \(0\) after the state label).
Configuration \(C\) yields configuration \(C'\), written \(C \vdash C'\), if \(C'\) is obtained from
\(C\) by a single application of \(\delta\) to the current state and the symbol under the head. Such an application
writes the new symbol, moves the head one cell left or right, and updates the state. A left move from the leftmost cell
leaves the head in place. The relation \(\vdash\) is undefined when the current state is \(q_{\mathrm{accept}}\) or
\(q_{\mathrm{reject}}\). Instead, \(M\) halts immediately upon entering either state, regardless of the value of
\(\delta\) at that configuration.
The start configuration of \(M\) on input \(w \in \Sigma^*\) is \(q_0 w\) (state \(q_0\), tape
contents \(w\) followed by blanks, head on the first symbol of \(w\)). An accepting configuration
is any configuration whose state is \(q_{\mathrm{accept}}\), and a rejecting configuration is any
whose state is \(q_{\mathrm{reject}}\). We say that \(M\) accepts input \(w\) if there exists a
finite sequence of configurations \(C_1, C_2, \ldots, C_k\) with \(C_1\) the start configuration on \(w\),
\(C_i \vdash C_{i+1}\) for each index \(i \lt k\), and \(C_k\) accepting. The
language recognized by \(M\) is
\[
L(M) = \{ w \in \Sigma^* \mid M \text{ accepts } w \}.
\]
The machine \(M\) halts on \(w\) if it reaches an accepting or rejecting configuration in finitely
many steps, and otherwise it loops on \(w\). It rejects \(w\) if it halts on \(w\) by
reaching a rejecting configuration.
Definition: Turing-Recognizable and Turing-Decidable
A language \(L\) is Turing-recognizable (or recursively enumerable) if some Turing
machine recognizes it. Such a machine accepts exactly the strings in \(L\). On a string not in \(L\), it may reject
or loop forever.
A language \(L\) is Turing-decidable (or simply decidable) if some Turing
machine decides it. Such a machine halts on every input, accepting strings in \(L\) and rejecting strings
not in \(L\).
For a language \(L\), we call a machine that recognizes \(L\) a recognizer for \(L\), and a machine that
decides \(L\) a decider for \(L\). Every decidable language is Turing-recognizable, but the converse does
not hold. Some Turing-recognizable languages are not decidable. The distinction hinges on whether the machine is
guaranteed to halt.
Example:
Consider the language
\[
L_1 = \{0^{2^n} \mid n \geq 0\},
\]
which consists of all strings of \(0\)s whose length is a power of 2.
The following Turing machine \(M_1\) decides \(L_1\):
\(M_1 = \) "On input string \(w\):
- Read left to right across the tape, crossing out every other \(0\).
- If in Stage 1, the tape contained a single \(0\), accept.
- If in Stage 1, the tape contained no \(0\), or more than a single \(0\) with the number of \(0\)s odd, reject.
- Return the head to the left-hand end of the tape.
- Go back to Stage 1."
In the state diagram below, Stage 1's "crossing out every other \(0\)" is realized in two steps. The machine first
replaces the leftmost \(0\) with a blank \(\sqcup\), which serves as the left-end marker that the head returns to
in Stage 4. It then replaces every other subsequent \(0\) with \(\text{x}\). The trace that follows illustrates
exactly this behavior.
Here \(Q = \{q_1, q_2, q_3, q_4, q_5, q_{\mathrm{accept}}, q_{\mathrm{reject}}\}\), \(\Sigma = \{0\}\), and
\(\Gamma = \{0, \text{x}, \sqcup\}\). The state diagram of \(M_1\) is as follows:
For example, if the input is \(0000\), the sequence of configurations is as follows:
\[
\begin{align*}
&q_1 0 0 0 0 \vdash \sqcup q_2 0 0 0 \vdash \sqcup \text{x} q_3 0 0 \vdash \sqcup \text{x} 0 q_4 0 \\\\
&\vdash \sqcup \text{x} 0 \text{x} q_3 \sqcup \vdash \sqcup \text{x} 0 q_5 \text{x} \sqcup \vdash \sqcup \text{x} q_5 0 \text{x} \sqcup \\\\
&\vdash \sqcup q_5 \text{x} 0 \text{x} \sqcup \vdash q_5 \sqcup \text{x} 0 \text{x} \sqcup \vdash \sqcup q_2 \text{x} 0 \text{x} \sqcup \\\\
&\vdash \sqcup \text{x} q_2 0 \text{x} \sqcup \vdash \sqcup \text{x} \text{x} q_3 \text{x} \sqcup \vdash \sqcup \text{x} \text{x} \text{x} q_3 \sqcup \\\\
&\vdash \sqcup \text{x} \text{x} q_5 \text{x} \sqcup \vdash \sqcup \text{x} q_5 \text{x} \text{x} \sqcup \vdash \sqcup q_5 \text{x} \text{x} \text{x} \sqcup \\\\
&\vdash q_5 \sqcup \text{x} \text{x} \text{x} \sqcup \vdash \sqcup q_2 \text{x} \text{x} \text{x} \sqcup \vdash \sqcup \text{x} q_2 \text{x} \text{x} \sqcup \\\\
&\vdash \sqcup \text{x} \text{x} q_2 \text{x} \sqcup \vdash \sqcup \text{x} \text{x} \text{x} q_2 \sqcup \\\\
&\vdash \sqcup \text{x} \text{x} \text{x} \sqcup q_{\mathrm{accept}}.
\end{align*}
\]
Multitape Turing Machines
A natural extension of the basic Turing machine model is to allow several tapes, each with its own
independent read/write head. Initially the input appears on tape 1, and the remaining tapes start out
blank. The transition function is generalized to allow simultaneous reading, writing, and head movement
across all tapes.
Definition: Multitape Turing Machine
A multitape Turing machine with \(k\) tapes is a Turing machine whose transition function has the form
\[
\delta: Q \times \Gamma^k \to Q \times \Gamma^k \times \{L, R, S\}^k,
\]
where \(k \geq 1\) is the number of tapes.
The expression
\[
\delta(q_i, a_1, \ldots, a_k) = (q_j, b_1, \ldots, b_k, L, R, \ldots, L)
\]
means that if the machine is in state \(q_i\) and the heads on tapes \(1\) through \(k\) are reading symbols \(a_1\)
through \(a_k\), then the machine transitions to state \(q_j\), writes \(b_1\) through \(b_k\) on the corresponding
tapes, and directs each head to move left (\(L\)), right (\(R\)), or stay in place (\(S\)) as specified.
Multitape Turing machines appear more powerful than the single-tape model. For instance, a two-tape machine can decide the
language \(\{0^k 1^k \mid k \geq 0\}\) in linear time, whereas no single-tape machine can decide it in \(o(n \log n)\) time
(a known lower bound whose proof is beyond the scope of this page). Yet in terms of what can be computed
(recognizability and decidability), the two models are equivalent.
Theorem: Multitape-Single-Tape Equivalence
Every multitape Turing machine has an equivalent single-tape Turing machine, that is, one that recognizes
the same language.
Proof sketch.
Given a \(k\)-tape Turing machine \(M\), we construct a single-tape machine \(T\) that simulates \(M\).
The single tape of \(T\) represents the contents of all \(k\) tapes of \(M\) by storing them
consecutively, separated by a fresh delimiter symbol \(\#\):
\[
\# \, \text{tape}_1 \, \# \, \text{tape}_2 \, \# \, \cdots \, \# \, \text{tape}_k \, \#.
\]
To track each head's position, \(T\) marks the cell where \(M\)'s head currently sits on each tape
with a "dotted" version of that symbol (a new symbol added to the tape alphabet). For instance, if
\(M\)'s tape \(i\) contains \(010\) with the head on the middle \(1\), \(T\) records \(\#0\dot{1}0\#\).
On input \(w\), \(T\) first formats its tape into this representation (with \(w\) on tape 1 and the remaining tapes
blank). To simulate one step of \(M\), \(T\) scans across its tape from the leftmost \(\#\) to the \((k+1)\)-st \(\#\)
to read the symbols under all virtual heads, then makes a second pass to update the contents and head positions
according to \(M\)'s transition function.
If a virtual head moves rightward onto a delimiter \(\#\), \(T\) shifts that delimiter, together with all tape contents
to its right, one cell further right, and writes a dotted blank in the vacated cell. The virtual head now occupies this
fresh blank cell. If a virtual head would move left from the first cell of its tape, \(T\) leaves it in place,
following for each tape of \(M\) the convention that a left move from the leftmost cell does not move the head. The
machine \(T\) accepts (or rejects) precisely when \(M\) does. Hence \(T\) recognizes the same language as \(M\).
This equivalence justifies our continued use of the single-tape model as the "standard" Turing machine. Multitape machines
may be more convenient to design, but they offer no additional computational power. However, when we turn to
time complexity, the choice of model does matter. The theorem on
single-tape vs. multitape simulation
quantifies the time overhead of this simulation.
Algorithms
An algorithm is an effective procedure. By this we mean a finite sequence of precise instructions that,
given an input, produces an output in a finite number of steps. Algorithms have been used throughout the history of
mathematics, and Euclid's algorithm for the GCD dates to about 300 BCE. Yet the concept was not given a precise
mathematical definition until 1936, when Alonzo Church (via the \(\lambda\)-calculus) and Alan Turing (via the Turing
machine) independently formalized it.
Thesis: Church-Turing Thesis
Every effective algorithm can be implemented as a Turing machine. Equivalently,
any function computable by an algorithm (in the intuitive sense) is computable by a Turing machine.
The thesis is not a theorem in the formal sense, and it cannot be proved, since "algorithm" in the intuitive
sense is not a formal concept. It is nevertheless almost universally accepted. The supporting evidence is that every
model proposed to capture effective, mechanical computation has turned out to be equivalent to the Turing machine in
power. These models include the \(\lambda\)-calculus, recursive functions, and register machines. Later models of
computation, such as suitable cellular automata and general-purpose programming languages given
unbounded memory, are likewise equivalent.
Now we have a fundamental question: are there problems that no algorithm can solve? The answer is yes. Studying
unsolvability is valuable for two reasons. First, recognizing that a problem is algorithmically unsolvable
guides us to modify or relax it into a tractable variant. Second, understanding the absolute limits of computation provides
deep insight into the structure of problems themselves.
We summarize the key facts about the decidability hierarchy. These results establish the relationships
among the language classes we have studied.
Theorem: Decidability Hierarchy
- Every context-free language (CFL) is decidable.
- Some Turing-recognizable languages are undecidable.
- A language \(L\) is decidable if and only if both \(L\) and its complement
\(L^c = \Sigma^* \setminus L\) are Turing-recognizable. (A language whose complement
is Turing-recognizable is called co-Turing-recognizable. Thus the condition
is that \(L\) is simultaneously Turing-recognizable and co-Turing-recognizable.)
Proof sketch.
We sketch each claim in turn.
Claim 1 (every CFL is decidable). Given a CFL \(L\) generated by a
context-free grammar \(G\), the membership
question "is \(w \in L\)?" can be decided by the Cocke-Younger-Kasami (CYK) algorithm. We assume that \(G\)
has been converted into Chomsky Normal Form beforehand. This conversion is a fixed transformation of the grammar, not
part of processing the input. The algorithm uses dynamic programming to build up the set of variables that can derive
each substring of \(w\), and it accepts if and only if the start variable derives \(w\) itself. The procedure performs
\(O(|w|^3)\) table operations and in particular halts on every input, so the
Turing machine implementing it decides \(L\).
Claim 2 (some Turing-recognizable languages are undecidable). The canonical example is
the acceptance problem
\[
A_{\mathrm{TM}} = \{ \langle M, w \rangle \mid M \text{ is a Turing machine that accepts } w \}.
\]
The language \(A_{\mathrm{TM}}\) is Turing-recognizable. A universal Turing machine takes
\(\langle M, w \rangle\) as input, simulates \(M\) on \(w\), and accepts whenever \(M\) accepts. However,
\(A_{\mathrm{TM}}\) is undecidable. The proof, a modern form of Turing's diagonal argument, is analogous to
the one we develop in the next section. Suppose \(H\) were a decider for \(A_{\mathrm{TM}}\). Let \(D\) be the machine
that, on input \(\langle M \rangle\), runs \(H\) on \(\langle M, \langle M \rangle \rangle\) and outputs the opposite
answer, rejecting if \(H\) accepts and accepting if \(H\) rejects. Since \(H\) always halts, so does \(D\), and \(D\)
accepts \(\langle M \rangle\) exactly when \(M\) does not accept \(\langle M \rangle\). Running \(D\) on its own
description \(\langle D \rangle\) then gives that \(D\) accepts \(\langle D \rangle\) if and only if \(D\) does not
accept \(\langle D \rangle\), a contradiction.
Claim 3 (decidable if and only if Turing-recognizable and co-Turing-recognizable). (\(\Rightarrow\))
If \(L\) is decidable, a decider \(M\) for \(L\) recognizes \(L\), so \(L\) is Turing-recognizable. Swapping
\(q_{\mathrm{accept}}\) and \(q_{\mathrm{reject}}\) in \(M\) yields a decider, hence a recognizer, for \(L^c\).
(\(\Leftarrow\)) Suppose \(M_1\) recognizes \(L\) and \(M_2\) recognizes \(L^c\). We build a new Turing machine \(M\)
that, on input \(w\), simulates \(M_1\) and \(M_2\) in parallel step by step (advancing each machine by one
step in alternation, on a shared input). Since every \(w\) lies in exactly one of \(L\) or \(L^c\), exactly one of
\(M_1, M_2\) eventually accepts. The machine \(M\) halts and accepts (resp. rejects) when \(M_1\) (resp. \(M_2\))
accepts. Thus \(M\) decides \(L\).
Modern computers are essentially finite versions of Turing machines. More precisely, they are random-access machines (RAMs)
with bounded memory. Any algorithm that runs on a real computer can, in principle, be translated into a Turing machine,
although the resulting machine may be inefficient.
Unsolvability
The decidability hierarchy already rules out the possibility that every language is at least recognizable.
Since \(A_{\mathrm{TM}}\) is Turing-recognizable but undecidable, item 3 of that theorem shows that its complement is
not Turing-recognizable. The main theorem of this section reaches the same conclusion by a counting argument that
depends on no particular language. There are languages beyond the reach of any Turing machine whatsoever.
The proof below uses Cantor's diagonalization method, a technique for revealing the limits
of any system by constructing an object that disagrees with every candidate the system can produce.
We first develop the method in its purest set-theoretic form.
Theorem: Cantor's Theorem (Power Sets)
For any set \(X\), there is no bijection between \(X\) and its power set \(\mathcal{P}(X)\).
In particular, \(\mathcal{P}(\mathbb{N})\) is uncountable.
Proof.
Suppose for contradiction that \(f: X \to \mathcal{P}(X)\) is a bijection. Define the set
\[
D = \{ x \in X \mid x \notin f(x) \} \in \mathcal{P}(X).
\]
Since \(f\) is surjective, there exists \(d \in X\) with \(f(d) = D\). Now ask: is \(d \in D\)?
- If \(d \in D\), then by definition of \(D\) we have \(d \notin f(d) = D\), a contradiction.
- If \(d \notin D\), then by definition of \(D\) we have \(d \in f(d) = D\), a contradiction.
Either case is contradictory, so no such bijection \(f\) exists. The argument used only the surjectivity of \(f\), so
in fact no map \(X \to \mathcal{P}(X)\) is surjective. Taking \(X = \mathbb{N}\) shows that \(\mathcal{P}(\mathbb{N})\)
is uncountable. Indeed, by definition a set is countable if and only if it is in bijection with \(\mathbb{N}\) or with
a subset of \(\mathbb{N}\). If \(g: S \to \mathcal{P}(\mathbb{N})\) were a bijection with \(S \subseteq \mathbb{N}\),
then \(S\) would be nonempty, because \(\mathcal{P}(\mathbb{N})\) is nonempty. Fixing \(s_0 \in S\) and sending every
element of \(\mathbb{N} \setminus S\) to \(g(s_0)\) would then extend \(g\) to a surjection
\(\mathbb{N} \to \mathcal{P}(\mathbb{N})\), which is impossible.
We now apply the same cardinality contrast to Turing machines. Over a fixed input alphabet, there are, up to renaming of
states and auxiliary tape symbols, only countably many machines but, by the theorem above, uncountably many languages.
Theorem: Existence of Non-Recognizable Languages
Some languages are not Turing-recognizable.
Proof.
Fix a nonempty finite alphabet \(\Sigma\). First, we show that, up to renaming, the Turing machines with input alphabet
\(\Sigma\) form a countable set. Renaming the states or the tape symbols outside \(\Sigma \cup \{\sqcup\}\) does not
change the language a machine recognizes, so we may assume that the states are drawn from a fixed list
\(q_1, q_2, \ldots\) and those tape symbols from a fixed list \(\gamma_1, \gamma_2, \ldots\), and we count only such
machines. Each such machine \(M\) can then be encoded as a finite string \(\langle M \rangle\) over some fixed finite
alphabet \(\Delta\). For instance, we can serialize its 7-tuple specification with appropriate delimiters so that
distinct machines produce distinct strings.
The set \(\Delta^*\) of all strings over \(\Delta\) can be written as
\[
\Delta^* = \bigcup_{n \geq 0} \Delta^n,
\]
where \(\Delta^n\) is the set of strings of length \(n\). Each \(\Delta^n\) is finite, so listing the strings of
\(\Delta^0\), then those of \(\Delta^1\), and so on, gives a list in which every string of \(\Delta^*\) appears exactly
once at a finite position. Hence \(\Delta^*\) is countable. The encoding \(M \mapsto \langle M \rangle\) is injective,
so the set of machines we count is in bijection with a subset of \(\Delta^*\), and hence is also countable.
Next, we show that the set of all languages over \(\Sigma\) is uncountable. A language over \(\Sigma\) is, by
definition, any subset of \(\Sigma^*\), so the set of all languages is exactly \(\mathcal{P}(\Sigma^*)\). The same
listing, applied to \(\Sigma\), enumerates every string of \(\Sigma^*\) exactly once. Since \(\Sigma\) is nonempty, the
list is infinite, so it puts \(\Sigma^*\) in bijection with \(\mathbb{N}\). Transporting
Cantor's theorem along this bijection, we conclude
that \(\mathcal{P}(\Sigma^*)\) is uncountable.
Every Turing-recognizable language over \(\Sigma\) is recognized by one of the machines we count. Indeed, a recognizer
whose input alphabet differs from \(\Sigma\) can be converted into one with input alphabet exactly \(\Sigma\): after
any auxiliary tape symbol of the original machine that lies in \(\Sigma\) is renamed to a fresh symbol outside
\(\Sigma\), the original machine's input symbols outside \(\Sigma\) become auxiliary tape symbols, and a preliminary
scan rejects any input containing a symbol of \(\Sigma\) outside the original input alphabet. Since each machine we
count recognizes exactly one language over \(\Sigma\), the recognizable languages over \(\Sigma\) are the image of a
countable set and therefore form a countable set, while the set of all languages over \(\Sigma\) is uncountable. Hence
some language over \(\Sigma\) cannot be recognized by any Turing machine.
Combined with the Church-Turing thesis, this
theorem implies that there exist well-defined problems that no algorithm can ever solve. Even among the problems
that can be solved, many practically important ones are intractable in the worst case. Such problems can still be addressed
through approximation algorithms and heuristics, which find good (if not provably
optimal) solutions in reasonable time.
Having established what is and is not computable, we next ask: among the decidable problems,
how efficiently can they be solved? This is the subject of
time complexity.