X, Conflict-Driven-Clause-Learning and for solving

Jeremias Berg

Monday 1st December, 2014

1 Introduction

In this text we give an informal description of the two used in the experimental comparison of Sudoku solvers. We direct the reader to the provided references for a more thorough presentation [1, 2]. Our aim is to present both algorithms in a easily followable way. However, basic knowledge of algorithm design, mathematical terminology and data structures is assumed.

2 DLX for exact cover

The first algorithm we present is Algorithm X implemented with Dancing Links, known as the DLX algorithm. As mentioned in the Sudoku solver comparison, the algorithm was originally proposed for solving the exact cover problem: Definition 1 Given a binary matrix M let M(r, c) denote the element of M on row r column c. The exact cover problem asks us to decide the existence of a of its rows R0 such that for each column c of M there exists exactly one r ∈ R0 for which M(r, c) = 1. We call such a subset for an exact cover of the matrix. As an example, consider: 1 0 1 1 1 1 0 0 . (1) 0 0 0 1 For this matrix no exact cover exists. In order to see this, note that in order to ensure that the potential exact cover includes a 1 on the second column, it has to include the second row. On the other hand, in order to include a 1 in the third column, the first row has to be included. However, now the exact cover includes 2 ones in the first column, which is a conflict. For a partial exact cover E of a matrix we say that E covers a column c if E includes exactly one row r for which M(r, c) = 1. The algorithm for solving exact cover suggested by Knuth, Algorithm X, is a simple non-deterministic search algorithm. At each iteration of the search, the algorithm picks one of the columns c in the matrix that has not been covered yet. Then it branches non-deterministically on the row to use for covering c. For each possible choice of r the algorithm removes all of the remaining columns of M that are also covered by r. In order to prevent conflicts the algorithm also removes all rows r0 that also cover any of the removed columns, including all rows that cover the originally picked c. Algorithm 1 shows the pseudo code of algorithm X. A simple (naive) conversion of Algorithm 1 into a deterministic bactracking algorithm does not perform particularly well. The reason is the time spent searching for ones in the matrix and the repeated addition and removal of rows/columns during search, (all operations require O(N × M) for an N times M matrix). In order to address these issues Knuth proposes a technique he calls dancing links. For a node x in a doubly linked list let x.l denote its left neighbour and x.r its right neighbour. Now (as most programmers know) the operations: x.l.r = x.r and x.r.l = x.l remove x from the list. Dancing links is based on the observation that the operations: x.l.r = x and x.r.l = x

1 Input: A Matrix M, a partial exact cover E Output: An exact cover E of M (if one exists) if M isEmpty() then return E else col ← nextColumn() // Deterministic r ← getRow() for which M(r, col) = 1 // Non-Deterministic E ← E ∪ r for c ∈ M s.t M(r, c) = 1 do M ← M \ c for r0 ∈ M s.t M(r0, c) = 1 do M ← M \ r0 end end return AlgorithmX(M, E) // Non-Deterministic end Algorithm 1: Algorithm X insert x back into the list (as long as the neighbour pointers of x are unaltered). This allows for efficient adding and removal of nodes in constant time, which solves the time problem for adding and removing rows/columns. In order to enable efficient search for ones in the matrix Knuth proposes a sparse data structure: • The number ones on each row form a doubly linked (circular) list. • The number ones on each column form a doubly linked (circular) list with a special header node for each column. The header nodes also form a doubly linked list. • Except for its neighbours (in the column list) each node also contains a reference to the header of its column. • The headers are used to indicate which columns are / are not covered in the considered partial solutions. Furthermore the headers include information regarding the number of ones in the column they represent. This is to enable a heuristic for picking the column with fewest number of ones for covering next.

h1 h2 h3 h4

1 1 1

1 1

1

Figure 1: Example of the datastructure required for DLX.

Figure 1 shows an example of the data structure instantiated for Matrix 1. The figure does not show the links from all “inner” nodes to their respective column headers. This datastructure allows an efficient implmentation of Algorithm X as long as some care is taken in the order of row/column additions and removals. Knuths paper [2] provides more information.

2 3 Conflict-Driven-Clause-Learning

In order to present the workings of a modern SAT solver we need a slightly more rigorous definition of the SAT problem. For a boolean variable x there are two literals x and ¬x. A literal of form x is called positive and a literal ¬x is called negative. A clause is a set of literals. A propositional formula in conjunctive-normal-form (CNF) is a set of clauses. The restriction to CNF-formulas can be done without loss of generality; it is fairly well known that for all propositional logic formulas there exists a logically equivalent CNF-formula. Given a CNF-formula F the SAT-problem asks to decide the existence of an assignment to the variables of F that satisfies all clauses of F . A positive (negative) literal l is satisfied by an assignment τ if τ(l) = 1(0). A clause C is satisfied by an assignment τ iff τ satisfies a literal l ∈ C. To simplify algorithmic presentation we view an assignment τ as a set of literals for which {x, ¬x} 6⊂ τ for any variable x. An assignment is is complete if either x ∈ τ or ¬x ∈ τ for all variables in F , else its partial. Modern Conflict-Driven-Clause-Learning (CDCDL) SAT solvers are at core based on the Davis–Putnam–Logemann–Loveland (DPLL) algorithm. The core is a simple search shown in Algorithm 2: at each iteration the algorithm picks a still unassigned variable, then branches on the two possible values for it. Each time a conflict (a clause whose all literals are unsatisfied by the current partial solution) is encountered, the current branch in the search tree is terminated. The algorithm terminates either after trying both assignments for the variable picked first or finding a complete (satisfying) assignment.

Input: A CNF formula F a partial assignment τ Output: Complete assignment τ to F or UNSAT unitP ropagate(F, τ) if conflict(F, τ) then if noDecisions() then return UNSAT // If we have a conflict without decisions (guesses), the formula can’t be satisfied else analyseConflict() // Learn a conflict clause and add it to the formula backtrack() // Non chronologically x ← pickNextV ariable() τ ← τ ∪ {x} r ← CNF Solve(F, τ) if r = UNSAT then τ ← (τ \{x}) ∪ {¬x} return CNF Solve(F, τ) else return r end Algorithm 2: CNFSolve

In order to improve performance SAT-solvers employ a number of heuristics, the three most important ones are unit-propagation, non-chronological backtracking and conflict-clause learning.

3.1 Unit-propagation The most important heuristic employed by SAT solvers is unit propagation. Unit propagation is a form of logical inference, whenever a partial assignment τ unsatisfies all but one literal from a clause C ∈ F , the value for the final literal is forced (True for a positive, False for a negative literal). A SAT solver exploits this by simplifying the formula accordingly. Efficient implementations of unit propagation employ the lazy watched literal scheme. The algorithm maintains pointers to two literals in each clause in the formula. As long as both are unassigned, the clause can never be unit and nothing needs to be done. As soon as one of the watched literals is unsatisfied, the solver needs to either find an unnasigned or satisfied literal from that clause. If neither can be found, the clause is unit and needs to be propagated.

3 3.2 Conflict-clause learning Whenever a SAT-solver encounters a conflict, it can analyze it in order to learn new information about the formula and avoid similar conflicts in other parts of the search tree. For a simple example consider a situation in which the solver has decided x, ¬y and z before encountering a conflict. Then the solver can learn the clause {¬x, y, ¬z}. As there might be a significant amount of search (decisions or unit-propagation) inbetween these decisions, the conflict clauses can potentially prune the search space significantly.

3.3 Non-chronological backtracking The final (presented) heuristic emplyed by SAT-solvers is non-chronological backtracking. The technique is based on conflict analysis. Instead of backtracing to the previous level, the solver might sometimes benefit from backtracking further, to the latest decision that actually affected the conflict. This technique again allows for more effective pruning of the search space. These three techniques have been shown to be crucial in the development of SAT-solverr. However, they are by no means the only proposed heuristics used by SAT-solvers. Solving SAT is an active area of research and new techniques are proposed every year. The book [1] provides a good starting-point for the interested reader.

References

[1] Armin Biere and Marijn Heule and Hans van Maaren and Toby Walsh, Handbook of Satisfiability, IOS Press, 2009. [2] Knuth Donald, Dancing links, Millennial Perspectives in Computer Science, arXiv:cs/0011047, 2000, Re- trieved 2006-07-11.

4