def test_check_of_true_in_or(self): """ Tests simplifying a formula that has true in or """ p = bf.Or( [ bf.Var("a"), bf.Var("b"), bf.Fls(), bf.And([bf.Var("b"), bf.Var("a")]), bf.Or([bf.Var("b"), bf.Var("a")]), bf.Tru(), ] ) result = bf.Tru() self.assertEqual(result, au.simplify(p), "Invalid simplification, expected same as result.") p = bf.Or( [ bf.Var("a"), bf.Var("b"), bf.And([bf.Var("b"), bf.Var("a")]), bf.Or([bf.Var("b"), bf.Var("a"), bf.Tru(), bf.Fls()]), bf.Tru(), ] ) result = bf.Tru() self.assertEqual(result, au.simplify(p), "Invalid simplification, expected same as result.")
def SAT_solver_brute_force(CNF_formula, dictionary): """ Solves SAT problem by trying all the possibilities for variables in formula. """ if isinstance(CNF_formula, bf.Tru): #Formula is Tru / satisfiable - return dictionary with given values of variables return dictionary elif isinstance(CNF_formula, bf.Fls): # Formula is Fls -/ not satisfiable - return None return None else: # Take first variable and set its value to True variables = au.extract_variables(CNF_formula) dictionary[variables[0]] = bf.Tru() simplified_formula = CNF_formula.replace(dictionary) simplified_formula = au.simplify(simplified_formula) result = SAT_solver_brute_force(simplified_formula, dictionary) if result is not None: # Return dictionary if formula is satisfiable return result else: # Set same variable to False and try to solve again again dictionary[variables[0]] = bf.Fls() # replace and simplify formula simplified_formula = au.simplify(CNF_formula.replace(dictionary) ) return SAT_solver_brute_force(simplified_formula, dictionary)
def test_not_and(self): """ Tests simplifying a formula that changes an And to a Or. """ p = bf.Not(bf.And([bf.Tru(), bf.Tru(), bf.Tru(), bf.Not(bf.Tru()), bf.Not(bf.Var("a"))])) self.assertEqual(bf.Tru(), au.simplify(p), "Invalid simplification, expected Tru.") p = bf.Not(bf.And([bf.Tru(), bf.Tru(), bf.Tru(), bf.Not(bf.Fls()), bf.Not(bf.Var("a"))])) self.assertEqual(bf.Var("a"), au.simplify(p), "Invalid simplification, expected Var 'a'.")
def test_not_or(self): """ Tests simplifying a formula that changes an Or to a And. """ p = bf.Not(bf.Or([bf.Tru(), bf.Tru(), bf.Tru(), bf.Not(bf.Tru()), bf.Not(bf.Var("a"))])) self.assertEqual(bf.Fls(), au.simplify(p), "Invalid simplification, expected Fls.") p = bf.Not(bf.Or([bf.Fls(), bf.Fls(), bf.Fls(), bf.Not(bf.Tru()), bf.Not(bf.Var("a"))])) self.assertEqual(bf.Var("a"), au.simplify(p), "Invalid simplification, expected Var 'a'.")
def DPLL(formula): """ Implementation of DPLL - argument is formula in CNF form. Returns False if formula is not in SAT or values of variables otherwise. """ CNF_formula = au.simplify(au.cnf_nnf(formula)) values = {} while True: if isinstance(CNF_formula, bf.Tru) or isinstance(CNF_formula, bf.Fls) or isinstance(CNF_formula, bf.Var) or isinstance(CNF_formula, bf.Not): # Formula is only True, False, Var or negated Var - no more pure vars / literals, we finished break temp_value = {} #Always check only for first clause in formula - sequence is F, T, Var, Not, And clause = CNF_formula.formulas[0] if isinstance(clause, bf.Var): #It is only literal - Var values[clause.name] = bf.Tru() temp_value[clause.name] = bf.Tru() elif isinstance(clause, bf.Not): # It is only literal - negated Var values[clause.formula.name] = bf.Fls() temp_value[clause.formula.name] = bf.Fls() if temp_value: #We found literal - replace formula with its value, simplify, put in cnf and look for literal again replaced_formula = CNF_formula.replace(temp_value) formula_simplified = au.simplify(replaced_formula) CNF_formula = au.cnf_nnf(formula_simplified) else: #finish, no more literals break #Check for pure variables pure_var_values = au.pure_variables(CNF_formula) replaced_formula = CNF_formula.replace(pure_var_values) formula_simplified = au.simplify(replaced_formula) CNF_formula = au.cnf_nnf(formula_simplified) #Solve the rest of formula by brute force values_brute_force = SAT_solver_brute_force(CNF_formula, {}) if values_brute_force is not None: # satisfiable problem return dict(values.items() + pure_var_values.items() + values_brute_force.items()) else: # unsatisfiable problem return False
def test_using_absorptions(self): """ Tests simplifying a formula that uses absorptions. """ p1 = bf.And([bf.Var("a"), bf.And([bf.Var("b"), bf.Var("a")]), bf.Or([bf.Var("c"), bf.Var("b")])]) p2 = bf.Or([bf.Var("a"), bf.And([bf.Var("b"), bf.Var("a")]), bf.Or([bf.Var("c"), bf.Var("b")])]) p = bf.And([p2, bf.Not(bf.And([bf.Tru(), bf.Tru(), bf.Tru(), bf.Not(bf.Tru()), bf.Not(bf.Var("a")), p1]))]) result = bf.Or([bf.Var("a"), bf.Var("b"), bf.Var("c"), bf.And([bf.Var("a"), bf.Var("b")])]) self.assertEqual( result, au.simplify(p, use_absorptions=True), "Invalid simplification, expected same as result." )
# Or or1 = bf.Or([x1, x2, x3, x4]) or2 = bf.Or([x1, bf.Or([x1, x2, x3, x4]), x4, x3, x2]) # this is equivalent to bf.Or([x1, x1, x2, x3, x4, x4, x3, x2]) or3 = bf.Or([]) # bf.Or([]) is equivalent to bf.Fls() # Examples of using the nnf method print "NNF EXAMPLES:" print au.nnf(bf.Not(bf.Not(bf.Var("b")))) print au.nnf(bf.Or([bf.And([bf.Var("a"), bf.Var("b")]), bf.Var("c")])) print au.nnf(bf.Not(bf.Or([bf.Var("a"), bf.Var("b")]))) print au.nnf(bf.And([bf.Var("a"), bf.And([bf.Var("b"), bf.Var("a")]), bf.Or([bf.Var("c"), bf.Var("b")])])) print "-----------------------------------------------------------------------------------------------------------------\n" # Examples of using the cnf method print "CNF EXAMPLES:" print au.cnf_nnf(bf.Or([bf.Var("b"), bf.Var("c")])) print au.cnf_nnf(bf.And([bf.Not(bf.Var("a")), bf.Or([bf.Var("b"), bf.Var("c")])])) print au.cnf_nnf(bf.And([bf.Var("a"), bf.Or([bf.Var("b"), bf.And([bf.Var("c"), bf.Var("d")])])])) print au.cnf_nnf(bf.Not(bf.Or([bf.Var("a"), bf.Var("b"), bf.Not(bf.Fls())]))) print "-----------------------------------------------------------------------------------------------------------------\n" # Examples of using the simplify method print "SIMPLIFY EXAMPLES:" print au.simplify(bf.Not(bf.Or([bf.Var("b"), bf.Var("c")]))) print au.simplify(bf.And([bf.Not(bf.Var("a")), bf.Or([bf.Var("b"), bf.Var("c")])])) print au.simplify(bf.And([bf.Var("a"), bf.Or([bf.Var("b"), bf.Tru(), bf.And([bf.Fls(), bf.Var("c"), bf.Var("d")])])])) print au.simplify(bf.Not(bf.Or([bf.Var("a"), bf.Var("b"), bf.Not(bf.Fls())]))) print "-----------------------------------------------------------------------------------------------------------------\n"
def test_false_in_and(self): """ Tests simplifying a formula that contains Fls in And. Result must be Fls'. """ p = bf.And([bf.Tru(), bf.Tru(), bf.Tru(), bf.Not(bf.Tru()), bf.Var("a")]) self.assertEqual(bf.Fls(), au.simplify(p), "Invalid simplification, expected Tru.")
def test_remove_true_from_and(self): """ Tests simplifying a formula that contains Tru in And. Result must be Var 'a'. """ p = bf.And([bf.Tru(), bf.Tru(), bf.Tru(), bf.Not(bf.Fls()), bf.Var("a")]) self.assertEqual(bf.Var("a"), au.simplify(p), "Invalid simplification, expected Var 'a'.")
def test_true_in_or(self): """ Tests simplifying a formula that contains Tru in Or. Result must be True. """ p = bf.Or([bf.Fls(), bf.Tru(), bf.Fls(), bf.Not(bf.Tru()), bf.Var("a")]) self.assertEqual(bf.Tru(), au.simplify(p), "Invalid simplification, expected Tru.")
def test_false(self): """ Tests simplifying a formula that is already simplified. Result must be Fls. """ p = bf.Fls() self.assertEqual(bf.Fls(), au.simplify(p), "Invalid simplification, expected Fls.")
def test_true(self): """ Tests simplifying a formula that is already simplified. Result must be Tru. """ p = bf.Tru() self.assertEqual(bf.Tru(), au.simplify(p), "Invalid simplification, expected Tru.")