Coverage for /usr/lib/python3/dist-packages/sympy/polys/domains/expressiondomain.py: 47%

153 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1"""Implementation of :class:`ExpressionDomain` class. """ 

2 

3 

4from sympy.core import sympify, SympifyError 

5from sympy.polys.domains.characteristiczero import CharacteristicZero 

6from sympy.polys.domains.field import Field 

7from sympy.polys.domains.simpledomain import SimpleDomain 

8from sympy.polys.polyutils import PicklableWithSlots 

9from sympy.utilities import public 

10 

11eflags = {"deep": False, "mul": True, "power_exp": False, "power_base": False, 

12 "basic": False, "multinomial": False, "log": False} 

13 

14@public 

15class ExpressionDomain(Field, CharacteristicZero, SimpleDomain): 

16 """A class for arbitrary expressions. """ 

17 

18 is_SymbolicDomain = is_EX = True 

19 

20 class Expression(PicklableWithSlots): 

21 """An arbitrary expression. """ 

22 

23 __slots__ = ('ex',) 

24 

25 def __init__(self, ex): 

26 if not isinstance(ex, self.__class__): 

27 self.ex = sympify(ex) 

28 else: 

29 self.ex = ex.ex 

30 

31 def __repr__(f): 

32 return 'EX(%s)' % repr(f.ex) 

33 

34 def __str__(f): 

35 return 'EX(%s)' % str(f.ex) 

36 

37 def __hash__(self): 

38 return hash((self.__class__.__name__, self.ex)) 

39 

40 def as_expr(f): 

41 return f.ex 

42 

43 def numer(f): 

44 return f.__class__(f.ex.as_numer_denom()[0]) 

45 

46 def denom(f): 

47 return f.__class__(f.ex.as_numer_denom()[1]) 

48 

49 def simplify(f, ex): 

50 return f.__class__(ex.cancel().expand(**eflags)) 

51 

52 def __abs__(f): 

53 return f.__class__(abs(f.ex)) 

54 

55 def __neg__(f): 

56 return f.__class__(-f.ex) 

57 

58 def _to_ex(f, g): 

59 try: 

60 return f.__class__(g) 

61 except SympifyError: 

62 return None 

63 

64 def __add__(f, g): 

65 g = f._to_ex(g) 

66 

67 if g is None: 

68 return NotImplemented 

69 elif g == EX.zero: 

70 return f 

71 elif f == EX.zero: 

72 return g 

73 else: 

74 return f.simplify(f.ex + g.ex) 

75 

76 def __radd__(f, g): 

77 return f.simplify(f.__class__(g).ex + f.ex) 

78 

79 def __sub__(f, g): 

80 g = f._to_ex(g) 

81 

82 if g is None: 

83 return NotImplemented 

84 elif g == EX.zero: 

85 return f 

86 elif f == EX.zero: 

87 return -g 

88 else: 

89 return f.simplify(f.ex - g.ex) 

90 

91 def __rsub__(f, g): 

92 return f.simplify(f.__class__(g).ex - f.ex) 

93 

94 def __mul__(f, g): 

95 g = f._to_ex(g) 

96 

97 if g is None: 

98 return NotImplemented 

99 

100 if EX.zero in (f, g): 

101 return EX.zero 

102 elif f.ex.is_Number and g.ex.is_Number: 

103 return f.__class__(f.ex*g.ex) 

104 

105 return f.simplify(f.ex*g.ex) 

106 

107 def __rmul__(f, g): 

108 return f.simplify(f.__class__(g).ex*f.ex) 

109 

110 def __pow__(f, n): 

111 n = f._to_ex(n) 

112 

113 if n is not None: 

114 return f.simplify(f.ex**n.ex) 

115 else: 

116 return NotImplemented 

117 

118 def __truediv__(f, g): 

119 g = f._to_ex(g) 

120 

121 if g is not None: 

122 return f.simplify(f.ex/g.ex) 

123 else: 

124 return NotImplemented 

125 

126 def __rtruediv__(f, g): 

127 return f.simplify(f.__class__(g).ex/f.ex) 

128 

129 def __eq__(f, g): 

130 return f.ex == f.__class__(g).ex 

131 

132 def __ne__(f, g): 

133 return not f == g 

134 

135 def __bool__(f): 

136 return not f.ex.is_zero 

137 

138 def gcd(f, g): 

139 from sympy.polys import gcd 

140 return f.__class__(gcd(f.ex, f.__class__(g).ex)) 

141 

142 def lcm(f, g): 

143 from sympy.polys import lcm 

144 return f.__class__(lcm(f.ex, f.__class__(g).ex)) 

145 

146 dtype = Expression 

147 

148 zero = Expression(0) 

149 one = Expression(1) 

150 

151 rep = 'EX' 

152 

153 has_assoc_Ring = False 

154 has_assoc_Field = True 

155 

156 def __init__(self): 

157 pass 

158 

159 def to_sympy(self, a): 

160 """Convert ``a`` to a SymPy object. """ 

161 return a.as_expr() 

162 

163 def from_sympy(self, a): 

164 """Convert SymPy's expression to ``dtype``. """ 

165 return self.dtype(a) 

166 

167 def from_ZZ(K1, a, K0): 

168 """Convert a Python ``int`` object to ``dtype``. """ 

169 return K1(K0.to_sympy(a)) 

170 

171 def from_ZZ_python(K1, a, K0): 

172 """Convert a Python ``int`` object to ``dtype``. """ 

173 return K1(K0.to_sympy(a)) 

174 

175 def from_QQ(K1, a, K0): 

176 """Convert a Python ``Fraction`` object to ``dtype``. """ 

177 return K1(K0.to_sympy(a)) 

178 

179 def from_QQ_python(K1, a, K0): 

180 """Convert a Python ``Fraction`` object to ``dtype``. """ 

181 return K1(K0.to_sympy(a)) 

182 

183 def from_ZZ_gmpy(K1, a, K0): 

184 """Convert a GMPY ``mpz`` object to ``dtype``. """ 

185 return K1(K0.to_sympy(a)) 

186 

187 def from_QQ_gmpy(K1, a, K0): 

188 """Convert a GMPY ``mpq`` object to ``dtype``. """ 

189 return K1(K0.to_sympy(a)) 

190 

191 def from_GaussianIntegerRing(K1, a, K0): 

192 """Convert a ``GaussianRational`` object to ``dtype``. """ 

193 return K1(K0.to_sympy(a)) 

194 

195 def from_GaussianRationalField(K1, a, K0): 

196 """Convert a ``GaussianRational`` object to ``dtype``. """ 

197 return K1(K0.to_sympy(a)) 

198 

199 def from_RealField(K1, a, K0): 

200 """Convert a mpmath ``mpf`` object to ``dtype``. """ 

201 return K1(K0.to_sympy(a)) 

202 

203 def from_PolynomialRing(K1, a, K0): 

204 """Convert a ``DMP`` object to ``dtype``. """ 

205 return K1(K0.to_sympy(a)) 

206 

207 def from_FractionField(K1, a, K0): 

208 """Convert a ``DMF`` object to ``dtype``. """ 

209 return K1(K0.to_sympy(a)) 

210 

211 def from_ExpressionDomain(K1, a, K0): 

212 """Convert a ``EX`` object to ``dtype``. """ 

213 return a 

214 

215 def get_ring(self): 

216 """Returns a ring associated with ``self``. """ 

217 return self # XXX: EX is not a ring but we don't have much choice here. 

218 

219 def get_field(self): 

220 """Returns a field associated with ``self``. """ 

221 return self 

222 

223 def is_positive(self, a): 

224 """Returns True if ``a`` is positive. """ 

225 return a.ex.as_coeff_mul()[0].is_positive 

226 

227 def is_negative(self, a): 

228 """Returns True if ``a`` is negative. """ 

229 return a.ex.could_extract_minus_sign() 

230 

231 def is_nonpositive(self, a): 

232 """Returns True if ``a`` is non-positive. """ 

233 return a.ex.as_coeff_mul()[0].is_nonpositive 

234 

235 def is_nonnegative(self, a): 

236 """Returns True if ``a`` is non-negative. """ 

237 return a.ex.as_coeff_mul()[0].is_nonnegative 

238 

239 def numer(self, a): 

240 """Returns numerator of ``a``. """ 

241 return a.numer() 

242 

243 def denom(self, a): 

244 """Returns denominator of ``a``. """ 

245 return a.denom() 

246 

247 def gcd(self, a, b): 

248 return self(1) 

249 

250 def lcm(self, a, b): 

251 return a.lcm(b) 

252 

253 

254EX = ExpressionDomain()