def test_to_CNF(): assert CNF.CNF_to_cnf(CNF.to_CNF(~(B | C))) == to_cnf(~(B | C)) assert CNF.CNF_to_cnf(CNF.to_CNF((A & B) | C)) == to_cnf((A & B) | C) assert CNF.CNF_to_cnf(CNF.to_CNF(A >> B)) == to_cnf(A >> B) assert CNF.CNF_to_cnf(CNF.to_CNF(A >> (B & C))) == to_cnf(A >> (B & C)) assert CNF.CNF_to_cnf(CNF.to_CNF(A & (B | C) | ~A & (B | C))) == to_cnf(A & (B | C) | ~A & (B | C)) assert CNF.CNF_to_cnf(CNF.to_CNF(A & B)) == to_cnf(A & B)
def ask(proposition, assumptions=True, context=global_assumptions): """ Method for inferring properties about objects. **Syntax** * ask(proposition) * ask(proposition, assumptions) where ``proposition`` is any boolean expression Examples ======== >>> from sympy import ask, Q, pi >>> from sympy.abc import x, y >>> ask(Q.rational(pi)) False >>> ask(Q.even(x*y), Q.even(x) & Q.integer(y)) True >>> ask(Q.prime(4*x), Q.integer(x)) False **Remarks** Relations in assumptions are not implemented (yet), so the following will not give a meaningful result. >>> ask(Q.positive(x), Q.is_true(x > 0)) It is however a work in progress. """ from sympy.assumptions.satask import satask if not isinstance(proposition, (BooleanFunction, AppliedPredicate, bool, BooleanAtom)): raise TypeError("proposition must be a valid logical expression") if not isinstance(assumptions, (BooleanFunction, AppliedPredicate, bool, BooleanAtom)): raise TypeError("assumptions must be a valid logical expression") if isinstance(proposition, AppliedPredicate): key, expr = proposition.func, sympify(proposition.arg) else: key, expr = Q.is_true, sympify(proposition) assump = CNF.from_prop(assumptions) assump.extend(context) local_facts = _extract_all_facts(assump, expr) known_facts_cnf = get_all_known_facts() known_facts_dict = get_known_facts_dict() enc_cnf = EncodedCNF() enc_cnf.from_cnf(CNF(known_facts_cnf)) enc_cnf.add_from_cnf(local_facts) if local_facts.clauses and satisfiable(enc_cnf) is False: raise ValueError("inconsistent assumptions %s" % assumptions) if local_facts.clauses: local_facts_ = CNF.CNF_to_cnf(local_facts) # See if there's a straight-forward conclusion we can make for the inference if local_facts_.is_Atom: if key in known_facts_dict[local_facts_]: return True if Not(key) in known_facts_dict[local_facts_]: return False elif (isinstance(local_facts_, And) and all(k in known_facts_dict for k in local_facts_.args)): for assum in local_facts_.args: if assum.is_Atom: if key in known_facts_dict[assum]: return True if Not(key) in known_facts_dict[assum]: return False elif isinstance(assum, Not) and assum.args[0].is_Atom: if key in known_facts_dict[assum]: return False if Not(key) in known_facts_dict[assum]: return True elif (isinstance(key, Predicate) and isinstance(local_facts_, Not) and local_facts_.args[0].is_Atom): if local_facts_.args[0] in known_facts_dict[key]: return False # direct resolution method, no logic res = key(expr)._eval_ask(assumptions) if res is not None: return bool(res) # using satask (still costly) res = satask(proposition, assumptions=assumptions, context=context) return res