def get_all_relevant_facts(proposition, assumptions=True, context=global_assumptions, use_known_facts=True, iterations=oo): # The relevant facts might introduce new keys, e.g., Q.zero(x*y) will # introduce the keys Q.zero(x) and Q.zero(y), so we need to run it until # we stop getting new things. Hopefully this strategy won't lead to an # infinite loop in the future. i = 0 relevant_facts = set() exprs = None all_exprs = set() while exprs != set(): exprs, relevant_facts = get_relevant_facts( proposition, assumptions, context, exprs=exprs, relevant_facts=relevant_facts) all_exprs |= exprs i += 1 if i >= iterations: break if use_known_facts: known_facts_CNF = CNF() known_facts_CNF.add_clauses(get_all_known_facts()) kf_encoded = EncodedCNF() kf_encoded.from_cnf(known_facts_CNF) def translate_literal(lit, delta): if lit > 0: return lit + delta else: return lit - delta def translate_data(data, delta): return [{translate_literal(i, delta) for i in clause} for clause in data] data = [] symbols = [] n_lit = len(kf_encoded.symbols) for i, expr in enumerate(all_exprs): symbols += [pred(expr) for pred in kf_encoded.symbols] data += translate_data(kf_encoded.data, i * n_lit) encoding = dict(list(zip(symbols, range(1, len(symbols) + 1)))) ctx = EncodedCNF(data, encoding) else: ctx = EncodedCNF() for e in relevant_facts: ctx.add_prop(e) return ctx
def minisat22_satisfiable(expr, all_models=False, minimal=False): if not isinstance(expr, EncodedCNF): exprs = EncodedCNF() exprs.add_prop(expr) expr = exprs from pysat.solvers import Minisat22 # Return UNSAT when False (encoded as 0) is present in the CNF if {0} in expr.data: if all_models: return (f for f in [False]) return False r = Minisat22(expr.data) if minimal: r.set_phases([-(i + 1) for i in range(r.nof_vars())]) if not r.solve(): return False if not all_models: return {expr.symbols[abs(lit) - 1]: lit > 0 for lit in r.get_model()} else: # Make solutions sympy compatible by creating a generator def _gen(results): satisfiable = False while results.solve(): sol = results.get_model() yield {expr.symbols[abs(lit) - 1]: lit > 0 for lit in sol} if minimal: results.add_clause([-i for i in sol if i > 0]) else: results.add_clause([-i for i in sol]) satisfiable = True if not satisfiable: yield False raise StopIteration return _gen(r)
def pycosat_satisfiable(expr, all_models=False): import pycosat if not isinstance(expr, EncodedCNF): exprs = EncodedCNF() exprs.add_prop(expr) expr = exprs # Return UNSAT when False (encoded as 0) is present in the CNF if {0} in expr.data: if all_models: return (f for f in [False]) return False if not all_models: r = pycosat.solve(expr.data) result = r != "UNSAT" if not result: return result return dict((expr.symbols[abs(lit) - 1], lit > 0) for lit in r) else: r = pycosat.itersolve(expr.data) result = r != "UNSAT" if not result: return result # Make solutions sympy compatible by creating a generator def _gen(results): satisfiable = False try: while True: sol = next(results) yield dict( (expr.symbols[abs(lit) - 1], lit > 0) for lit in sol) satisfiable = True except StopIteration: if not satisfiable: yield False return _gen(r)
def dpll_satisfiable(expr, all_models=False): """ Check satisfiability of a propositional sentence. It returns a model rather than True when it succeeds. Returns a generator of all models if all_models is True. Examples ======== >>> from sympy.abc import A, B >>> from sympy.logic.algorithms.dpll2 import dpll_satisfiable >>> dpll_satisfiable(A & ~B) {A: True, B: False} >>> dpll_satisfiable(A & ~A) False """ if not isinstance(expr, EncodedCNF): exprs = EncodedCNF() exprs.add_prop(expr) expr = exprs # Return UNSAT when False (encoded as 0) is present in the CNF if {0} in expr.data: if all_models: return (f for f in [False]) return False solver = SATSolver(expr.data, expr.variables, set(), expr.symbols) models = solver._find_model() if all_models: return _all_models(models) try: return next(models) except StopIteration: return False