Skip to main content

Computability

(Content adapted from Critchlow & Eck)

At this point, it would be useful to look at increasingly complex Turing machines, which compute increasingly complex functions and languages. Although Turing machines are very simple devices, it turns out that they can perform very sophisticated computations. In fact, any computation that can be carried out by a modern digital computereven one with an unlimited amount of memorycan be carried out by a Turing machine. Although it is not something that can be proved, it is widely believed that anything that can reasonably be called "computation" can be done by a Turing machine. This claim is known as the Church-Turing Thesis.

We do not have time to look at enough examples to convince you that Turing machines are as powerful as computers, but the proof reduces to the fact that computers are actually fairly simple in their basic operation. Everything that a computer does comes down to copying data from one place to another, making simple comparisons between two pieces of data, and performing some basic arithmetic operations. It's possible for Turing machines to do all these things. In fact, it's possible to build a Turing machine to simulate the step-by-step operation of a given computer. Doing so proves that the Turing machine can do any computation that the computer could do, although it will, of course, work much, much more slowly.

Extended Turing Machines

We can, however, look briefly at some other models of computation and see how they compare with Turing machines. For example, there are various ways in which we might try to increase the power of a Turing machine. For example, consider a two-tape Turing machine that has two tapes, with a read/write head on each tape. In each step of its computation, a two-tape Turing machine reads the symbols under its read/write heads on both tapes. Based on these symbols and on its current state, it can write a new symbol onto each tape, independently move the read/write head on each tape one cell to the left or right, and change state.

It might seem that with two tapes available, two-tape Turing machines might be able to do computations that are impossible for ordinary one-tape machines. In fact, though, this is not the case. The reason, again, is simulation: Given any two-tape Turing machine, it is possible to build a one-tape Turing machine that simulates the step-by-step computation of the two-tape machine. Let MM be a two-tape Turing machine. To simulate MM with a one-tape machine, KK, we must store the contents of both of MM's tapes on one tape, and we must keep track of the positions of both of MM's read/write heads. Let @ and $ be symbols that are not in the alphabet of MM. The @ will be used to mark the position of a read/write head, and the $ will be used to delimit the parts of KK's tape that represent the two tapes of MM. For example, suppose that one of MM's tapes contains the symbols "abb##cca" with the read/write head on the first b, and that the other tape contains "01#111#001" with the read/write head on the final 1. This configuration would be represented on KK's tape as "$a@bb##cca$01#111#00@1$". To simulate one step of MM's computation, KK must scan its entire tape, looking for the @'s and noting the symbol to the right of each @. Based on this information, KK can update its tape and its own state to reflect MM's new configuration after one step of computation. Obviously, KK will take more steps than MM and it will operate much more slowly, but this argument makes it clear that one-tape Turing machines can do anything that can be done by two-tape machines.

We needn't stop there. We can imagine nn-tape Turing machines, for n>2n>2. We might allow a Turing machine to have multiple read/write heads that move independently on each tape. We could even allow two or three-dimensional tapes. None of this makes any difference as far as computational power goes, since each type of Turing machine can simulate any of the other types.1

Recursively Enumerable Languages

We have used Turing machines to define Turing-acceptable languages and Turing-decidable languages. The definitions seem to depend very much on the peculiarities of Turing machines. But the same classes of languages can be defined in other ways. For example, we could use programs running on an idealized computer, with an unlimited amount of memory, to accept or decide languages. Or we could use nn-tape Turing machines. The resulting classes of languages would be exactly the same as the Turing-acceptable and Turing-decidable languages.

We could look at other ways of specifying languages "computationally." One of the most natural is to imagine a Turing machine or computer program that runs forever and outputs an infinite list of strings over some alphabet Σ\Sigma. In the case of Turing machines, it's convenient to think of a two-tape Turing machine that lists the strings on its second tape. The strings in the list form a language over Σ\Sigma. A language that can be listed in this way is said to be recursively enumerable. Note that we make no assumption that the strings must be listed in any particular order, and we allow the same string to appear in the output any number of times. Clearly, a recursively enumerable language is "computable" in some sense. Perhaps we have found a new type of computable language. But noit turns out that we have just found another way of describing the Turing-acceptable languages. The following theorem makes this fact official and adds one more way of describing the same class of languages:

Theorem: Let Σ\Sigma be an alphabet and let LL be a language over Σ\Sigma. Then the following are equivalent:

  • There is a Turing machine that accepts LL.
  • There is a two-tape Turing machine that runs forever, making a list of strings on its second tape, such that a string ww is in the list if and only if wLw\in L.
  • There is a Turing-computable function f ⁣:{a}Σf\colon\{a\}^*\to\Sigma^* such that LL is the range of the function ff.

While I will not give a complete, formal proof of this theorem, it's not too hard to see why it is true. Consider a language that satisfies the third property. We can use the fact that LL is the range of a Turing-computable function, ff, to build a two-tape Turing machine that lists LL. The machine will consider each of the strings ana^n, for nNn\in \N, in turn, and it will compute f(an)f(a^n) for each nn. Once the value of f(an)f(a^n) has been computed, it can be copied onto the machine's second tape, and the machine can move on to do the same with an+1a^{n+1}. This machine writes all the elements of LL (the range of ff) onto its second tape, so LL satisfies the second property. Conversely, suppose that there is a two-tape Turing machine, MM, that lists LL. Define a function g ⁣:{a}Σg\colon\{a\}^*\to\Sigma^* such that for nNn\in\N, g(an)g(a^n) is the (n+1)th(n+1)^{th} item in the list produced by MM. Then the range of gg is LL, and gg is Turing-computable since it can be computed as follows: On input ana^n, simulate the computation of MM until it has produced n+1n+1 strings, then halt, giving the (n+1)th(n+1)^{th} string as output. This shows that the second property implies the third property, so these properties are in fact equivalent.

We can also check that the second property is equivalent to the first. Suppose that LL satisfies the second property. Consider a two-tape Turing machine, TT, that lists the elements of LL. We must build a Turing machine, MM, which accepts LL. We do this as follows: Given an input wΣw\in\Sigma^*, MM will simulate the computation of TT. Every time the simulated TT produces a string in the list, MM compares that string to ww. If they are the same, MM halts. If wLw\in L, eventually it will be produced by TT, so MM will eventually halt. If w∉Lw\not\in L, then it will never turn up in the list produced by TT, so MM will never halt. Thus, MM accepts the language LL. This shows that the second property implies the first one.

The fact that the first property implies the second is somewhat harder to see. First, we note that it is possible for a Turing machine to generate every possible string in Σ\Sigma^*, one-by-one, in some definite order (such as order of increasing length, with something like alphabetical order for strings of the same length). Now, suppose that LL is Turing-acceptable and that MM is a Turing machine that accepts LL. We need a two-tape Turing machine, TT that makes a list of all the elements of LL. Unfortunately, the following idea does not work: Generate each of the elements in Σ\Sigma^* in turn, and see whether MM accepts it. If so, then add it to the list on the second tape. It looks like we have a machine that lists all the elements of LL. The problem is that the only way for TT to "see whether MM accepts" a string is to simulate the computation of MM. Unfortunately, as soon as we try this for any string ww that is not in LL, the computation never ends! TT will get stuck in the simulation and will never even move on to the next string. To avoid this problem, TT must simulate multiple computations of MM at the same time. TT can keep track of these computations in different regions of its first tape (separated by $'s). Let the list of all strings in Σ\Sigma^* be x1x_1, x2x_2, x3x_3, . Then TT should operate as follows:

  • 1: Set up the simulation of MM on input x1x_1, and simulate one step of the computation for x1x_1

  • 2: Set up the simulation of MM on input x2x_2, and simulate one step of the computation for x1x_1 and one step of the computation for x2x_2.

  • 3: Set up the simulation of MM on input x3x_3, and simulate one step of each of the computations, for x1x_1, x2x_2, and x3x_3.

  • n: Set up the simulation of MM on input xnx_n, and simulate one step of each of the computations, for x1x_1, x2x_2, \dots, xnx_n.

and so on. Each time one of the computations halts, TT should write the corresponding xix_i onto its second tape. Over the course of time, TT simulates the computation of MM for each input wΣw\in\Sigma^* for an arbitrary number of steps. If wLw\in L, the simulated computation for ww will eventually end and it will appear on TT's second tape. On the other hand, if w∉Lw\not\in L, then the simulated computation will never end, so ww will not appear in the list. So we see that TT does in fact make a list of all the elements, and only the elements of LL. This completes an outline of the proof of the theorem.

General Grammars

Next, we compare Turing machines to a completely different method of specifying languages: general grammars. Suppose G=(V,Σ,P,S)G=(V,\Sigma,P,S) is a general grammar and that LL is the language generated by GG. Then there is a Turing machine, MM, that accepts the same language, LL. The alphabet for MM will be VΣ{$,#}V\cup\Sigma\cup\{\$,\#\}, where $ is a symbol that is not in VΣV\cup\Sigma. (We also assume that # is not in VΣV\cup\Sigma.) Suppose that MM is started with input ww, where wΣw\in\Sigma^*. We have to design MM so that it will halt if and only if wLw\in L. The idea is to have MM find each string that can be derived from the start symbol SS. The strings will be written to MM's tape and separated by $'s. MM can begin by writing the start symbol, SS, on its tape, separated from ww by a $. Then it repeats the following process indefinitely: For each string on the tape and for each production rule, xyx\longrightarrow y, of GG, search the string for occurrences of xx. When one is found, add a $ to the end of the tape and copy the string to the end of the tape, replacing the occurrence of xx by yy. The new string represents the results of applying the production rule xyx\longrightarrow y to the string. Each time MM produces a new string, it compares that string to ww. If they are equal, then MM halts. If ww is in fact in LL, then eventually MM will produce the string ww and will halt. Conversely, if ww is not in LL, then MM will go on producing strings forever without ever finding ww, so MM will never halt. This shows that, in fact, the language LL is accepted by MM.

Conversely, suppose that LL is a language over an alphabet Σ\Sigma, and that LL is Turing-acceptable. Then it is possible to find a grammar GG that generates LL. To do this, it's convenient to use the fact that, as discussed above, there is a Turing-computable function f ⁣:{a}Σf\colon \{a\}^*\to\Sigma such that LL is the range of ff. Let M=(Q,Λ,q0,δ)M=(Q,\Lambda,q_0,\delta) be a Turing machine that computes the function ff. We can build a grammar, GG, that imitates the computations performed by MM. The idea is that most of the production rules of GG will imitate steps in the computation of MM. Some additional rules are added to get things started, to clean up, and to otherwise bridge the conceptual gap between grammars and Turing machines.

The terminal symbols of GG will be the symbols from the alphabet, Σ\Sigma. For the non-terminal symbols, we use: the states of MM, every member of Λ\Lambda that is not in Σ\Sigma, two special symbols << and >>, and two additional symbols SS and AA. (We can assume that all these symbols are distinct.) SS will be the start symbol of GG. As for production rules, we begin with the following three rules:

S<q0A>AaAAε\begin{aligned} S&\longrightarrow <q_0A>\\ A&\longrightarrow aA\\ A&\longrightarrow\varepsilon \end{aligned}

These rules make it possible to produce any string of the form <q0an><q_0a^n>. This is the only role that SS and AA play in the grammar. Once we've gotten rid of SS and AA, strings of the remaining terminal and non-terminal symbols represent configurations of the Turing machine MM. The string will contain exactly one of the states of MM (which is, remember, one of the non-terminal symbols of GG). This tells us which state MM is in. The position of the state-symbol tells us where MM is positioned on the tape: the state-symbol is located in the string to the left of the symbol on which MM is positioned. And the special symbols << and >> just represent the beginning and the end of a portion of the tape of MM. So, the initial string <q0an><q_0a^n> represents a configuration in which MM is in its start state, and is positioned on the first aa in a string of nn aa's. This is the starting configuration of MM when it is run with input ana^n.

Now, we need some production rules that will allow the grammar to simulate the computations performed by MM. For each state qiq_i and each symbol σΛ\sigma\in\Lambda, we need a production rule that imitates the transition rule δ(qi,σ)=(τ,d,qj)\delta(q_i,\sigma) =(\tau,d,q_j). If d=Rd=R, that is if the machine moves to the right, then all we need is the rule

qiστqj\begin{aligned} q_i\sigma&\longrightarrow \tau q_j \end{aligned}

This represents that fact that MM converts the σ\sigma to a τ\tau, moves to the right, and changes to state qjq_j. If d=Ld=L, that is if the machine moves to the left, then we will need several rulesone rule for each λΛ\lambda\in\Lambda, namely

λqiσqjλτ\begin{aligned} \lambda q_i\sigma&\longrightarrow q_j\lambda\tau \end{aligned}

This rule says that MM changes the σ\sigma to a τ\tau, moves left, and changes to state qjq_j. The λ\lambda doesn't affect the application of the rule, but is necessary to represent the fact that MM moves left.

Each application of one of these rules represents one step in the computation of MM. There is one remaining requirement for correctly simulating MM. Since MM's tape contains an infinite number of cells and we are only representing a finite portion of that tape, we need a way to add and remove #'s at the ends of the string. We can use the following four rules to do this:

<<#<#<>#>#>>\begin{aligned} <&\longrightarrow <\#\\ <\#&\longrightarrow <\\ >&\longrightarrow \#>\\ \#>&\longrightarrow > \end{aligned}

These rules allow blank symbols to appear at the ends of the string when they are needed to continue the computation, and to disappear from the ends of the string whenever we like.

Now, suppose that ww is some element of LL. Then w=f(an)w=f(a^n) for some nNn\in\N. We know that on input ana^n, MM halts with output ww. If we translate the computation of MM into the corresponding sequence of production rules in GG, we see that for the grammar GG, <q0an><hw><q_0a^n>\Longrightarrow^*<hw>, where hh is the halt state of MM. Since we already know that S<q0an>S\Longrightarrow^*<q_0a^n>, for every nNn\in\N, we see that in fact S<hw>S\Longrightarrow^*<hw> for each wLw\in L. We almost have it! We want to show that SwS\Longrightarrow^*w. If we can just get rid of the <<, the hh, and the >>, we will have that <hw>w<hw>\Longrightarrow^*w and we can then deduce that SwS\Longrightarrow^*w for each wLw\in L, as desired. We can do this by adding just a few more rules to GG. We want to let the hh eliminate the <<, move through the ww, and then eliminate the >> along with itself. We need the rules

<hhh>ε\begin{aligned} <h&\longrightarrow h\\ h>&\longrightarrow \varepsilon \end{aligned}

and, for each σΣ\sigma\in\Sigma,

hσσh\begin{aligned} h\sigma&\longrightarrow \sigma h \end{aligned}

We have constructed GG so that it generates every string in LL. It is not difficult to see that the strings in LL are in fact the only strings that are generated by GG. That is, LL is precisely L(G)L(G).

We have now shown, somewhat informally, that a language LL is Turing-acceptable if and only if there is a grammar GG that generates LL. Even though Turing machines and grammars are very different things, they are equivalent in terms of their ability to describe languages. We state this as a theorem:

Theorem: A language LL is Turing acceptable (equivalently, recursively enumerable) if and only if there is a general grammar that generates LL.

Turing Decidability

In this section, we have been talking mostly about recursively enumerable languages (also known as the Turing-acceptable languages). What about the Turing-decidable languages? We already know that if a language LL is Turing-decidable, then it is Turing-acceptable. The converse is not true (although we won't be able to prove this until the next section). However, suppose that LL is a language over the alphabet Σ\Sigma and that both LL and its complement, L=ΣL\overline{L}=\Sigma^*\smallsetminus L, are Turing-acceptable. Then LL is Turing-decidable.

For suppose that MM is a Turing machine that accepts the language LL and that MM' is a Turing machine that accepts L\overline{L}. We must show that LL is Turing-decidable. That is, we have to build a Turing machine TT that decides LL. For each wΣw\in\Sigma^*, when TT is run with input ww, it should halt with output 1 if wLw\in L and with output 00 if w∉Lw\not\in L. To do this, TT will simulate the computation of both MM and MM' on input ww. (It will simulate one step in the computation of MM, then one step in the computation of MM', then one step of MM, then one step of MM', and so on.) If and when the simulated computation of MM halts, then TT will halt with output 1; since MM accepts LL, this will happen if and only if wLw\in L. If and when the simulated computation of MM' halts, then TT will halt with output 0; since MM accepts LL, this will happen if and only if w∉Lw\not\in L. So, for any wΣw\in\Sigma^*, TT halts with the desired output. This means that TT does in fact decide the language LL.

It is easy to prove the converse, and the proof is left as an exercise. So we see that a language is Turing-decidable if and only if both it and its complement are Turing-acceptable. Since Turing-acceptability can be defined using other forms of computation besides Turing machines, so can Turing-decidability. For example, a language is Turing-decidable if and only if both it and its complement can be generated by general grammars. We introduced the term "recursively enumerable" as a synonym for Turing-acceptable, to get away from the association with a particular form of computation. Similarly, we define the term "recursive" as a synonym for Turing-decidable. That is, a language LL is said to be recursive if and only if it is Turing-decidable. We then have the theorem:

Theorem: Let Σ\Sigma be an alphabet and let LL be a language over Σ\Sigma. Then LL is recursive if and only if both LL and its complement, ΣL\Sigma^*\smallsetminus L, are recursively enumerable.

Exercises

  1. The language L={am    m>0}L=\{a^m\;|\; m>0\} is the range of the function f(an)=an+1f(a^n)=a^{n+1}. Design a Turing machine that computes this function, and find the grammar that generates the language LL by imitating the computation of that machine.

  2. Complete the proof of the above theorem by proving the following: If LL is a recursive language over an alphabet Σ\Sigma, then both LL and ΣL\Sigma^*\smallsetminus L are recursively enumerable.

  3. Show that a language LL over an alphabet Σ\Sigma is recursive if and only if there are grammars GG and HH such that the language generated by GG is LL and the language generated by HH is ΣL\Sigma^*\smallsetminus L.

  4. This section discusses recursive languages and recursively enumerable languages. How could one define recursive subsets of N\N and recursively enumerable subsets of N\N?

  5. Give an informal argument to show that a subset XNX\subseteq\N is recursive if and only if there is a computer program that prints out the elements of XX in increasing order.


  1. We can also define non-deterministic Turing machines that can have several possible actions at each step. Non-deterministic Turing machines cannot be used to compute functions, since a function can have only one possible output for any given input. However, they can be used to accept languages. We say that a non-deterministic Turing machine accepts a language LL is it is possible for the machine to halt on input ww if and only if wLw\in L. The class of languages accepted by non-deterministic Turing machines is the same as the class of languages accepted by deterministic Turing machines. So, non-determinism does not add any computational power.