The Algorithm
The basic backtracking algorithm runs by choosing a literal, assigning a truth value to it, simplifying the formula and then recursively checking if the simplified formula is satisfiable; if this is the case, the original formula is satisfiable; otherwise, the same recursive check is done assuming the opposite truth value. This is known as the splitting rule, as it splits the problem into two simpler sub-problems. The simplification step essentially removes all clauses which become true under the assignment from the formula, and all literals that become false from the remaining clauses.
The DPLL algorithm enhances over the backtracking algorithm by the eager use of the following rules at each step:
- Unit propagation
- If a clause is a unit clause, i.e. it contains only a single unassigned literal, this clause can only be satisfied by assigning the necessary value to make this literal true. Thus, no choice is necessary. In practice, this often leads to deterministic cascades of units, thus avoiding a large part of the native search space.
- Pure literal elimination
- If a propositional variable occurs with only one polarity in the formula, it is called pure. Pure literals can always be assigned in a way that makes all clauses containing them true. Thus, these clauses do not constrain the search anymore and can be deleted.
Unsatisfiability of a given partial assignment is detected if one clause becomes empty, i.e. if all its variables have been assigned in a way that makes the corresponding literals false. Satisfiability of the formula is detected either when all variables are assigned without generating the empty clause, or, in modern implementations, if all clauses are satisfied. Unsatisfiability of the complete formula can only be detected after exhaustive search.
The DPLL algorithm can be summarized in the following pseudocode, where Φ is the CNF formula:
Algorithm DPLL Input: A set of clauses Φ. Output: A Truth Value. function DPLL(Φ) if Φ is a consistent set of literals then return true; if Φ contains an empty clause then return false; for every unit clause l in Φ Φ ← unit-propagate(l, Φ); for every literal l that occurs pure in Φ Φ ← pure-literal-assign(l, Φ); l ← choose-literal(Φ); return DPLL(Φ ∧ l) or DPLL(Φ ∧ not(l));In this pseudocode, unit-propagate(l, Φ)
and pure-literal-assign(l, Φ)
are functions that return the result of applying unit propagation and the pure literal rule, respectively, to the literal l
and the formula Φ
. In other words, they replace every occurrence of l
with "true" and every occurrence of not l
with "false" in the formula Φ
, and simplify the resulting formula. The pseudocode DPLL function only returns whether the final assignment satisfies the formula or not. In a real implementation, the partial satisfying assignment typically is also returned on success; this can be derived from the consistent set of literals of the first if
statement of the function.
The Davis–Logemann–Loveland algorithm depends on the choice of branching literal, which is the literal considered in the backtracking step. As a result, this is not exactly an algorithm, but rather a family of algorithms, one for each possible way of choosing the branching literal. Efficiency is strongly affected by the choice of the branching literal: there exist instances for which the running time is constant or exponential depending on the choice of the branching literals. Such choice functions are also called heuristic functions or branching heuristics.
Read more about this topic: DPLL Algorithm