DPLL an iterative implementation -------------------------------- UPstack -- holds records for the form topUPstack pointer to empty slot on stack. UPptr pointer to next literal to unit propagate pushUPstack(lit l, clause c) dlevel(l) = DLEVEL val[l] = true val[neg(l)] = true UPstack[topUPstack++] = InitDP() //call before DP forall unit clauses u=(l) pushUPstack(l, u) DP int DLEVEL=1; //Decision level while(1) { conflict = UP(); if(conflict != 0) { learnConflictAndBackTrack(conflict) if DLEVEL = 0 break; } else { DLEVEL++; lit = chooseNxtlit() if(lit != NO_MORE_LITS) pushUPstack(lit,0); //a zero reason else break; //finished with a SAT result. } } if DLEVEL == 0 report UNSAT else UPstack contains satisfying assignment. UP() performs unit propagation. some number of new literals have entered the stack (from UPptr to topUPstack) all of these literals are newly true. We must find all clauses that have newly become unit, and put their unit lit on the UPstack. State of the art performance: 100,000 variables, 500,000 clauses and 1M extra clauses (long) learned during solving, solution times of about 2500 sec, searching trees of with about 3M branches. Can't achieve this performance if we visit every clause containing the assigned variable. Here is where watch literals come into play. updateWatch(l1, c) //the watch l1 of c just became false. check c's other watch l2. If true, keep l1 as a watch for c return Search c for another literal l3 that is not false (true or unassigned) if found remove c from l1's watch list add c to l3's watch list. return Note this switch from l1 to l3 does not need to be undone on backtrack (if l3 is a non-false watch at this node then it is a non-false watch at every ancestor node). else if l2 = unassigned pushUPstack(l2, c) (the clause that forced l2) else if l2 = false return C as conflict. UP() while(UPptr < topUPstack) lit = UPstack[UPptr++].l for each c on lit's watch list conflict = updatewatch(lit,c) if conflict != 0 return conflict //c is returned as a conflict if no literal Observation. Every clause in the UPstack (clauses that forced members of the stack, consists of (a) a literal on the stack (the literal it forced). (b) literals made false higher up the stack than the forced literal. learnConflictAndBackTrack(conflict) //all of the literals in conflict are falsified in current branch //learn a conflict clause, backtrack, and assert a new unit //propagant. //learns a 1-UIP clause (we will explain this later) new1UIP = {} nlits = 0; forall lit \in conflict if dlevel(lit) < DLEVEL new1UIP = new1UIP \union lit else inconflict(not(lit)) = true; nlits++; while(nlits > 1) lit = UPstack[--topUPStack].l; val[lit] = UNSET; if inconflict(lit) nlits--; inconflict(lit) = false; c = UPstack[topUPStack].c forall x in c if dlevel(x) < DLEVEL new1UIP = new1UIP \union x else if(!inconflict(not(x)) & x != lit) inconflict(not(x)) = true nlits++; AssertinLit = lit in new1UIP that is deepest on UPStack BTLevel = dlevel(assertinglit) while(!inconflict(UPstack[--topUPStack].l)) val[UPstack[topUPStack]] = UNSET; UPlit = not(UPstack[topUPStack].l) new1UIP = new1UIP \union UPlit inconflict(not(UPlit)) = false; val[not(UPlit)] = UNSET; while(dlevel(UPStack[--topUPStack] > BTLevel) val[UPstack[topUPStack]] = UNSET; DLEVEL = BTLevel storeClause(AssertingLit,UPlit, new1UIP) pushUPstack(UPlit, new1UIP) return.