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

1""" 

2Functions and wrapper object to call assumption property and predicate 

3query with same syntax. 

4 

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)``. 

10 

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. 

14 

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. 

20 

21Examples 

22======== 

23 

24For multiple use, use ``AssumptionsWrapper()``. 

25 

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 

34 

35For single use, use ``is_[...]()`` functions. 

36 

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 

43 

44""" 

45 

46from sympy.assumptions import ask, Q 

47from sympy.core.basic import Basic 

48from sympy.core.sympify import _sympify 

49 

50 

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 

60 

61 

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 

67 

68 Parameters 

69 ========== 

70 

71 expr : Basic 

72 

73 assumptions : Boolean, optional 

74 

75 Examples 

76 ======== 

77 

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 

86 

87 With ``AssumptionsWrapper``, both evaluation and refinement can be supported 

88 by single implementation. 

89 

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 

107 

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 

116 

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") 

148 

149 

150# one shot functions which are faster than AssumptionsWrapper 

151 

152def is_infinite(obj, assumptions=None): 

153 if assumptions is None: 

154 return obj.is_infinite 

155 return ask(Q.infinite(obj), assumptions) 

156 

157 

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) 

162 

163 

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)