CSE596 Problem Set 5 Answer Key Fall 2015

Problem Set 5 Answer Key
Fall 2015
(A) A program verification system . . . gives us a program Q—itself total—such that if Q
accepts a program P , then P is total. The limitation—but which also enables Q to be real
code—is that we don’t always get the converse: Q is allowed to reject some programs that
really are total. In general terms, Q is allowed to give false negatives but not false positives.
. . . [A]lso the following program P is real code—not “paradoxical”:
bool P(string z) {
if (z fails to compile to a valid program M) { reject; }
//else we have M
if (Q rejects z) { reject; }
//now we know M is total
if (M accepts z) { reject; } else { accept; }
This program P is total—crucially because Q is total and Q never gives a false positive.
We humans can see that. The question is, can our verification system “see” it? Take p to be
the code of P and q to be the code of Q: so p compiles to P and q compiles to Q. (If you like
the e(·) function, p = e(P ) and q = e(Q).)
(a) Show that Q cannot accept p.
(b) What actually happens when P is run on input p?
(c) If Q accepts q, does that cause a contradiction when P is run on q?
Answer: (a) Two answers were fine: (i) If Q accepts p and we suppose the third line is
executed to completion (based on our saying P is total) when P is run on input p, then we
get the diagonal contradiction from P : P accepts p ⇐⇒ P rejects p. (ii) What actually
would happen if Q accepted p is that, since “M ” is literally P itself in the third line, P when
run on p would invoke itself on input p in that line. This causes an infinite recursion, which
formally means not halting (in practice it would “segfault” with a stack overflow). But that in
turn contradicts P being total and the given assumption that Q gives no false positives—since
now “Q(p) accepts” is a false positive. Either way, something’s gotta give—you can have the
assumptions of the problem but not with Q accepting p.
(b) Since Q, being total, must reject p by (a), P (p) rejects in that same second line.
(c) If Q accepts q, then P on input q runs Q(q) and gives the opposite answer. That’s fine
because it’s P (q) versus Q(q); it just means that P and Q cannot accept the same language.
In jargon terms, it means “P is diagonal for Q.” Actually it’s the language L(P ) of P that is
diagonal for Q, which takes us into the for-credit problem.
(1) Show that Q cannot accept the code of any program M such that L(M ) = L(P ). (12
Answer: Suppose there were such a program M —since we are thinking of a specific one
now we can more helpfully call it P 0 since it is “like P .” Take p0 to stand for the code of
P 0 —then we are supposing that Q accepts p0 and L(P 0 ) = L(P ). We produce a contradiction
as follows: Run P on p0 . Then in the first step it compiles p0 to get a working copy of P 0 and
in the second step Q accepts p0 —which means P 0 is total by the assumption about Q. So the
third step runs to completion. We get:
P accepts p0
P 0 rejects p0
P rejects p’
(by third step)
(by L(P 0 ) = L(P )).
This is our old friend (or “fiend”) the diagonal contradiction, which completes the proof.
Remarks: Notice that the contradiction comes about because of the assumption that
languages are equal—so p0 ∈ L(P 0 ) ⇐⇒ p0 ∈ L(P ), so P 0 accepts p0 ⇐⇒ P accepts p0 .
It does not rely on any idea that P 0 must work like P does—assuming the program P 0 must
work like P is another issue of “intension vs. extension.” It comes down to the particular
language—call it just L now—that P accepts. The jargon term here is that L is diagonal for
Q. The language not just the program is diagonal.
The upshot is that Q not only cannot accept the code of P , it cannot accept the code of
any program that recognizes L. This is so even though L is a decidable language—since there
really are cases where programs like Q exist and are practically relevant, and then P really
exists as above and is total. The ulterior motives for this topic are:
• Any formal system F of logic that can analyze computations (technically the bar is
very low: F only needs to express and prove some basic identities of arithmetic and
induction on N) can give you a program verification system Q without false positives.
But then the statements “P is total” and “some total program P 0 accepts L” are true
but unprovable in F . This is a neat way to appreciate Gòˆdel’s Theorem that for
every consistent formal system with implementable proofs there are true statements
that the system cannot prove. This is not on the course syllabus but is important to
the intellectual context of the course.
• When we hit Section 5.5 of the text we will see a diagonalization technique where the
fact that it applies to all programs for a diagonal language is essential. There will be
an extra component that will allow us to “morph” the diagonal language so that it fits
inside a slightly-higher complexity class. If you get this first, that—which is central to
the second-half syllabus—will be easier to follow.
(2) Consider the triad of problems you get from the program behavior that a single-tape
Turing machine M overwrites a non-blank character by the blank B. (A basic fact you need to
know is that Turing machines can always be programmed to treat a char like ‘%’ as a “virtual
blank” and avoid writing the actual blank B, unless. . . ) Stated as decision problems, their
questions are:
1. Given M and x, does M (x) ever overwrite a non-blank char by B?
2. Given M , is there some x such that M (x) does that behavior?
3. Given M , does M (x) do that behavior for all x?
State the languages L1 , L2 , L3 of these problems using set notation, and then prove that all
three languages are undecidable. (39 pts. total, for 51 on the set)
Answer: To help visualize, I will use M 0 rather than M for the “dummy variable” in these
sets. (For L1 I could also “dummy” x0 instead of x, but since it’s the same x the visual help
is not so important.) There is nothing wrong with using “M ” for them though.
L1 = {hM 0 , xi : M 0 (x) overwrites a non-blank char by B}
L2 = {e(M 0 ) : for some x, M 0 (x) overwrites a non-blank char by B}
L3 = {e(M 0 ) : for all x, M 0 (x) overwrites a non-blank char by B}
Now to prove that these languages are undecidable, it suffices to reduce the Acceptance
Problem (or essentially equivalently the Halting Problem) to each of them. Given an instance
hM, xi of the APT M problem, we kill all three birds with one stone by defining a particular
Turing machine M 0 that operates as follows:
M 0 : On any input w, M 0 (w) first (writes down x on another tape or next to w on the
input tape, whatever—you don’t need to say this) starts up a simulation of M on input x.
Importantly, the simulation of M (x) operates without ever writing a literal blank—it can
use a special char ‘%’ (that is not used by any TM in the formalized instances of APT M ) as a
“virtual blank.” If and when M accepts x, M 0 (w) then proudly writes a literal blank B over
a non-blank char.
It is easy to stitch a given M and x into the code for M 0 , so the functions f1 (M, x) = hM, xi
and f2 (M, x) = e(M 0 ) are computable. We get this analysis:
hM, xi ∈ APT M
M accepts x
M 0 (x) overwrites a non-blank char by B
hM 0 , xi ∈ L1
f1 (M, x) ∈ L1
(so APT M ≤m L1 )
(∃w)M (w) overwrites a non-blank char by B
e(M 0 ) ∈ L2
f2 (M, x) ∈ L2
(so APT M ≤m L2 ).
Finally, by the logic of the “all-or-nothing-switch,” the same function f2 also many-one
reduces APT M to L3 , because
hM, xi ∈ APT M
M accepts x
(∃w)M 0 (w) overwrites a non-blank char by B
(∀w)M 0 (w) overwrites a non-blank char by B
f2 (M, x) ∈ L3
(so APT M ≤m L3 ).