From Turing Machines to the Halting Problem
Tue Apr 01 2025
Why Turing Machines?
If you know a bit about Turing machines, you might wonder: in an era where computing devices have gone through countless iterations, the Turing machine seems like an awkward and inefficient model. Any modern device appears far more elegant and fast. So, is it still necessary to understand the Turing machine? What can it possibly offer us today?
For the first question, the answer is: it depends. If you’re not interested in computability or complexity theory and your focus is purely on applications, then you might not need to study Turing machines at all.
For the second question, the Turing machine offers a formal mathematical model for rigorous proofs — and it’s surprisingly powerful:
-
The Church–Turing thesis tells us that any computable problem can be solved by a Turing machine. This means anything your computer can do—or anything you can program in Python, Haskell, or C—can also be done by a Turing machine. In terms of computational power, they are equivalent.
-
If an algorithm runs in polynomial time on a Turing machine, it will also run in polynomial time on a RAM model—that is, on real-world devices like smartphones and computers.
Any function that can be computed algorithmically can also be computed by a Turing machine.
— Church–Turing Thesis
Therefore, if we prove that a problem cannot be solved by a Turing machine, then no programming language, RAM model, or even any other computing model can solve it.
If we prove an algorithm’s complexity is polynomial on the Turing machine model, it will belong to the same complexity class on any programming language or RAM-based device (though the actual runtime may differ). The same applies in reverse.
One of the most famous problems that a Turing machine cannot solve is the Halting Problem. By the end of this blog, we’ll see why.
Definition of a Turing Machine
The idea of a Turing machine was first introduced by Alan Turing in 1936. A computable problem is written on an input tape, which extends infinitely to the right. The machine starts in an initial state with its read/write head pointing to the first symbol of the input. Based on a set of rules, the current symbol under the head, and its state, the Turing machine can:
- Update the symbol at the current position
- Change its state
- Move the head left or right
When the computation finishes, the result remains on the tape.
Formally, a Turing machine is defined as a 5-tuple :
- is a finite alphabet of symbols, including the blank symbol .
- is a finite set of states.
- is the initial state.
- is the set of halting states.
- is the transition function.
is used to represent the input on the tape—it can be as simple as , like a binary computer, or any alphabet that is easy to work with.
defines the machine’s states, tells it where to start, and defines the states where the machine should stop immediately.
encodes the rules—the algorithm for solving the problem—and is usually written as:
Here, is the current state, and is the current symbol under the head. Based on these, determines the next state, the new symbol to write, and the direction to move the head.
Note: Besides the 5-tuple definition, some conventions of Turing machines may vary—for example, whether the tape is infinite on both sides, or whether the head starts on the first input symbol or just before it. These conventions are ultimately reflected in the definitions of and .
Example
Let’s define a Turing machine that inverts all the 0s and 1s in the input. For example, given 11001, the output will be 00110. Its 5-tuple is defined as:
The transition function is defined as:
For the input 10011, the Turing machine runs on the tape as follows:
You may have noticed that for linear problems, a Turing machine can solve them quickly. But for nonlinear problems, the solutions are often less intuitive. Here, we only need to convince ourselves that any problem a computer can solve can also be solved by a specific Turing machine.
Decision Problem
A decision problem is a type of problem with a YES or NO answer. For example, given a positive integer, determine whether it is even; or given a Turing machine and an input, determine whether the machine halts on that input. For such problems, the Turing machine does not need to write the answer on the tape. Instead, it uses two special halting states, and , to represent acceptance and rejection. (This can easily be converted into writing the answer on the tape if needed.)
To formally define a decision problem, we consider that for any input string, there are two cases:
- The string is a YES instance.
- The string is a NO instance.
We define the set of all YES-instance strings as the language (languages are just subsets of ). A Turing machine that solves this decision problem acts as a decision function: when given input , it halts in state ; otherwise, it halts in state .
For example, consider the problem of determining whether a number is even, and the Turing machine that solves it.
The alphabet is , and the language . Then, for input , halts in state . For input , halts in state .
Encoding
At this point, we have a basic understanding of how a Turing machine works. However, some parts are still lacking a formal definition—for example, the input . For the same problem and data, the encoding is not unique.
Take the parity-checking problem for positive integers as an example. If the alphabet is , the input can be a string of decimal digits. Alternatively, we could represent the number in binary using only . Even with the alphabet fixed to , encoding is still not unique—for example, we could encode a number by repeating the symbol : becomes 11, and becomes 11111.
Therefore, we need to define what makes an encoding valid or invalid. For a problem and data instance , a valid encoding system should satisfy:
- If , then .
- We should be able to determine whether a string is a valid encoding of some .
- It must be possible to recover the original from .
For point 2, recognizability helps us check whether the input is a valid instance of the problem. For example, in the positive integer parity-checking problem over the alphabet , the string “0” is not a valid encoding, since 0 is not a positive integer. Therefore, it is not the encoding of any valid data . Other examples of invalid encodings might include or .
In decision problems, inputs that are invalid or do not belong to the problem domain—along with the NO instances—together form the set of inputs that the Turing machine should reject.
Decidability and Recognizability
Before we can decide whether a problem can be solved by a Turing machine, we must first define what it means for a problem to be solved by a Turing machine.
For decision problems encoding as language , we require that the Turing machine produces the correct answer in a finite number of steps. That is, if the data is a YES-instance, the input , then halts in within a finite number of steps. If is a NO-instance, the input , or not a valid encoding, then halts in within a finite number of steps. At this point, we say that decides .
If there exists a Turing machine that decides a language , then the language and its corresponding decision problem are called decidable.
If no Turing machine exists that decides a language , then the language and its corresponding decision problem are called undecidable or unsolvable.
Among these, some problems are still recognizable—meaning there exists a Turing machine that halts on all YES-instances, but dose not halt on NO-instances.
Clearly, the Halting Problem is a recognizable problem. We can simply run the given Turing machine on the given input (see following section): if the machine halts, we also halts. If it does not halt, we make no decision.
Universal Turing Machine
So far, the Turing machines we’ve introduced are designed to solve specific tasks. This is quite different from modern computers, which allow us to run task-specific programs directly, rather than building a separate “machine” for each task. This leads to the concept of the Universal Turing Machine (UTM).
A UTM takes as input a encoding of a Turing machine and an input , then simulates the behavior of and produces the same result.
A UTM does exist, and can be constructed in various ways. One possible structure is as follows:
- The input to the UTM is , where includes all of ‘s information and its transition function.
- The UTM checks whether and are valid. If not, it enters an infinite loop.
- The UTM then simulates : if halts and produces an output , the UTM does the same; if loops forever, so does the UTM.
The Undecidability of the Halting Problem
The Halting Problem is a decision problem: given a Turing machine and an input , determine whether halts on . The corresponding language can be defined as:
We already know that is recognizable. Now, we will prove that it is undecidable.
We use proof by contradiction: assume there exists a Turing machine that decides .
Now we construct a Turing machine that takes an input , then runs on input .
- If accepts —meaning that running the decoded Turing machine on input halts—then enters an infinite loop.
- If rejects —meaning that on input does not halt or the encoding is invalid—then accepts.
Now consider feeding as input to . The execution flow of is as follows:
- runs on input .
- Then decides whether halts on input . If halts on input , then accepts; otherwise, it rejects.
- If accepts , then enters an infinite loop;
if rejects , then accepts .
However:
- accepting implies that halts on input ,
but in fact enters an infinite loop on that case. - rejecting implies that does not halt on input ,
but in fact halts.
This contradiction shows that no Turing machine can decide the language .
The Unrecognizability of the Complement of HALT
The language HALT is recognizable. As a direct consequence, its complement, , is not recognizable.
We use proof by contradiction: suppose there exists a Turing machine that recognizes . Together with a machine that recognizes , we can construct the following machine decides :
The input is given to both and , which run in parallel. The simplest method is to let each machine execute one step at a time, alternating between them. Since and recognize and respectively, for any , will halt and accept; otherwise, will halt and accept.
This proof idea applies to any recognizable language—in fact, the complement of any recognizable language is not recognizable.
Conclusion
We have now proven that the Halting Problem is undecidable, and that no known real-world computational model can solve it. But how can we deal with it—or at least work around it?
The answer is to place restrictions on the Halting Problem. For example: does Turing machine halt on input within 100 steps? This version is clearly decidable.
Acknowledgments
This blog references material from the slides of COMP0017 Computability and Complexity Theory at University College London.