Spaces:
Sleeping
Sleeping
File size: 5,434 Bytes
6a86ad5 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
"""
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):
pred = getattr(Q, fact)
ret = ask(pred(self.expr), self.assumptions)
return ret
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)
|