For any two sets \(A\) and \(B\), we say that \(|A| \ge |B|\) if and only if there exists an onto function \(f: A \to B\).
It turns out that a power set of a set is always strictly larger than the original set:
Theorem: Let \(X\) be any set. Then there is no onto function \(f: X \to \powerset(X)\).
Proof:
Assume for contradiction an onto function \(f\) exists.
Thus, for each well defined subset of \(X\), \(f\) must map at least one element of \(X\) to it.
Consider the subset: \[ D = \setbuild{a \in X}{a \notin f(a)} \]
This is weird/tricky to parse but it’s well defined!
Let \(k \in X\) be an element such that \(f(k) = D\).
Now, we have two cases:
Therefore, \(f\) cannot be onto!
0 | 1 | 2 | 3 | \(\cdots\) | k | |
---|---|---|---|---|---|---|
\(f(0) = \{1, 3, \ldots\}\)
Each cell value indicates whether the “column element” is in the set. |
0 | 1 | 0 | 1 | \(\cdots\) | |
\(f(1) = \{0, 1, 2, 3 \ldots\}\) | 1 | 1 | 1 | 1 | \(\cdots\) | |
\(f(2) = \{2, \ldots\}\) | 0 | 0 | 1 | 0 | \(\cdots\) | |
\(f(3) = \{0, 2, \ldots\}\) | 1 | 0 | 1 | 0 | \(\cdots\) | |
|
\(\ddots\) | |||||
\(f(k) = D\)
Row \(k\) (corresponding to \(D\)) is constructed by taking each diagonal element and flipping it! |
1 | 0 | 0 | 1 | \(\cdots\) |
??
Assigning a value to \((k, k)\) using this rule is impossible! |
We can also claim \(D\) can’t be on this table since it differs from every row.
A set \(X\) is countable if \(|X| \le |\N|\). There are two possible cases:
A set \(X\) is uncountable if \(|X| > |\N|\).
In other words: a set is countable if it can be listed, \[ X = \{x_0, x_1, x_2, \ldots\} \] so that any given element can be found at some finite index \(n\).
This listing implicitly defines an onto function \(f: \N \to X\).
Observation: \(\powerset(\N)\) is uncountable.
Finally getting back to computation:
Observation: There exist undecidable languages \(L \subseteq \binary^*\).
Proof:
But we still haven’t proved any specific language to be undecidable!
We are finally ready for Turing’s diagonalization argument proving the undecidability of:
\[ \probHALT = \setbuild{\encoding{M, w}}{M \text{ is a Turing machine that halts on } w} \]
Theorem: \(\probHALT\) is undecidable.
Proof:
Assume for contradiction that \(\probHALT\) is decidable by the algorithm:
def H(M, w): raise NotImplementedError()
Define the following algorithm (analogous to the set \(D\) we constructed earlier):
def D(M):
M_src = inspect.getsource(M)
if H(M, M_src):
while True: pass # Loop forever
else:
return # Halt
D
loops if TM \(M\) halts on \(\encoding{M}\) (if \(\encoding{M, \encoding{M}} \in \probHALT\)),
and halts if TM \(M\) loops on \(\encoding{M}\) (if \(\encoding{M, \encoding{M}} \notin \probHALT\)).
Theorem: \(\probHALT\) is undecidable.
Proof:
Assume for contradiction that \(\probHALT\) is decidable by the algorithm:
def H(M, w): raise NotImplementedError()
Define the following algorithm (analogous to the set \(D\) we constructed earlier):
def D(M):
if H(M, inspect.getsource(M)):
while True: pass # Loop forever
else: return # Halt
D
loops if TM \(M\) halts on \(\encoding{M}\) (if \(\encoding{M, \encoding{M}} \in \probHALT\)),
and halts if TM \(M\) loops on \(\encoding{M}\) (if \(\encoding{M, \encoding{M}} \notin \probHALT\)).
D(D)
do?
D
halts on itself, then H(D, D_src)
returns True
, so D
loops forever (a contradiction!).D
loops on itself, then H(D, D_src)
returns False
, so D
halts (a contradiction!).H
must not exist, so \(\probHALT\) is undecidable!def D(M):
if H(M, inspect.getsource(M)):
while True: pass # Loop forever
else: return # Halt
Expressing the previous argument in Turing machine notation:
\[\begin{align*} D \text{ halts on }& \encoding{D} \\ &\iff H \text{ accepts }\encoding{D, \encoding{D}} \quad \quad \color{green} (\text{Since } H \text{ solves }\probHALT) \\ &\iff D \text { loops on } \encoding{D} \quad \quad \quad \; \; \, \color{green} (\text{Implementation of } D) \end{align*}\]
This argument doesn’t just show \(H\) can’t analyze this weird algorithm \(D\).
It shows \(H\) itself cannot exist!
Let’s consider the (countable) set of all Turing machines and try running each on
strings that encode Turing machines.
These inputs probably don’t make sense, but the TMs will nonetheless either loop or halt.
We can organize the results in a table:
\(\encoding{M_0}\) | \(\encoding{M_1}\) | \(\encoding{M_2}\) | \(\encoding{M_3}\) | \(\cdots\) | \(\encoding{D}\) | |
---|---|---|---|---|---|---|
\(M_0\) | loop | halt | loop | halt | \(\cdots\) | |
\(M_1\) | halt | halt | halt | halt | \(\cdots\) | |
\(M_2\) | loop | loop | halt | loop | \(\cdots\) | |
\(M_3\) | halt | loop | halt | loop | \(\cdots\) | |
\(\;\,\vdots\) | \(\ddots\) | |||||
\(D\) | halt | loop | loop | halt | \(\cdots\) | ?? |
The row for machine \(D\) is constructed by taking each diagonal result and flipping it!
Assigning a value to \((D, \encoding{D})\) using this rule is impossible!