17.7. Finding Counterexamples


Counterexamples

Most of what we did this term has been concerned with demonstrating that a problem is not in a particular class of problems.

To show that problem X is not solvable by an algorithm of type T, we can design an algorithm that solves the following problem.

Input. A program or machine M of type T.

Output. A string y on which M gets the wrong answer. That is, if yX then M says that yX, and if yX then M says that yX.

String y is a counterexample for M.

Since our algorithm finds a counterexample for every program or machine of type T, no such program or machine can solve X.


Finite-state

To show that a given set X of strings cannot be solved by a finite-state machine, the counterexample-finding algorithm relies on a selected infinite list of strings y1, y2, … The choice of this list is part of algorithm discovery.

Then the algorithm works as follows on input M.

  1. Run M on y1, y2, … until two of them, yi and yj are found so that M ends on the same state, q, on both.

    Such strings must exist because M has finitely many states. If M has k states, then it cannot end of a different state on all of y1, y2, … yk+1.

  2. Find a third string s so that yisX but yjsX. List y1, y2, … should be very simple so that finding s is easy.

  3. Conclude that, because M ends on the same state on yi and yj, M must also end on the same state on yis and yjs.

    Since M 's answer depends only on the state where it ends, M must give the same answer on yis and yjs.

    But the correct answers to yis and yjs are different. So one of yis and yjs is a counterexample. Choose the one that M gets wrong.

See this example.

You should be prepared to demonstrate that a given language (set of strings) cannot be solved by any finite-state machine.


Diagonalization

To show that a given problem is not computable by a (deterministic) Turing machine, we need a more powerful way to find a counterexample. We did that for the acceptance problem for Turing machines, using a method called diagonalization.

The idea of diagonalization is at its simplest for showing that K = {x | φx(x)↓} is not computable.

On input M (a program that is purported to solve K ), find a counterexample as follows.

  1. Construct program F so that, for every x,

    φF (x)↑ ⇔ φM (x) = yes.
  2. Since that equivalence is true for every x, it must be true for x = F. That is,

    φF (F)↑ ⇔ φM (F) = yes.

    But, by the definition of K,

    φF (F)↑ ⇔ FK.

    Putting those two equivalences together:

    FK ⇔ φM (F) = yes.
  3. The counterexample is F; clearly, M gives the wrong answer about membership in K on input F.

I will not ask you to do a proof by diagonalization.