CDCL
Conflict-driven clause learning (CDCL) is the search algorithm used by practically every complete SAT solver[13]. It keeps the structure of DPLL: assign variables by decisions, propagate their consequences by unit propagation, and backtrack on conflict. What it adds is learning. A conflict is not just a dead end but a proof that some combination of assignments cannot be extended to a model. CDCL extracts that proof as a new clause by conflict analysis, adds it to the clause database, and jumps back to the earliest decision level at which the new clause forces a literal, skipping decisions that had nothing to do with the conflict. The learned clause stops the same conflict from happening again anywhere else in the search. GRASP introduced the method in 1996[1]; Chaff added watched literals and the VSIDS heuristic in 2001[2], and MiniSat made the design standard[7].
The loop
The solver keeps a trail of assigned literals, each with its decision level and the clause that forced it. Each iteration propagates. If no clause is falsified, it makes a decision on an unassigned variable, opening a new level, or reports a model if none is left. If a clause is falsified, it analyzes the conflict, learns a clause with exactly one literal at the current level, undoes the trail back to the second-highest level among the clause's literals, and lets the learned clause propagate there[1][13]. A conflict at level 0 depends on no decision at all, so the formula is unsatisfiable.
The main loop of a CDCL solver with watched literals, first-UIP learning, VSIDS and Luby restarts; the helper functions are omitted.
let solve ?cfg ?(setup = ignore) (f : Cnf.cnf) =let s = create ?cfg f insetup s;let ok = ref true inList.iter (fun c ->let c = List.sort_uniq compare c inif List.exists (fun l -> List.mem (-l) c) c then () (* tautology *)else match c with| [] -> ok := false| [ l ] -> if lit_value s l = -1 then ok := false else if lit_value s l = 0 then assign s l (-1)| _ -> ignore (add_clause_raw s (Array.of_list c))) f.clauses;let result = ref None inif not !ok then result := Some Unsat;let restart_no = ref 1 and budget = ref 100 inwhile !result = None dolet confl = propagate s inif confl >= 0 then begins.st.conflicts <- s.st.conflicts + 1; decr budget; s.on_conflict ();if s.dl = 0 then result := Some Unsatelse if s.st.conflicts > s.cfg.limit then result := Some Unknownelse if s.cfg.learn then beginlet learnt, back = analyze s confl ins.on_learn learnt;cancel_until s back;s.inc <- s.inc /. 0.95; (* decay: newer bumps count more *)if Array.length learnt = 1 then assign s learnt.(0) (-1)else begins.st.learned <- s.st.learned + 1;assign s learnt.(0) (add_clause_raw s learnt)endend else begin(* DPLL: undo the latest decision and assert its negation one leveldown, where it stays until that level is undone in turn *)let d = s.trail.(s.lim.(s.dl - 1)) incancel_until s (s.dl - 1);assign s (-d) (-2)endend else if s.cfg.restarts && s.cfg.learn && !budget <= 0 then begincancel_until s 0; incr restart_no; budget := 100 * luby !restart_noend else beginlet v = pick s inif v = 0 then result := Some (Sat (Array.init (s.n + 1) (fun v -> s.value.(v) = 1)))else begins.st.decisions <- s.st.decisions + 1;s.lim.(s.dl) <- s.len; s.dl <- s.dl + 1;assign s (if s.phase.(v) then v else -v) (-1)endenddone;(Option.get !result, s.st)
An example
Take the five clauses
Deciding at level 1 implies through . Deciding at level 2 implies nothing. Deciding at level 3 implies through , then and , and is falsified.
Conflict analysis resolves with the reasons for and and learns . Its literals are at levels 1 and 3, so the solver backjumps from level 3 directly to level 1, undoing the decision on along the way, and at level 1 the learned clause is unit and sets to false. It mentions neither nor : the conflict follows from and alone, whatever made true.
Components
Learning, backjumping and branching are the core; a practical solver adds several further techniques[13].
Restarts
From time to time the solver undoes all decisions and starts the search again, keeping its learned clauses, activity scores and saved phases. Restarts guard against runs that are stuck in an unproductive part of the search space, whose running times on randomized solvers are heavy-tailed[9]. MiniSat and its successors space restarts by the Luby sequence 1, 1, 2, 1, 1, 2, 4, …, multiplied by a base interval, which is optimal for restarting a Las Vegas algorithm with unknown run-time distribution[8][7]. Because of phase saving, a restart usually rebuilds a similar assignment quickly, so restarts can be frequent.
Clause deletion
Learned clauses slow propagation and fill memory, so solvers delete most of them periodically. MiniSat kept clauses that had recently taken part in conflicts[7]; Glucose introduced the literal block distance, the number of distinct decision levels in a clause, and keeps clauses with small LBD indefinitely[10].
Preprocessing and inprocessing
Before and during search, solvers simplify the formula: bounded variable elimination resolves away variables when this does not increase the number of clauses, and subsumption, blocked clause elimination and equivalent-literal substitution remove redundancy[11].
Incremental solving
Many applications solve a sequence of related formulas. MiniSat's interface allows clauses to be added between calls and each call to be made under assumptions, literals that are treated as decisions at the lowest levels; learned clauses remain valid across calls because they are implied by the clauses alone[12]. Bounded model checking and SMT solvers depend on this.
The contribution of each part
Switching features off one at a time, on random 3-SAT, graph colouring and pigeonhole formulas, all unsatisfiable.
(* Switching the parts of a CDCL solver off one at a time. *)let colouring ~vertices ~edges ~colours =let x v c = (v * colours) + c + 1 inCnf.of_clauses(List.init vertices (fun v -> List.init colours (x v))@ List.concat_map (fun (u, v) -> List.init colours (fun c -> [ - (x u c); - (x v c) ])) edges)let random_graph n m =let rec go acc = if List.length acc = m then acc elselet u = Random.int n and v = Random.int n inif u = v || List.mem (min u v, max u v) acc then go acc else go ((min u v, max u v) :: acc) ingo []
Conflicts needed, with a limit of 300,000.
conflicts 3-SAT 100 3-SAT 130 colouring 70 7 pigeonsfull 371 795 358 758no restarts 470 893 376 847no VSIDS 2102 7798 888 130no learning (DPLL) 41903 > 300000 > 300000 3246result UNSAT UNSAT UNSAT UNSAT
Learning is the decisive ingredient: without it, the solver becomes DPLL, and two of the four formulas are out of reach within the limit. The branching heuristic matters by factors of two to ten, except on the pigeonhole formula, where the fixed variable order happens to follow its structure. Restarts matter little on these small formulas; their benefit shows on large industrial instances.
Proof complexity
Each learned clause is derived from the formula by resolution, so a CDCL run on an unsatisfiable formula is a resolution refutation. The converse also holds: CDCL with restarts, and with the right decisions, polynomially simulates general resolution[3][4], whereas DPLL corresponds to tree-like resolution[5], which is exponentially weaker on some formulas[6]. Formulas that are hard for resolution, such as the pigeonhole formulas, are therefore hard for CDCL as well.
History
Marques-Silva and Sakallah introduced conflict analysis, clause learning and non-chronological backtracking in GRASP, presented in 1996 and published in 1999[1]; Bayardo and Schrag's rel_sat of 1997 used related learning[14]. Chaff, from Princeton in 2001, combined first-UIP learning with watched literals and VSIDS and was an order of magnitude faster than earlier solvers[2]. Eén and Sörensson's MiniSat, first released in 2003, distilled the design into a small, readable C++ program and became the base of many later solvers[7]. The following decade added clause minimization, LBD-based deletion, phase saving, inprocessing and rapid restarts[10][11]; the theoretical explanation of CDCL's power as a resolution engine came in 2004 and 2011[5][3][4].
see also
- First-UIP conflict analysisConflict analysis is the step of a CDCL SAT solver that explains a conflict by a new clause. Starting from the clause that became false, the solver repeatedly resolves it with the reason clauses of literals assigned at the current decision level, in reverse order of assignment, until only one literal of that level remains. That literal is the first unique implication point (UIP), a node through which every path from the decision to the conflict passes in the implication graph. The resulting clause is learned; it is implied by the formula, it forbids the combination of assignments that caused the conflict, and after backjumping to the second-highest level in it, it immediately propagates the negation of the UIP.
- DPLLDPLL, the Davis–Putnam–Logemann–Loveland procedure, is the backtracking search algorithm for Boolean satisfiability on which all complete SAT solvers are built. It repeatedly simplifies a CNF formula by unit propagation and pure literal elimination, then chooses an unassigned variable and tries both of its values in turn, backtracking to the most recent choice when a clause becomes false. It is sound and complete, uses memory linear in the formula, and its runs on unsatisfiable formulas correspond to tree-like resolution proofs, which gives exponential lower bounds such as the n! − 1 decisions it needs for the pigeonhole formulas. Clause learning turned it into CDCL.
- VSIDSVSIDS, Variable State Independent Decaying Sum, is the branching heuristic of conflict-driven SAT solvers. Each variable has an activity score, which is increased whenever the variable takes part in a conflict and decays geometrically over time; when the solver must make a decision, it branches on the unassigned variable with the highest activity. The heuristic is cheap, because it depends on conflicts rather than on the current formula, and it focuses the search on the variables involved in recent conflicts. It was introduced by the Chaff solver in 2001 and, in the exponential form used by MiniSat, remains the default in most solvers.
- Watched literalsThe two-watched-literal scheme is the data structure SAT solvers use to detect unit and conflicting clauses. Each clause of two or more literals watches two of its literals that are not false; a clause is examined only when one of its watched literals becomes false, and then it either finds a replacement watch, becomes unit, or is a conflict. Because the watches remain valid when assignments are undone, backtracking costs nothing, and a clause with many literals is touched only when its watches are hit. Introduced by the Chaff solver in 2001, it made unit propagation, which dominates solver time, several times faster.
- Unit propagationUnit propagation is the inference rule at the core of SAT solvers: when every literal of a clause is false under the current partial assignment except one unassigned literal, that literal must be true. Applying the rule until nothing changes either extends the assignment or finds a clause with every literal false, a conflict. It decides satisfiability of Horn formulas on its own, it takes most of the running time of a modern CDCL solver, and it is implemented with two watched literals per clause so that only clauses that may have become unit are ever inspected.
- ResolutionResolution is the inference rule that derives, from two clauses containing a variable with opposite signs, the clause of all their other literals: from C ∨ x and D ∨ ¬x, infer C ∨ D. It is sound and refutation complete for propositional logic, so a set of clauses is unsatisfiable exactly when the empty clause can be derived. Resolution is the proof system behind SAT solvers, whose runs on unsatisfiable formulas are resolution refutations, and behind first-order theorem provers and logic programming. Some formulas, such as the pigeonhole formulas, have only exponentially long resolution refutations.
- SATThe Boolean satisfiability problem, SAT, asks whether some assignment of true and false to the variables of a propositional formula makes the formula true. It was the first problem shown to be NP-complete, so every problem in NP reduces to it, and no polynomial-time algorithm is known. In practice SAT solvers based on conflict-driven clause learning decide industrial instances with millions of variables, which has made SAT a general-purpose engine for hardware and software verification, planning, scheduling and combinatorics.
- Bit-blastingBit-blasting decides formulas over fixed-width bit-vectors, the machine integers of programs and hardware, by translating every variable into one Boolean variable per bit and every operation into a Boolean circuit, then handing the resulting clauses to a SAT solver. Addition becomes a ripple-carry adder and multiplication a shift-and-add array of adders, encoded with the Tseitin transformation. It is complete and simple, and it is how SMT solvers handle bit-vectors after word-level simplification; its weak point is multiplication, whose circuits are large and hard for SAT solvers.
- Craig interpolationCraig's interpolation theorem states that if a formula A implies a formula B, there is a formula I, the interpolant, built only from the symbols A and B have in common, such that A implies I and I implies B. In verification it is used in the equivalent refutation form: when A ∧ B is unsatisfiable, an interpolant is implied by A, inconsistent with B, and mentions only shared variables. For propositional logic, an interpolant can be computed from a resolution refutation of A ∧ B in linear time, which McMillan used in 2003 to build an unbounded model checker from a SAT solver.
- DPLL(T)DPLL(T) is the architecture of lazy SMT solvers: a CDCL SAT solver searches over the Boolean structure of a formula, treating each theory atom as a propositional variable, and a theory solver for T checks the consistency of the atoms it assigns. When the theory solver finds the assigned literals inconsistent, it returns an explanation, whose negation the SAT solver learns as a clause before backjumping; it may also propagate literals the assignment implies. The approach separates a generic engine from pluggable theory solvers and is used by nearly all SMT solvers, including Z3, cvc5 and Yices.
- Pigeonhole formulaThe pigeonhole formulas PHPⁿ⁺¹ₙ are CNF formulas stating that n + 1 pigeons can be placed in n holes with no two in the same hole. They are unsatisfiable, as the pigeonhole principle says, but Haken proved in 1985 that every resolution refutation of them has exponential size. Since SAT solvers based on DPLL and CDCL produce resolution proofs, they need exponential time on these small formulas, which makes the family the standard example of what resolution cannot do. Proof systems that can count, such as cutting planes and extended resolution, refute them in polynomial size.
referenced by
- Implementing SAT in OCaml Part 2From backtracking to CDCL: a trail, decision levels, first-UIP conflict analysis, clause learning, and non-chronological backjumping.
- Implementing SAT in OCaml Part 3From SAT to SMT: the DPLL(T) architecture, reusing conflict-driven learning for theory conflicts, and a union-find equality theory.
- Implementing SAT in OCaml Part 5A hand-written C stub binding to Z3, run against the same difference-logic benchmarks as the from-scratch solver, and where it falls over.
further reading
- [1]J. P. Marques-Silva, K. A. Sakallah, “GRASP: a search algorithm for propositional satisfiability”, IEEE Transactions on Computers 48 (1999).
- [2]M. W. Moskewicz, C. F. Madigan, Y. Zhao, L. Zhang, S. Malik, “Chaff: engineering an efficient SAT solver”, DAC (2001).
- [3]K. Pipatsrisawat, A. Darwiche, “On the power of clause-learning SAT solvers as resolution engines”, Artificial Intelligence 175 (2011).
- [4]A. Atserias, J. K. Fichte, M. Thurley, “Clause-learning algorithms with many restarts and bounded-width resolution”, Journal of Artificial Intelligence Research 40 (2011).
- [5]P. Beame, H. Kautz, A. Sabharwal, “Towards understanding and harnessing the potential of clause learning”, Journal of Artificial Intelligence Research 22 (2004).
- [6]E. Ben-Sasson, R. Impagliazzo, A. Wigderson, “Near optimal separation of tree-like and general resolution”, Combinatorica 24 (2004).
- [7]N. Eén, N. Sörensson, “An extensible SAT-solver”, SAT, Lecture Notes in Computer Science 2919 (2004).
- [8]M. Luby, A. Sinclair, D. Zuckerman, “Optimal speedup of Las Vegas algorithms”, Information Processing Letters 47 (1993).
- [9]C. P. Gomes, B. Selman, H. Kautz, “Boosting combinatorial search through randomization”, AAAI (1998).
- [10]G. Audemard, L. Simon, “Predicting learnt clauses quality in modern SAT solvers”, IJCAI (2009).
- [11]N. Eén, A. Biere, “Effective preprocessing in SAT through variable and clause elimination”, SAT (2005).
- [12]N. Eén, N. Sörensson, “Temporal induction by incremental SAT solving”, Electronic Notes in Theoretical Computer Science 89 (2003).
- [13]J. Marques-Silva, I. Lynce, S. Malik, “Conflict-driven clause learning SAT solvers”, in A. Biere et al. (eds.), Handbook of Satisfiability, IOS Press (2nd ed., 2021).
- [14]R. J. Bayardo, R. C. Schrag, “Using CSP look-back techniques to solve real-world SAT instances”, AAAI (1997).
last updated