""" This module defines base class for handlers and some core handlers: ``Q.commutative`` and ``Q.is_true``. """ from sympy.assumptions import Q, ask, AppliedPredicate from sympy.core import Basic, Symbol from sympy.core.logic import _fuzzy_group from sympy.core.numbers import NaN, Number from sympy.logic.boolalg import (And, BooleanTrue, BooleanFalse, conjuncts, Equivalent, Implies, Not, Or) from sympy.utilities.exceptions import sympy_deprecation_warning from ..predicates.common import CommutativePredicate, IsTruePredicate class AskHandler: """Base class that all Ask Handlers must inherit.""" def __new__(cls, *args, **kwargs): sympy_deprecation_warning( """ The AskHandler system is deprecated. The AskHandler class should be replaced with the multipledispatch handler of Predicate """, deprecated_since_version="1.8", active_deprecations_target='deprecated-askhandler', ) return super().__new__(cls, *args, **kwargs) class CommonHandler(AskHandler): # Deprecated """Defines some useful methods common to most Handlers. """ @staticmethod def AlwaysTrue(expr, assumptions): return True @staticmethod def AlwaysFalse(expr, assumptions): return False @staticmethod def AlwaysNone(expr, assumptions): return None NaN = AlwaysFalse # CommutativePredicate @CommutativePredicate.register(Symbol) def _(expr, assumptions): """Objects are expected to be commutative unless otherwise stated""" assumps = conjuncts(assumptions) if expr.is_commutative is not None: return expr.is_commutative and not ~Q.commutative(expr) in assumps if Q.commutative(expr) in assumps: return True elif ~Q.commutative(expr) in assumps: return False return True @CommutativePredicate.register(Basic) def _(expr, assumptions): for arg in expr.args: if not ask(Q.commutative(arg), assumptions): return False return True @CommutativePredicate.register(Number) def _(expr, assumptions): return True @CommutativePredicate.register(NaN) def _(expr, assumptions): return True # IsTruePredicate @IsTruePredicate.register(bool) def _(expr, assumptions): return expr @IsTruePredicate.register(BooleanTrue) def _(expr, assumptions): return True @IsTruePredicate.register(BooleanFalse) def _(expr, assumptions): return False @IsTruePredicate.register(AppliedPredicate) def _(expr, assumptions): return ask(expr, assumptions) @IsTruePredicate.register(Not) def _(expr, assumptions): arg = expr.args[0] if arg.is_Symbol: # symbol used as abstract boolean object return None value = ask(arg, assumptions=assumptions) if value in (True, False): return not value else: return None @IsTruePredicate.register(Or) def _(expr, assumptions): result = False for arg in expr.args: p = ask(arg, assumptions=assumptions) if p is True: return True if p is None: result = None return result @IsTruePredicate.register(And) def _(expr, assumptions): result = True for arg in expr.args: p = ask(arg, assumptions=assumptions) if p is False: return False if p is None: result = None return result @IsTruePredicate.register(Implies) def _(expr, assumptions): p, q = expr.args return ask(~p | q, assumptions=assumptions) @IsTruePredicate.register(Equivalent) def _(expr, assumptions): p, q = expr.args pt = ask(p, assumptions=assumptions) if pt is None: return None qt = ask(q, assumptions=assumptions) if qt is None: return None return pt == qt #### Helper methods def test_closed_group(expr, assumptions, key): """ Test for membership in a group with respect to the current operation. """ return _fuzzy_group( (ask(key(a), assumptions) for a in expr.args), quick_exit=True)