Recall the terminology for TM computation:
A language \(A\) is called Turing-recognizable (or Turing-acceptable, recursively enumerable, or
computably enumerable) if some Turing machine \(M\) recognizes it (\(L(M) = A\)).
A language \(A\) is called Turing-decidable if there is a total Turing machine \(M\) (a decider) such that \(L(M) = A\). In other words \(M\) accepts all \(w \in A\) and rejects all \(w \notin A\).
def halt_recognizer(M, w):
"""
M: a Python function
(stand-in for a Turing machine)
w: an input string
"""
M(w)
return True
def M1(w):
count = 0
for c in w:
if c == 'a':
count += 1
return count > 5
w = 'abcabcaaabcaa'
halt_recognizer(M1, w) # returns True
def M2(w):
i = 0
while i < len(w):
if w[i] != 'c':
i += 1
return w
w = 'abcabcaaabcaa'
halt_recognizer(M2, w) # never returns...
Theorem (Turing): \(\probHALT\) is not decidable.
Once we prove this, we can use Turing reductions to show that many other problems are also undecidable.
Simple example of a Turing reduction:
showing that the no-input Halting problem is undecidable
\[ \probHALT_\emptystring = \setbuild{\encoding{M}}{M \text{ is a Turing machine and } M(\emptystring)} \]
\(\probHALT_\emptystring\) is obviously reducible to \(\probHALT\) since it is just a special case!
We could decide if \(\encoding{M} \in \probHALT_\emptystring\) by checking if \(\encoding{M, \emptystring} \in \probHALT\).
But \(\probHALT_\emptystring\) could easierโฆ
Simple example of a Turing reduction:
showing that the no-input Halting problem is undecidable
\[ \probHALT_\emptystring = \setbuild{\encoding{M}}{M \text{ is a Turing machine and } M(\emptystring) halts} \]
Theorem: \(\probHALT_\emptystring\) is undecidable.
Proof:
Suppose that \(\probHALT_\emptystring\) is decidable by an algorithm:
from typing import Callable
def H_๐(M: Callable[[str], bool]) -> bool: raise NotImplementedError()
We can use this to decide \(\probHALT\) as follows:
def H(M: Callable[[str], bool], w: str) -> bool:
# Create a new algorithm T_Mw that ignores its input
# and has the original input w "hardcoded".
def T_Mw(x: str) -> bool: # This is algorithm is never actually run!!!
M(w) # Executing these lines merely *defines* T_Mw.
return H_๐(T_Mw) # ... but instead is *analyzed* by H_๐.
M(w) halts, then:
T_Mw halts on every input (including \(\emptystring\)).H_๐(T_Mw)returns True.M(w) loops (doesnโt halt), then:
T_Mw loops on every input (including \(\emptystring\)).H_๐(T_Mw) returns False.H decides \(\probHALT\), a contradiction.