Coverage for /usr/lib/python3/dist-packages/sympy/assumptions/wrapper.py: 70%
63 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1"""
2Functions and wrapper object to call assumption property and predicate
3query with same syntax.
5In SymPy, there are two assumption systems. Old assumption system is
6defined in sympy/core/assumptions, and it can be accessed by attribute
7such as ``x.is_even``. New assumption system is defined in
8sympy/assumptions, and it can be accessed by predicates such as
9``Q.even(x)``.
11Old assumption is fast, while new assumptions can freely take local facts.
12In general, old assumption is used in evaluation method and new assumption
13is used in refinement method.
15In most cases, both evaluation and refinement follow the same process, and
16the only difference is which assumption system is used. This module provides
17``is_[...]()`` functions and ``AssumptionsWrapper()`` class which allows
18using two systems with same syntax so that parallel code implementation can be
19avoided.
21Examples
22========
24For multiple use, use ``AssumptionsWrapper()``.
26>>> from sympy import Q, Symbol
27>>> from sympy.assumptions.wrapper import AssumptionsWrapper
28>>> x = Symbol('x')
29>>> _x = AssumptionsWrapper(x, Q.even(x))
30>>> _x.is_integer
31True
32>>> _x.is_odd
33False
35For single use, use ``is_[...]()`` functions.
37>>> from sympy.assumptions.wrapper import is_infinite
38>>> a = Symbol('a')
39>>> print(is_infinite(a))
40None
41>>> is_infinite(a, Q.finite(a))
42False
44"""
46from sympy.assumptions import ask, Q
47from sympy.core.basic import Basic
48from sympy.core.sympify import _sympify
51def make_eval_method(fact):
52 def getit(self):
53 try:
54 pred = getattr(Q, fact)
55 ret = ask(pred(self.expr), self.assumptions)
56 return ret
57 except AttributeError:
58 return None
59 return getit
62# we subclass Basic to use the fact deduction and caching
63class AssumptionsWrapper(Basic):
64 """
65 Wrapper over ``Basic`` instances to call predicate query by
66 ``.is_[...]`` property
68 Parameters
69 ==========
71 expr : Basic
73 assumptions : Boolean, optional
75 Examples
76 ========
78 >>> from sympy import Q, Symbol
79 >>> from sympy.assumptions.wrapper import AssumptionsWrapper
80 >>> x = Symbol('x', even=True)
81 >>> AssumptionsWrapper(x).is_integer
82 True
83 >>> y = Symbol('y')
84 >>> AssumptionsWrapper(y, Q.even(y)).is_integer
85 True
87 With ``AssumptionsWrapper``, both evaluation and refinement can be supported
88 by single implementation.
90 >>> from sympy import Function
91 >>> class MyAbs(Function):
92 ... @classmethod
93 ... def eval(cls, x, assumptions=True):
94 ... _x = AssumptionsWrapper(x, assumptions)
95 ... if _x.is_nonnegative:
96 ... return x
97 ... if _x.is_negative:
98 ... return -x
99 ... def _eval_refine(self, assumptions):
100 ... return MyAbs.eval(self.args[0], assumptions)
101 >>> MyAbs(x)
102 MyAbs(x)
103 >>> MyAbs(x).refine(Q.positive(x))
104 x
105 >>> MyAbs(Symbol('y', negative=True))
106 -y
108 """
109 def __new__(cls, expr, assumptions=None):
110 if assumptions is None:
111 return expr
112 obj = super().__new__(cls, expr, _sympify(assumptions))
113 obj.expr = expr
114 obj.assumptions = assumptions
115 return obj
117 _eval_is_algebraic = make_eval_method("algebraic")
118 _eval_is_antihermitian = make_eval_method("antihermitian")
119 _eval_is_commutative = make_eval_method("commutative")
120 _eval_is_complex = make_eval_method("complex")
121 _eval_is_composite = make_eval_method("composite")
122 _eval_is_even = make_eval_method("even")
123 _eval_is_extended_negative = make_eval_method("extended_negative")
124 _eval_is_extended_nonnegative = make_eval_method("extended_nonnegative")
125 _eval_is_extended_nonpositive = make_eval_method("extended_nonpositive")
126 _eval_is_extended_nonzero = make_eval_method("extended_nonzero")
127 _eval_is_extended_positive = make_eval_method("extended_positive")
128 _eval_is_extended_real = make_eval_method("extended_real")
129 _eval_is_finite = make_eval_method("finite")
130 _eval_is_hermitian = make_eval_method("hermitian")
131 _eval_is_imaginary = make_eval_method("imaginary")
132 _eval_is_infinite = make_eval_method("infinite")
133 _eval_is_integer = make_eval_method("integer")
134 _eval_is_irrational = make_eval_method("irrational")
135 _eval_is_negative = make_eval_method("negative")
136 _eval_is_noninteger = make_eval_method("noninteger")
137 _eval_is_nonnegative = make_eval_method("nonnegative")
138 _eval_is_nonpositive = make_eval_method("nonpositive")
139 _eval_is_nonzero = make_eval_method("nonzero")
140 _eval_is_odd = make_eval_method("odd")
141 _eval_is_polar = make_eval_method("polar")
142 _eval_is_positive = make_eval_method("positive")
143 _eval_is_prime = make_eval_method("prime")
144 _eval_is_rational = make_eval_method("rational")
145 _eval_is_real = make_eval_method("real")
146 _eval_is_transcendental = make_eval_method("transcendental")
147 _eval_is_zero = make_eval_method("zero")
150# one shot functions which are faster than AssumptionsWrapper
152def is_infinite(obj, assumptions=None):
153 if assumptions is None:
154 return obj.is_infinite
155 return ask(Q.infinite(obj), assumptions)
158def is_extended_real(obj, assumptions=None):
159 if assumptions is None:
160 return obj.is_extended_real
161 return ask(Q.extended_real(obj), assumptions)
164def is_extended_nonnegative(obj, assumptions=None):
165 if assumptions is None:
166 return obj.is_extended_nonnegative
167 return ask(Q.extended_nonnegative(obj), assumptions)