We conclude the discussion of undecidability with a few more examples of languages that one might not expect to be undecidable.
The configuration of a Turing Machine at some point of time consists of the the content of the tape, the position of the head on that tape, and the state of the DFA.
We can represent any configuration of a TM using a string where
The infinite blank part of the tape to the left of and the right of is left implicit.
Even though the tape is infinite, at any instant during a computation there are only finitely many non-blank symbols on the tape. The TM starts with a tape that is blank except for the finite input string, and after finitely many steps the TM can have written to only finitely many squares on the tape.
A Computation History is a step-by-step (finite) trace of a Turing Machine’s computation, represented as a string.
For example if a TM takes threes step through the successive configurations
then we can represent this history as a finite string:
A history checker for accepting is a Turing Machine that takes an input string checks whether is a valid computation history showing accepting
Such a machine always exists for any and any ; it just needs to check whether
Note that a history checker for accepting always exists whether or not accepts ! If accepts then there is a history showing the trace of that computation, and this string will be accepted by the history checker. But if does not accept , there is no such finite trace. As a consequence, any purported trace we give to the history checker will be found to be flawed, and the history checker won’t accept any strings at all.
This observation immediately gives us a different way to prove a known fact:
Here’s another proof that is not semidecidable.
Proof. We will show that .
Let be the function that turns into the code of a history checker for accepting .
The idea of computation histories lets us prove surprising facts about context-free languages.
While it is easy to decide whether a context-free grammar generates any strings at all (whether its language is nonempty), it is undecidable whether a context-free grammar can generate all possible strings!
That is, the language
is not decidable.
Proof Sketch. One can show that .
The fundamental trick is that given , the strings that are not valid computation histories are (with one small hack) context-free.
So asking whether fails to accept is equivalent to asking whether all strings are not valid histories showing accept , which in turn is equivalent to asking whether the language of CFG generating strings that are not valid histories includes all possible strings.
To see why strings that are not valid computation histories are context-free, it is a little easier to think about PDAs rather than grammars. A trace is not a valid history of accepting if it has at least one error, such as:
We can find each sort of error using a PDA, and then can create one “super” PDA that nondeterministically chooses which kind of error to look for (and in the case of consecutive configurations, nondeterministically choose where in the string to find those configurations). If an error exists, the nondeterministic PDA is guaranteed to find it. (And if a PDA exists, then there is a corresponding CFG.)
It is not even semidecidable whether two CFGs parse the same strings (i.e., produce the same language). That is,
is not decidable and not semidecidable.
Proof. We can show that using a mapping that sends to the pair where is a context-free grammar specifically constructed to generate all strings in .