wiki

DPLL

The Davis–Putnam–Logemann–Loveland procedure, DPLL, decides the satisfiability of a formula in conjunctive normal form by backtracking search[2]. It alternates two activities. Simplification applies rules that cannot lose solutions: unit propagation sets the only unassigned literal of a clause whose other literals are false, and pure literal elimination sets a literal whose negation occurs nowhere. When no rule applies, the procedure splits: it chooses a variable, assigns it a value, and recurses, trying the other value if the first leads to a clause with every literal false. The formula is satisfiable if some branch satisfies every clause and unsatisfiable if every branch ends in conflict. Martin Davis, George Logemann and Donald Loveland published it in 1962 as a variant of the Davis–Putnam procedure of 1960 that needed far less memory[1][2]. Every modern SAT solver still runs this search, extended by clause learning.

§ 01

Algorithm

Write for the formula obtained by making literal true: clauses containing are removed, and is deleted from the rest. Then[2][3]:

where is the empty clause. The unit and pure rules are applied first because they never need to be undone for their own sake: a unit clause leaves no choice, and a pure literal can be made true without falsifying any clause. Only the split introduces a choice point.

DPLL on lists of clauses, with an optional trace.

(* DPLL on clauses as lists of integer literals. Assigning a literal
removes the clauses it satisfies and deletes its negation from the
others; an empty clause is a conflict. *)
let assign l cs =
List.filter_map (fun c -> if List.mem l c then None else Some (List.filter (( <> ) (-l)) c)) cs
let decisions = ref 0
let trace = ref false
let say depth fmt = Printf.ksprintf (fun s -> if !trace then print_endline (String.make (2 * depth) ' ' ^ s)) fmt
let rec dpll ?(pure = true) depth cs model =
if cs = [] then Some model (* every clause satisfied *)
else if List.mem [] cs then (say depth "conflict"; None)
else match List.find_opt (fun c -> List.length c = 1) cs with
| Some [ l ] -> (* unit clause: l is forced *)
say depth "unit %d" l; dpll ~pure depth (assign l cs) (l :: model)
| _ ->
let lits = List.sort_uniq compare (List.concat cs) in
match (if pure then List.find_opt (fun l -> not (List.mem (-l) lits)) lits else None) with
| Some l -> (* pure literal: safe to set *)
say depth "pure %d" l; dpll ~pure depth (assign l cs) (l :: model)
| None ->
let v = abs (List.hd lits) in (* branch *)
incr decisions;
say depth "decide %d" v;
match dpll ~pure (depth + 1) (assign v cs) (v :: model) with
| Some m -> Some m
| None -> say depth "decide %d" (-v); dpll ~pure (depth + 1) (assign (-v) cs) (-v :: model)

Two traces: the eight clauses over three variables, which are unsatisfiable, and a satisfiable formula.

open Dpll

Running it.

decide 3
decide 2
unit 1
conflict
decide -2
unit 1
conflict
decide -3
decide 2
unit 1
conflict
decide -2
unit 1
conflict
UNSAT
--
pure 5
pure 4
decide 3
unit -2
unit 1
SAT: 5 4 3 -2 1
x₃¬x₃x₂¬x₂x₂¬x₂x₃x₂x₂x₁, then ✗x₁, then ✗x₁, then ✗x₁, then ✗each leaf: unit propagation forces x₁ and then falsifies a clause
The search tree of the first trace. The procedure splits on x₃ and then x₂; in each of the four branches unit propagation sets x₁ and reaches a conflict, so the formula is unsatisfiable after four decisions and three backtracks.

In the satisfiable example, the pure literals 5 and 4 are set first, removing two clauses, and a single decision then propagates to a full model. Implementations do not copy the formula at each step as this one does; they keep one assignment, a trail of the literals set so far in order, and undo the trail back to the last decision when they backtrack, which is called chronological backtracking.

§ 02

Correctness and cost

The procedure terminates because every step either assigns a variable or ends a branch, and the depth is bounded by the number of variables. It is sound, since a claimed model satisfies every clause, and complete, since the split covers both values of the variable, and the unit and pure rules only discard assignments that cannot lead to a model or that can be modified into one that does not use them. Memory is linear in the size of the formula, which was the point of the 1962 version.

Time is exponential in the worst case. On an unsatisfiable formula, the search tree of DPLL can be read as a tree-like resolution refutation: each leaf is a clause falsified by the branch, and each split resolves the refutations of its two subtrees on the split variable. Lower bounds on tree-like resolution therefore bound DPLL on every branching order[4][11]. The pigeonhole formulas, which have no short resolution proofs of any kind[10], make the growth visible.

Decisions made by DPLL, with and without the pure literal rule, against conflicts of a CDCL solver.

(* How the search grows: DPLL decisions against CDCL conflicts. *)
let dpll_decisions ~pure (f : Cnf.cnf) =
Dpll.decisions := 0; ignore (Dpll.dpll ~pure 0 f.clauses []); !Dpll.decisions

Running it.

pigeonhole DPLL decisions (no pure rule) CDCL conflicts
3+1 5 8 7
4+1 23 51 28
5+1 119 374 154
6+1 719 3245 758
7+1 5039 32780 4164
random 3-SAT, 4.5 clauses per variable, medians of 11
n DPLL decisions CDCL conflicts
20 15 10
30 25 17
40 65 31
50 267 54
60 923 72
70 1338 109

On the pigeonhole formulas with holes, DPLL with the pure literal rule makes exactly decisions, and without it several times more. Clause learning does not help much here, because the formulas are hard for general resolution, which bounds CDCL as well. On random formulas the gap is large: CDCL's conflicts grow far more slowly than DPLL's decisions.

§ 03

Branching heuristics

The choice of the variable to split on, and of the value to try first, determines the size of the tree. Classical DPLL solvers used static measures of the current formula: MOMS heuristics prefer variables with the most occurrences in the shortest clauses, and the Jeroslow–Wang rule weights each occurrence of a literal in a clause of length by [5]. Lookahead solvers try assigning each candidate variable, propagate, and measure how much the formula shrinks, choosing the variable whose two branches reduce it most[6][7]. Lookahead remains strong on small hard random formulas; on large structured instances it was overtaken by the cheap, conflict-driven VSIDS heuristic of CDCL solvers.

§ 04

Davis–Putnam and DPLL

The 1960 procedure of Davis and Putnam also used unit and pure literal rules, but eliminated variables instead of splitting on them: to remove , it replaced all clauses containing or by all their resolvents on [1]. This is complete, but the number of clauses can grow quadratically at each elimination and exponentially overall. When Logemann and Loveland implemented the method on an IBM 704, the memory ran out, and they replaced elimination by the splitting rule, which only needs a stack[2][8]. Variable elimination returned decades later as a preprocessing step in CDCL solvers, applied only where it does not increase the number of clauses.

§ 05

From DPLL to CDCL

DPLL backtracks chronologically, to the most recent decision, even if that decision had nothing to do with the conflict, and it forgets the reason for the conflict, so the same contradiction can be rediscovered in many branches. Conflict-driven clause learning, introduced by GRASP in 1996, analyzes each conflict to derive a clause that explains it, adds the clause to the formula, and jumps back to the decision that the clause implicates[9]. Nieuwenhuis, Oliveras and Tinelli described both as transition systems over partial assignments, in which DPLL and CDCL differ only in the backtracking and learning rules, and extended the system to DPLL(T) for SMT[3]. With learning and restarts, a CDCL solver can simulate general resolution, which is exponentially stronger than the tree-like resolution that bounds DPLL[4].

§ 06

History

Martin Davis and Hilary Putnam published their procedure in 1960 as part of a method for first-order logic based on Herbrand's theorem[1]. Implementing it at New York University, George Logemann and Donald Loveland replaced resolution-based elimination by splitting, and the three published the resulting program in 1962[2][8]. The algorithm, often named DPLL after all four authors, was the basis of complete SAT solvers for three decades; heuristics and lookahead refined it through the 1990s[5][6], and clause learning transformed it into CDCL from 1996[9].

see also

further reading

  1. [1]M. Davis, H. Putnam, “A computing procedure for quantification theory”, Journal of the ACM 7 (1960).
  2. [2]M. Davis, G. Logemann, D. Loveland, “A machine program for theorem-proving”, Communications of the ACM 5 (1962).
  3. [3]R. Nieuwenhuis, A. Oliveras, C. Tinelli, “Solving SAT and SAT Modulo Theories: from an abstract Davis–Putnam–Logemann–Loveland procedure to DPLL(T)”, Journal of the ACM 53 (2006).
  4. [4]P. Beame, H. Kautz, A. Sabharwal, “Towards understanding and harnessing the potential of clause learning”, Journal of Artificial Intelligence Research 22 (2004).
  5. [5]R. G. Jeroslow, J. Wang, “Solving propositional satisfiability problems”, Annals of Mathematics and Artificial Intelligence 1 (1990).
  6. [6]C. M. Li, Anbulagan, “Heuristics based on unit propagation for satisfiability problems”, IJCAI (1997).
  7. [7]M. J. H. Heule, H. van Maaren, “Look-ahead based SAT solvers”, in A. Biere et al. (eds.), Handbook of Satisfiability, IOS Press (2009).
  8. [8]M. Davis, “The early history of automated deduction”, in A. Robinson, A. Voronkov (eds.), Handbook of Automated Reasoning, Elsevier (2001).
  9. [9]J. P. Marques-Silva, K. A. Sakallah, “GRASP: a search algorithm for propositional satisfiability”, IEEE Transactions on Computers 48 (1999).
  10. [10]A. Haken, “The intractability of resolution”, Theoretical Computer Science 39 (1985).
  11. [11]E. Ben-Sasson, R. Impagliazzo, A. Wigderson, “Near optimal separation of tree-like and general resolution”, Combinatorica 24 (2004).

last updated