Step 1: Go through the instance of CNFSAT and list each Boolean variable used in the expression. (O(n

Step 2: Loop through the list of variables, and for each one ask the "CHOICE" function whether it should be true or false. Write down whether it should be true or false along with the variable. (O(n

Step 3: Replace each instance of a variable in the CNFSAT instance with the true or false value you have created. (O(n

Step 4: Go through the CNFSAT expression and make sure every sum contains at least one true. (O(n

If Step 4 verifies that every sum contains at least one true in each sum then the instance is satisfiable. If not, it is not since the "CHOICE" would have given a correct value to satisfy the expression if the expression could be satisfied.

From CSCI 150, we know that all operations on a computer can be reduced to multiple AND, OR, and NOT operations together with LOAD/STORE operations, conditional jumps, and a clock to move from one instruction to the next. We are going to show how to implement AND, OR, NOT, "CHOICE" calls, conditional jumps, and a clock and conclude that since the algorithm can be implemented in this "low-level" way that the program can be translated into an instance of CNFSAT.

Here is how we do it:

We translate a given nondeterministic program into a logical expression describing the complete execution of the program.

First, our transformed program will need a concept of time (corresponding to the system clock), memory (in our case 1-bit addressable memory), and, of course, the transformed program.

Let us suppose to start that we have L instructions in the nondeterministic program. Let p(n) be a polynomial and let n be the length of an instance of the problem. Suppose p(n) is a polynomial that is "big enough" that the nondeterministic program will solve an instance of this problem of size n in time <=p(n) if the instance should return true. (Remember, we are just doing decision problems - problems that return true or false.)

Our "clock", then, is just a variable t representing time that "runs" for as long as the problem needs to run to get an answer.

Since the program finishes in less than p(n) time, we will only let the variable t run from 0 to p(n). If t becomes larger than p(n) we will assume the instance could not return true so it will return false. In addition, there is the interesting fact that if the program runs in less than p(n) time, it cannot possibly access more than p(n) memory locations. We will picture our memory as pairs of addresses and bits and a load or store of a memory bit will, then, simply mean going through that list until you find the matching address and, then, modifying that bit. Thus each memory access could take p(n) time, there could be p(n) times, and there could be at most p(n) memory locations. We have, then, modified our program so that it could take p(n)

Let E(i,t) be a series of logical variables meaning that instruction i is executed at time t if E(i,t) is true. Let M(j,t) be a series of Boolean variables representing the contents of memory bit j at time t. Notice that we have a constant number of instructions (L) and time running from 0 to q(n)+1 as above, so we have at most L*(q(n)+2) of these E variables. Since both j and t could be q(n) different values, we have at most q(n)

We will deal with the following instructions:

if(M) goto k and M=NT and M=N+T and CHOICE() and M=N and M=N'

where the if is obvious, M=NT means M receives the AND of N and T, M=N+T means M receivers the OR of N and T, CHOICE() sets a memory location called G to true or false and M=N does a simple assignment.

Here are the logical steps in the solution:

- At time 0 the first instruction will be executed. This is represented by E(1,0)E'(2,0)E'(3,0)...E'(L,0) where this is the and of these variables and where E'(i,j) means the negation of E(i,j). Note this is simple CNF.
- At time 0 the memory contains the instance of the problem to be
run. Whatever the bits required - say, for example, 101111001....010 -
we would then have
M(0,0)M'(1,0)M(2,0)M(3,0)M(4,0)M(5,0)M'(6,0)M'(7,0)M(8,0)...M'(n-3,0)M(n-2,0)M'(n,0)
as
a simple AND to represent that condition. (Here M' represents 0, M represents 1.)

- At any time t, only one instruction can be executed. This is
represented at a particular time t by
E(1,t) => E'(2,t)E'(3,t)...E'(L-1,t)E'(L,t), E(2,t) =>
E'(1,t)E'(3,t)...E'(L-1,t)E'(L,t), ... E(L,t) =>
E'(1,t)E'(2,t)E'(3,t)...E'(L-1,t). Note that since A => B is
equivalent to A'+B, we can rewrite this as
(E'(1,t)+E'(2,t)E'(3,t)...E'(L,t))(E'(2,t)+E'(1,t)E'(3,t)...E'(L,t))...(E'(L,t)+E'(1,t)E'(2,t)E'(3,t)...E'(L-1,t))
and
this can be fixed by distributing the + over the products to get
(E'(1,t)+E'(2,t))(E'(1,t)+E'(3,t))...(E'(1,t)+E'(L,t))(E'(2,t)+E'(1,t))(E'(2,t)+E'(3,t))
...(E'(2,t)+E'(L,t))...(E'(L,t)+E'(1,t))(E'(L,t)+E'(2,t))(E'(L,t)+E'(3,t))...(E'(L,t)+E'(L-1,t)).
If
we and this for all t from 1 to q(n)+1 and for all j from 1 to L we
will have what we want and
it is in CNF.

- For any instruction, we can write the effect of that instruction
in CNF. The effect always consists of determining which instruction
executes next AND what affect the instruction has. (We will demonstrate
the CNF for the instructions above.)

- The run of the program returns true if and only if at time q(n)+1
the return true instruction is executing. This can be written
E(rt,q(n)+1) where rt is the index of the return true instruction.

Note 1 2, and 3 are done. (I.e., they are in CNF and obviously correct.) Number 5 can be handled in the following way. Whenever we find ourselves executing a return true instruction, we simply replace it with a return true followed by a statement that "infinite loops" in the same spot. Hence, E(rt,t) => E(rt,t+1) and since an A => B can be rewritten as A'+B we see that we need only add the and of all statements of the form E'(rt,t)+E(rt,t+1) for each t and, then, the instance comes out true if and only if E(rt,q(t)+1) is true and this and of these or's is in CNF.

Suppose instruction j is if(M(i,t)) then goto k. This is E(j,t) means if(M(i,t)) then k is the instruction at t+1 else j+1 is the instruction at t+1. Thus E(j,t) => ( M(i,t) => E(k,t+1) && M'(i,t) => E(j+1,t+1)). Using the rule for implication gives us E'(j,t)+(M'(i,t)+E(k,t+1))(M(i,t)+E(j+1,t+1)) which is logically equivalent to (E'(j,t)+M'(i,t)+E(k,t+1))(E'(j,t)+M(i,t)+E(j+1,t+1)) which is in CNF. In addition, for every memory location M(i,t+1)=M(i,t) is equivalent to (M'(i,t+1)+M(i,t))(M(i,t+1)+M'(i,t)) should be added as a product which the E'(j,t) should be distributed over but we will leave that off for simplicity. Note that it should be there.

Suppose that instruction j is M(i)=M(k). Then what we have is E(j,t) => [(M(i,t+1)=M(k,t+1)) and E(j+1,t+1)]. Using our distributive law again, we write this as (E'(j,t)+(M(i,t+1)=M(k,t+1)))(E'(j,t)+E(j+1,t+1)). We need to show that E'(j,t)+(M(i,t+1)=M(k,t+1)) can be put in CNF. If we use product of sum formulation from a truth table we see that A=B <=> (A+B')(A'+B) so that E'(j,t)+(M(i,t+1)=M(k,t+1)) is equivalent to E'(j,t)+(M(i,t+1)+M'(k,t+1))(M'(i,t+1)+M(k,t+1)) and distributing + gives us the expression (E'(j,t)+M(i,t+1)+M'(k,t+1))(E'(j,t)+M'(i,t+1)+M(k,t+1)) and when we and this with (E'(j,t)+E(j+1,t+1)) the result is clearly in CNF. Again, we should add an and of M(m,t+1)=M(m,t) for every m not equal to i as above. Again, we keep it simple by not doing this.

Suppose that instruction j is CHOICE(). What should it do? Well, it should set M(G,t+1) to true if that will work or to false if that will work. Thus, all we can say is that the choice could be either one but if it can be done it will be chosen so as to make the program work and, therefore, the corresponding CNF expression to work. This means that CHOICE() should advance and allow M(G,T+1) to be either value in the CNF so that the expression can give the value to it that will make the expression come true. In other words, E(j,t)=>(M(G,t+1)+M'(G,t+1)) && E(j+1,t+1). This becomes E'(j,t)+(M(G,t+1)+M'(G,t+1)E(j+1,t+1) which by distribution is equivallent to (E'(j,t)+M(G,t+1)+M'(G,t+1))(E'(j,t)+E(j+1,t+1)) which is in CNF. Again, all other memory is preserved.

Suppose instruction j is M(i)=M(k)M(h). Recall that A=B can be written as (A+B')(A'+B) we get that instruction j at time t is E(j,t) => (M(i)+(M(k)M(h))')(M'(i)+M(k)M(h)). (M(k)M(h))' is (M'(k)+M'(h)) so this becomes (M(i)+M'(k)+M'(h))(M'(i)+M(k))(M'(i)+M(h)) so using the rule for => and distributing E'(j,t) we represent this instruction by (E'(j,t)+M(i,t+1)+M'(k,t)+M'(h,t))(E'(j,t)+M'(i,t+1)+M(k,t))(E'(j,t)+M'(i,t+1)+M(h,t))(E'(j,t)+E(j+1,t+1)) in CNF form.

M(i)=M(k)+M(h) and M(i)=M'(k) are left as exercises.

Note that we have part 1 taking at most O(q

QEAD (Quid Errat almost demonstratum).