@@ -309,7 +309,7 @@ def parse_definite_clause(s):
309309
310310## Useful constant Exprs used in examples and code:
311311TRUE , FALSE , ZERO , ONE , TWO = map (Expr , ['TRUE' , 'FALSE' , 0 , 1 , 2 ])
312- A , B , C , F , G , P , Q , x , y , z = map (Expr , 'ABCFGPQxyz ' )
312+ A , B , C , D , E , F , G , P , Q , x , y , z = map (Expr , 'ABCDEFGPQxyz ' )
313313
314314#______________________________________________________________________________
315315
@@ -683,33 +683,50 @@ def find_pure_symbol(symbols, clauses):
683683 return None , None
684684
685685def find_unit_clause (clauses , model ):
686- """A unit clause has only 1 variable that is not bound in the model.
687- >>> find_unit_clause([A|B|C, B|~C, A|~B], {A:True})
686+ """Find a forced assignment if possible from a clause with only 1
687+ variable not bound in the model.
688+ >>> find_unit_clause([A|B|C, B|~C, ~A|~B], {A:True})
688689 (B, False)
689690 """
690691 for clause in clauses :
691- num_not_in_model = 0
692- for literal in disjuncts (clause ):
693- sym = literal_symbol (literal )
694- if sym not in model :
695- num_not_in_model += 1
696- P , value = sym , (literal .op != '~' )
697- if num_not_in_model == 1 :
698- return P , value
692+ P , value = unit_clause_assign (clause , model )
693+ if P : return P , value
699694 return None , None
700695
701-
702- def literal_symbol (literal ):
703- """The symbol in this literal (without the negation).
704- >>> literal_symbol(P)
705- P
706- >>> literal_symbol(~P)
707- P
696+ def unit_clause_assign (clause , model ):
697+ """Return a single variable/value pair that makes clause true in
698+ the model, if possible.
699+ >>> unit_clause_assign(A|B|C, {A:True})
700+ (None, None)
701+ >>> unit_clause_assign(B|~C, {A:True})
702+ (None, None)
703+ >>> unit_clause_assign(~A|~B, {A:True})
704+ (B, False)
705+ """
706+ P , value = None , None
707+ for literal in disjuncts (clause ):
708+ sym , positive = inspect_literal (literal )
709+ if sym in model :
710+ if model [sym ] == positive :
711+ return None , None # clause already True
712+ elif P :
713+ return None , None # more than 1 unbound variable
714+ else :
715+ P , value = sym , positive
716+ return P , value
717+
718+ def inspect_literal (literal ):
719+ """The symbol in this literal, and the value it should take to
720+ make the literal true.
721+ >>> inspect_literal(P)
722+ (P, True)
723+ >>> inspect_literal(~P)
724+ (P, False)
708725 """
709726 if literal .op == '~' :
710- return literal .args [0 ]
727+ return literal .args [0 ], False
711728 else :
712- return literal
729+ return literal , True
713730
714731#______________________________________________________________________________
715732# Walk-SAT [Fig. 7.18]
@@ -1153,6 +1170,10 @@ class logicTest: """
11531170>>> tt_true(A & B)
11541171False
11551172
1173+ ### An earlier version of the code failed on this:
1174+ >>> dpll_satisfiable(A & ~B & C & (A | ~D) & (~E | ~D) & (C | ~D) & (~A | ~F) & (E | ~F) & (~D | ~F) & (B | ~C | D) & (A | ~E | F) & (~A | E | D))
1175+ {B: False, C: True, A: True, F: False, D: True, E: False}
1176+
11561177### [Fig. 7.13]
11571178>>> alpha = expr("~P12")
11581179>>> to_cnf(Fig[7,13] & ~alpha)
0 commit comments