Boolean Satisfiability and DPLL: The Core Algorithm

Encode CSP constraints as SAT clauses, then trace the Davis-Putnam-Logemann-Loveland algorithm — unit propagation, pure-literal elimination, and recursive splitting — step by step on small instances.

Estimated time
~16 min
Difficulty
intermediate
Sources
6 sources

Every time your GPS finds the fastest route, a chip verifier proves a microprocessor correct, or a package manager resolves dependencies without conflict, an algorithm is deciding whether a giant system of Boolean constraints can all be true simultaneously — and if so, how. That algorithm, at its heart, is almost always DPLL.

Coming from the previous lesson?

In “Constraint Satisfaction: Variables, Domains, and Backtracking” you saw how a CSP is defined as a triple (X, D, C), traced backtracking on 4-Queens, and used arc consistency to prune domains. This lesson reframes those same constraints as Boolean clauses, then shows you the algorithm that modern solvers — including the CP-SAT solver used in the school timetabling lesson — actually use under the hood.

What Is Boolean Satisfiability?

Picture a padlock with three numbered dials: A, B, C. Each dial is binary — it can only point to 0 (False) or 1 (True). The lock opens only when a specific combination satisfies a set of rules written on the back of the box:

  • Rule 1: At least one of A or B must be True.
  • Rule 2: If A is True, then C must be True.
  • Rule 3: B and C cannot both be True.

Can you open the lock? If so, what combination works?

This is Boolean Satisfiability (SAT): given a set of Boolean variables and a set of constraints (clauses) over them, find an assignment of True/False to each variable that satisfies every clause — or determine that none exists.

SAT (Boolean Satisfiability) def.

Given a set of Boolean variables and a formula in Conjunctive Normal Form (CNF) — a conjunction (AND) of clauses, each clause being a disjunction (OR) of literals — determine whether there exists a truth assignment that makes the formula True.

CNF is the universal language. Every Boolean constraint can be rewritten as a conjunction of clauses. A literal is either a variable (positive literal, e.g. A) or its negation (negative literal, e.g. ¬A). A clause is an OR of literals. The whole formula is an AND of clauses.

Our padlock rules above translate directly:

This is a 3-clause CNF over three variables. Any assignment that makes all three clauses True simultaneously is a satisfying assignment.

Checking an assignment by hand

Try A = True, B = False, C = True:

  • (A ∨ B) = (T ∨ F) = T
  • (¬A ∨ C) = (F ∨ T) = T
  • (¬B ∨ ¬C) = (T ∨ F) = T

All three clauses are satisfied. This assignment opens the lock.

Try A = True, B = True, C = True:

  • (A ∨ B) = T
  • (¬A ∨ C) = (F ∨ T) = T
  • (¬B ∨ ¬C) = (F ∨ F) = F

Rule 3 fails. This combination does not work.

Check your understanding

Which of the following is a valid CNF clause?

From CSP Constraints to SAT Clauses

In the previous lesson you encoded the 4-Queens problem as a CSP: variables Q1–Q4 (column of each queen), domain 4, and binary not-attack constraints. How does that become SAT?

The key idea: replace each (variable, value) pair with a Boolean indicator variable, then write clauses that enforce the original CSP semantics.

Analogy — CSP constraint (Q1 ≠ Q2) is like SAT clause set

For 4-Queens with columns 1–4, introduce Boolean variable meaning “queen i is in column c.” Then:

  • At-least-one: each queen must be in some column.
  • At-most-one: each queen can be in only one column.
  • No-attack: two queens in the same column or diagonal are forbidden.

Encoding 'Q1 ≠ Q2' (same column forbidden) as clauses

Suppose only columns 1 and 2 exist (simplified). Variables: x₁₁, x₁₂ (queen 1 in col 1 or 2) and x₂₁, x₂₂ (queen 2 in col 1 or 2).

“At least one column per queen”: and

“Not both in column 1”:

“Not both in column 2”:

These four clauses, in CNF, fully capture the constraint that Q1 ≠ Q2 (same column). The pattern generalises to all pairs and all columns.

This encoding is called the direct/naive encoding. Modern SAT-based CSP solvers use more compact encodings (commander encoding, ladder encoding), but the principle is the same: every domain value becomes a Boolean, every constraint becomes a clause set. [Handbook of Satisfiability (2nd ed.)]

CSP SAT / CNF
Variable X with domain DOne Boolean per (variable, value) pair
Constraint Relation over variable tuplesOne or more clauses
Solution Assignment satisfying all constraintsAssignment making CNF True
Backtracking Branch on variable valueBranch on literal True/False
Arc consistency Prune domain valuesUnit propagation in SAT
Concept mapping between CSP and SAT

Why bother with SAT?

SAT solvers have been engineered for decades with heuristics (VSIDS), clause learning (CDCL), and restarts tuned for industrial instances with millions of variables. Encoding a CSP into SAT and running a modern solver often beats a hand-written CSP solver on the same problem. CP-SAT itself uses a SAT backbone for this reason.

Check your understanding

If a CSP has 10 variables each with domain size 5, how many Boolean indicator variables does the direct encoding introduce?

The DPLL Algorithm

Named after Davis, Putnam, Logemann, and Loveland (1960–62), DPLL is a systematic backtracking search over truth assignments, accelerated by two powerful inference rules that collapse large parts of the search tree before you even branch. [A Machine Program for Theorem-Proving (DPLL original paper)]

DPLL (Davis-Putnam-Logemann-Loveland) def.

A complete, sound, backtracking-based algorithm for SAT. It selects a variable, assigns it, simplifies the formula, and recurses. Two inference rules — unit propagation and pure-literal elimination — are applied eagerly at each node to collapse forced assignments before branching.

DPLL has three interlocking rules:

Rule 1 — Unit Propagation (UP): If a clause contains exactly one unassigned literal (a unit clause), that literal must be True (otherwise the clause is immediately falsified). Assign it and simplify. This often cascades — one forced assignment creates new unit clauses.

Rule 2 — Pure Literal Elimination (PLE): If a variable appears in the formula with only one polarity (always positive, or always negative, across all remaining unsatisfied clauses), assigning it to satisfy those clauses can only help, never hurt. Assign it to make those clauses true.

Rule 3 — Splitting (Branching): If neither rule fires, pick an unassigned variable and branch: try True in one recursive call, False in the other. If the True branch fails, backtrack and try False.

flowchart TD
  A([Start: CNF formula F, assignment α]) --> B{All clauses satisfied?}
  B -- Yes --> SAT([Return SAT with α])
  B -- No --> C{Any clause empty?}
  C -- Yes --> UNSAT([Return UNSAT — backtrack])
  C -- No --> D{Unit clause exists?}
  D -- Yes --> E[Unit Propagation: force literal l, simplify F]
  E --> A
  D -- No --> F{Pure literal exists?}
  F -- Yes --> G[Pure Literal Elimination: assign variable, simplify F]
  G --> A
  F -- No --> H[Pick unassigned variable x]
  H --> I[Try x = True → recurse]
  I -- SAT --> SAT
  I -- UNSAT --> J[Try x = False → recurse]
  J --> A
DPLL control flow
Show the formal recursive pseudocode
function DPLL(F, α):
  if all clauses in F are satisfied by α:  return SAT(α)
  if some clause in F is empty:            return UNSAT
  if F has a unit clause {l}:
    return DPLL(simplify(F, l), α ∪ {lit(l) = True})
  if F has a pure literal l:
    return DPLL(simplify(F, l), α ∪ {lit(l) = True})
  x ← pick_unassigned_variable(F)
  if DPLL(simplify(F, x), α ∪ {x = T}) = SAT: return SAT
  return DPLL(simplify(F, ¬x), α ∪ {x = F})

simplify(F, l) removes every clause containing l (they are now satisfied) and removes ¬l from every remaining clause (that literal is now forced False).

Tracing DPLL by Hand

Let us trace DPLL on our padlock formula from the opening section:

Step 0 — Initial state. Three clauses, no assignments. No unit clause (each clause has 2 literals). Check for pure literals: A appears positive and negative (in clauses 1 and 2), B appears positive and negative (clauses 1 and 3), C appears positive and negative (clauses 2 and 3). No pure literal either. We must split.

Step 1 — Split on A = True. Simplify:

  • (A ∨ B): contains A (True) → satisfied, remove.
  • (¬A ∨ C): ¬A is False, remove it → remaining clause: (C) — a unit clause!
  • (¬B ∨ ¬C): unchanged.

Remaining formula: (C) ∧ (¬B ∨ ¬C)

Step 2 — Unit propagation: C = True. (C) is a unit clause, force C = True. Simplify:

  • (C): satisfied, remove.
  • (¬B ∨ ¬C): ¬C is False, remove it → remaining: (¬B) — another unit clause!

Remaining formula: (¬B)

Step 3 — Unit propagation: B = False. (¬B) forces B = False. All clauses are now satisfied.

Result: SAT with A = True, C = True, B = False.

Full DPLL trace on the padlock formula

StepRuleAssignment addedFormula state
0Split on AA = T(C) ∧ (¬B ∨ ¬C)
1Unit propagationC = T(¬B)
2Unit propagationB = F(empty — all satisfied)
SATA=T, B=F, C=T

Notice we never had to backtrack. Unit propagation cascaded through the entire problem once we committed to A = True.

Common misconception

DPLL always needs to explore both branches of every split.

What's actually true

Unit propagation frequently collapses entire sub-trees without branching. In the trace above, one split on A immediately triggered two cascaded unit propagations that resolved the entire formula — no backtracking needed. In practice, strong unit propagation means DPLL explores far fewer branches than naive enumeration.

Now step through the algorithm yourself on several different formulas using the interactive widget below.

Step through DPLL on three different CNF formulas. Observe how unit propagation and pure-literal elimination collapse branches before splitting.

Check your understanding

In the padlock trace above, what forced B = False without any branching on B?

Why DPLL Matters — The Foundation of Modern Solvers

DPLL from 1962 is not, by itself, the solver inside CP-SAT. But it is the architectural skeleton on which every modern SAT solver is built. Understanding DPLL gives you the vocabulary to understand everything that came after.

  1. 1960

    Davis–Putnam procedure

    Resolution-based procedure. Exponential memory; rarely used today.

  2. 1962

    DPLL

    Davis, Logemann, Loveland replace resolution with backtracking + unit propagation. Memory-linear. Still the canonical algorithm.

  3. 1996–99

    GRASP / CDCL

    Marques-Silva & Sakallah introduce Conflict-Driven Clause Learning. Each conflict generates a new clause that prevents revisiting the same bad decision. Industrial SAT is born.

  4. 2001–05

    MiniSat, zChaff, Glucose

    Modern CDCL solvers dominate SAT competitions. Millions of variables, real-time performance.

  5. 2011–now

    CP-SAT (OR-Tools)

    Google's CP-SAT solver uses a CDCL SAT core augmented with CP propagators. Routinely handles scheduling problems with tens of thousands of variables.

[GRASP: A Search Algorithm for Propositional Satisfiability]

The jump from DPLL to industrial CDCL solvers has two key ingredients:

  1. Clause learning: when a branch fails, analyse why it failed and add a new clause capturing that conflict. Future searches avoid the same dead end without re-exploring it.
  2. Non-chronological backjumping: instead of always undoing the most recent decision, jump back to the earliest decision that actually caused the conflict.
[Artificial Intelligence: A Modern Approach (4th ed.), Chapter 7]

The SAT solver inside CP-SAT is a custom CDCL implementation called Glucose-style SAT augmented with lazy clause propagation and watched literals — a data structure trick that makes unit propagation run in near-linear time on large formulas. Every time CP-SAT searches a timetabling constraint, it is running millions of unit propagations per second. [CP-SAT Solver Documentation — OR-Tools]

DPLL (1962) CDCL (1996+)
Core search Backtracking with UP + PLEBacktracking with UP + PLE + clause learning
On conflict Chronological backtrackAnalyse conflict, learn clause, non-chronological backjump
Formula size Grows only by decisionsGrows by learned clauses (managed by deletion heuristics)
Practical scale Hundreds of variablesMillions of variables
Completeness CompleteComplete
DPLL vs modern CDCL

Check your understanding

Which property makes DPLL (and CDCL) complete — guaranteed to find a solution or prove none exists?

Check your understandingQ 1 / 4

A CNF formula has three clauses: (A), (¬A ∨ B), (¬B). What does DPLL conclude after applying unit propagation?