123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- """
- Functions and wrapper object to call assumption property and predicate
- query with same syntax.
- In SymPy, there are two assumption systems. Old assumption system is
- defined in sympy/core/assumptions, and it can be accessed by attribute
- such as ``x.is_even``. New assumption system is defined in
- sympy/assumptions, and it can be accessed by predicates such as
- ``Q.even(x)``.
- Old assumption is fast, while new assumptions can freely take local facts.
- In general, old assumption is used in evaluation method and new assumption
- is used in refinement method.
- In most cases, both evaluation and refinement follow the same process, and
- the only difference is which assumption system is used. This module provides
- ``is_[...]()`` functions and ``AssumptionsWrapper()`` class which allows
- using two systems with same syntax so that parallel code implementation can be
- avoided.
- Examples
- ========
- For multiple use, use ``AssumptionsWrapper()``.
- >>> from sympy import Q, Symbol
- >>> from sympy.assumptions.wrapper import AssumptionsWrapper
- >>> x = Symbol('x')
- >>> _x = AssumptionsWrapper(x, Q.even(x))
- >>> _x.is_integer
- True
- >>> _x.is_odd
- False
- For single use, use ``is_[...]()`` functions.
- >>> from sympy.assumptions.wrapper import is_infinite
- >>> a = Symbol('a')
- >>> print(is_infinite(a))
- None
- >>> is_infinite(a, Q.finite(a))
- False
- """
- from sympy.assumptions import ask, Q
- from sympy.core.basic import Basic
- from sympy.core.sympify import _sympify
- def make_eval_method(fact):
- def getit(self):
- try:
- pred = getattr(Q, fact)
- ret = ask(pred(self.expr), self.assumptions)
- return ret
- except AttributeError:
- return None
- return getit
- # we subclass Basic to use the fact deduction and caching
- class AssumptionsWrapper(Basic):
- """
- Wrapper over ``Basic`` instances to call predicate query by
- ``.is_[...]`` property
- Parameters
- ==========
- expr : Basic
- assumptions : Boolean, optional
- Examples
- ========
- >>> from sympy import Q, Symbol
- >>> from sympy.assumptions.wrapper import AssumptionsWrapper
- >>> x = Symbol('x', even=True)
- >>> AssumptionsWrapper(x).is_integer
- True
- >>> y = Symbol('y')
- >>> AssumptionsWrapper(y, Q.even(y)).is_integer
- True
- With ``AssumptionsWrapper``, both evaluation and refinement can be supported
- by single implementation.
- >>> from sympy import Function
- >>> class MyAbs(Function):
- ... @classmethod
- ... def eval(cls, x, assumptions=True):
- ... _x = AssumptionsWrapper(x, assumptions)
- ... if _x.is_nonnegative:
- ... return x
- ... if _x.is_negative:
- ... return -x
- ... def _eval_refine(self, assumptions):
- ... return MyAbs.eval(self.args[0], assumptions)
- >>> MyAbs(x)
- MyAbs(x)
- >>> MyAbs(x).refine(Q.positive(x))
- x
- >>> MyAbs(Symbol('y', negative=True))
- -y
- """
- def __new__(cls, expr, assumptions=None):
- if assumptions is None:
- return expr
- obj = super().__new__(cls, expr, _sympify(assumptions))
- obj.expr = expr
- obj.assumptions = assumptions
- return obj
- _eval_is_algebraic = make_eval_method("algebraic")
- _eval_is_antihermitian = make_eval_method("antihermitian")
- _eval_is_commutative = make_eval_method("commutative")
- _eval_is_complex = make_eval_method("complex")
- _eval_is_composite = make_eval_method("composite")
- _eval_is_even = make_eval_method("even")
- _eval_is_extended_negative = make_eval_method("extended_negative")
- _eval_is_extended_nonnegative = make_eval_method("extended_nonnegative")
- _eval_is_extended_nonpositive = make_eval_method("extended_nonpositive")
- _eval_is_extended_nonzero = make_eval_method("extended_nonzero")
- _eval_is_extended_positive = make_eval_method("extended_positive")
- _eval_is_extended_real = make_eval_method("extended_real")
- _eval_is_finite = make_eval_method("finite")
- _eval_is_hermitian = make_eval_method("hermitian")
- _eval_is_imaginary = make_eval_method("imaginary")
- _eval_is_infinite = make_eval_method("infinite")
- _eval_is_integer = make_eval_method("integer")
- _eval_is_irrational = make_eval_method("irrational")
- _eval_is_negative = make_eval_method("negative")
- _eval_is_noninteger = make_eval_method("noninteger")
- _eval_is_nonnegative = make_eval_method("nonnegative")
- _eval_is_nonpositive = make_eval_method("nonpositive")
- _eval_is_nonzero = make_eval_method("nonzero")
- _eval_is_odd = make_eval_method("odd")
- _eval_is_polar = make_eval_method("polar")
- _eval_is_positive = make_eval_method("positive")
- _eval_is_prime = make_eval_method("prime")
- _eval_is_rational = make_eval_method("rational")
- _eval_is_real = make_eval_method("real")
- _eval_is_transcendental = make_eval_method("transcendental")
- _eval_is_zero = make_eval_method("zero")
- # one shot functions which are faster than AssumptionsWrapper
- def is_infinite(obj, assumptions=None):
- if assumptions is None:
- return obj.is_infinite
- return ask(Q.infinite(obj), assumptions)
- def is_extended_real(obj, assumptions=None):
- if assumptions is None:
- return obj.is_extended_real
- return ask(Q.extended_real(obj), assumptions)
- def is_extended_nonnegative(obj, assumptions=None):
- if assumptions is None:
- return obj.is_extended_nonnegative
- return ask(Q.extended_nonnegative(obj), assumptions)
|