Background

A Boolean formula f is said to be in 3CNF (3 conjunctive normal form) if f is the conjunction (AND) of some number of clauses, where each clause is the disjunction (OR) of three literals, where each literal is either a variable or the complement (NOT) of a variable. To be in 3CNF we further insist that the variables in each clause be distinct. Also, there must be at least one clause.

For example,

f = (x1,x2,-x4) (x2,x3,x5) (-x1,x2,x4) (-x2,-x3,-x5)

is one way to represent a 3CNF formula. We have used a comma to denote disjunction, a minus sign to denote complementation, and concatenation to denote conjunction. This formula has 4 clauses (the things in parentheses) and 5 variables (x1,x2,x3,x4,x5).

A truth assignment t to a formula f having underlying variables in Vars is a map from Vars to {0,1}. A truth assignment t causes f to evaluate to either false (0) or true (1) in the natural way. For example, the truth assignment (x1,x2,x3,x4,x5)=(0,0,0,0,0) causes the example formula f to evaluate to false (0), because the second clause evaluates to false. (In a 3CNF formula, the formula evaluates to true if and only if each clause evaluates to true.)

A formula f is satisfiable if there exists a truth assignment t which makes f evaluate to true.

You are to write a program that takes a list of 3CNF formulas and tries to find a satisfying assignment for each. Your program will work its way down the list until it satisfies every formula in the list or until it runs out time trying. When your program finds a satisfying assignment for a formula, print it out. Have your program terminate once it has used 30 seconds of CPU time. Before your program terminates have it report the number of formulas it found satisfying assignments for.

Here is a list of known-to-be-satisfiable 3CNF formulas that we'd like you to run your program on: hw1-data. In this file we use a slightly different encoding convention than above. To facilitate reading the input file, its format is similar to that of Homework 0. There will be one or more "runs" where each run begins with a line containing a single integer. This integer indicates how many clauses are in the next formula. Each of the following lines contains a single clause each. Each clause is represented by three integers representing three variables. A run length of 0 indicates the end of input. Thus, a file containing only the example formula above would be encoded as:

```   4
1  2 -4
2  3  5
-1  2  4
-2 -3 -5
0 ```

Each time your program successfully finds a satisfying assignment you should output the assignment as a series of ones and zeroes, each separated by white space, indicating assignments of true or false for the variables x1, x2, ... Follow this assignment output on the following line by a floating point value indicating the total amount of CPU time your program has used for all runs so far. Separate the output of each run by an empty line. Output for the above file might look like this:

```0 1 0 0 0
0.012```

As with homework 0, your program will be tested mechanically, so it is very important that your output conform with these specifications.

How to do it

If the formula f has n variables then there will be 2**n possible truth assignments. This number quickly becomes too many for you to try them all. Instead, you must use a heuristic to try to find a satisfying assignment for f. Here is the heuristic you should use:

```   ***  HEURISTIC "WalkSAT" -  Try to find a satisfying assignment for f   ***

repeat
Choose a random truth assignment t.
for i=1 to max_flips do
if t satisfies f then SUCCESS: output t and go on to next formula.
Choose a random unsatisfied clause C. Denote C's variables x,y,z.
Let t1,t2,t3 be the truth assignments obtained by toggling t on
variables x,y,z, respectively.
Whichever of t1,t2,t3 satisfies the most clauses, let t be that
truth assignment. (Break ties arbitrarily.)
until the total CPU time exceeds LIMIT seconds.
halt -- ran out of time.```

Changing the value of a variable is making a flip. You might try making max_flips (the maximum number of flips) around 500. In general, this could be a function of the number of variables and/or the number of clauses in f. Changing the (random) initial assignment is making a new try. You'll keep making new tries until you run out of time.

Try to make your program beautiful. Make appropriate use of C++ classes. Use C++ (not C) I/O and (if you need it) memory allocation. Make your program efficient. BUT: efficiency should be obtained by cleanly implementing a good algorithm; don't compromise readability in a (usually misguided!) attempt to be more efficient.

We will post to the newsgroup and course homepage code for generating random numbers and timing executions.

What to turn in

Hardcopy: Besides the files which constitute your program (and the makefile which builds your executable) turn in a 1-2 page design document. The design document explains the design choices that you made (including key data structures), and why. It reports anything interesting you discovered (in this case: what is a good choice for max_flips?). The audience for your design document is the grader. The grader knows very well what the programming assignment is supposed to do, so don't waste your time (or his) describing the problem. Make sure your document is clear, concise, and understandable.

Softcopy: Use handin, as you did for homework 0. The directory for this program will be hw1. Turn in a makefile called makefile which produces an executable program called satisfy. We will be using make to compile your program, so it is very important that you turn in a functioning makefile. If your program uses any header files that you wrote, don't forget to submit them, too.

Contest!

Run your program on the DECs a few times (using the supplied dataset) and bring a printout of your program's fastest execution to class on April 22. Whoever writes the program which gets furthest down the list will win a great prize!!!

There will be more contests in this class. Of course participation in the contests is optional.