expressiondomain.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. """Implementation of :class:`ExpressionDomain` class. """
  2. from sympy.core import sympify, SympifyError
  3. from sympy.polys.domains.domainelement import DomainElement
  4. from sympy.polys.domains.characteristiczero import CharacteristicZero
  5. from sympy.polys.domains.field import Field
  6. from sympy.polys.domains.simpledomain import SimpleDomain
  7. from sympy.polys.polyutils import PicklableWithSlots
  8. from sympy.utilities import public
  9. eflags = {"deep": False, "mul": True, "power_exp": False, "power_base": False,
  10. "basic": False, "multinomial": False, "log": False}
  11. @public
  12. class ExpressionDomain(Field, CharacteristicZero, SimpleDomain):
  13. """A class for arbitrary expressions. """
  14. is_SymbolicDomain = is_EX = True
  15. class Expression(DomainElement, PicklableWithSlots):
  16. """An arbitrary expression. """
  17. __slots__ = ('ex',)
  18. def __init__(self, ex):
  19. if not isinstance(ex, self.__class__):
  20. self.ex = sympify(ex)
  21. else:
  22. self.ex = ex.ex
  23. def __repr__(f):
  24. return 'EX(%s)' % repr(f.ex)
  25. def __str__(f):
  26. return 'EX(%s)' % str(f.ex)
  27. def __hash__(self):
  28. return hash((self.__class__.__name__, self.ex))
  29. def parent(self):
  30. return EX
  31. def as_expr(f):
  32. return f.ex
  33. def numer(f):
  34. return f.__class__(f.ex.as_numer_denom()[0])
  35. def denom(f):
  36. return f.__class__(f.ex.as_numer_denom()[1])
  37. def simplify(f, ex):
  38. return f.__class__(ex.cancel().expand(**eflags))
  39. def __abs__(f):
  40. return f.__class__(abs(f.ex))
  41. def __neg__(f):
  42. return f.__class__(-f.ex)
  43. def _to_ex(f, g):
  44. try:
  45. return f.__class__(g)
  46. except SympifyError:
  47. return None
  48. def __lt__(f, g):
  49. return f.ex.sort_key() < g.ex.sort_key()
  50. def __add__(f, g):
  51. g = f._to_ex(g)
  52. if g is None:
  53. return NotImplemented
  54. elif g == EX.zero:
  55. return f
  56. elif f == EX.zero:
  57. return g
  58. else:
  59. return f.simplify(f.ex + g.ex)
  60. def __radd__(f, g):
  61. return f.simplify(f.__class__(g).ex + f.ex)
  62. def __sub__(f, g):
  63. g = f._to_ex(g)
  64. if g is None:
  65. return NotImplemented
  66. elif g == EX.zero:
  67. return f
  68. elif f == EX.zero:
  69. return -g
  70. else:
  71. return f.simplify(f.ex - g.ex)
  72. def __rsub__(f, g):
  73. return f.simplify(f.__class__(g).ex - f.ex)
  74. def __mul__(f, g):
  75. g = f._to_ex(g)
  76. if g is None:
  77. return NotImplemented
  78. if EX.zero in (f, g):
  79. return EX.zero
  80. elif f.ex.is_Number and g.ex.is_Number:
  81. return f.__class__(f.ex*g.ex)
  82. return f.simplify(f.ex*g.ex)
  83. def __rmul__(f, g):
  84. return f.simplify(f.__class__(g).ex*f.ex)
  85. def __pow__(f, n):
  86. n = f._to_ex(n)
  87. if n is not None:
  88. return f.simplify(f.ex**n.ex)
  89. else:
  90. return NotImplemented
  91. def __truediv__(f, g):
  92. g = f._to_ex(g)
  93. if g is not None:
  94. return f.simplify(f.ex/g.ex)
  95. else:
  96. return NotImplemented
  97. def __rtruediv__(f, g):
  98. return f.simplify(f.__class__(g).ex/f.ex)
  99. def __eq__(f, g):
  100. return f.ex == f.__class__(g).ex
  101. def __ne__(f, g):
  102. return not f == g
  103. def __bool__(f):
  104. return not f.ex.is_zero
  105. def gcd(f, g):
  106. from sympy.polys import gcd
  107. return f.__class__(gcd(f.ex, f.__class__(g).ex))
  108. def lcm(f, g):
  109. from sympy.polys import lcm
  110. return f.__class__(lcm(f.ex, f.__class__(g).ex))
  111. dtype = Expression
  112. zero = Expression(0)
  113. one = Expression(1)
  114. rep = 'EX'
  115. has_assoc_Ring = False
  116. has_assoc_Field = True
  117. def __init__(self):
  118. pass
  119. def __eq__(self, other):
  120. if isinstance(other, ExpressionDomain):
  121. return True
  122. else:
  123. return NotImplemented
  124. def __hash__(self):
  125. return hash("EX")
  126. def to_sympy(self, a):
  127. """Convert ``a`` to a SymPy object. """
  128. return a.as_expr()
  129. def from_sympy(self, a):
  130. """Convert SymPy's expression to ``dtype``. """
  131. return self.dtype(a)
  132. def from_ZZ(K1, a, K0):
  133. """Convert a Python ``int`` object to ``dtype``. """
  134. return K1(K0.to_sympy(a))
  135. def from_ZZ_python(K1, a, K0):
  136. """Convert a Python ``int`` object to ``dtype``. """
  137. return K1(K0.to_sympy(a))
  138. def from_QQ(K1, a, K0):
  139. """Convert a Python ``Fraction`` object to ``dtype``. """
  140. return K1(K0.to_sympy(a))
  141. def from_QQ_python(K1, a, K0):
  142. """Convert a Python ``Fraction`` object to ``dtype``. """
  143. return K1(K0.to_sympy(a))
  144. def from_ZZ_gmpy(K1, a, K0):
  145. """Convert a GMPY ``mpz`` object to ``dtype``. """
  146. return K1(K0.to_sympy(a))
  147. def from_QQ_gmpy(K1, a, K0):
  148. """Convert a GMPY ``mpq`` object to ``dtype``. """
  149. return K1(K0.to_sympy(a))
  150. def from_GaussianIntegerRing(K1, a, K0):
  151. """Convert a ``GaussianRational`` object to ``dtype``. """
  152. return K1(K0.to_sympy(a))
  153. def from_GaussianRationalField(K1, a, K0):
  154. """Convert a ``GaussianRational`` object to ``dtype``. """
  155. return K1(K0.to_sympy(a))
  156. def from_AlgebraicField(K1, a, K0):
  157. """Convert an ``ANP`` object to ``dtype``. """
  158. return K1(K0.to_sympy(a))
  159. def from_RealField(K1, a, K0):
  160. """Convert a mpmath ``mpf`` object to ``dtype``. """
  161. return K1(K0.to_sympy(a))
  162. def from_ComplexField(K1, a, K0):
  163. """Convert a mpmath ``mpc`` object to ``dtype``. """
  164. return K1(K0.to_sympy(a))
  165. def from_PolynomialRing(K1, a, K0):
  166. """Convert a ``DMP`` object to ``dtype``. """
  167. return K1(K0.to_sympy(a))
  168. def from_FractionField(K1, a, K0):
  169. """Convert a ``DMF`` object to ``dtype``. """
  170. return K1(K0.to_sympy(a))
  171. def from_ExpressionDomain(K1, a, K0):
  172. """Convert a ``EX`` object to ``dtype``. """
  173. return a
  174. def get_ring(self):
  175. """Returns a ring associated with ``self``. """
  176. return self # XXX: EX is not a ring but we don't have much choice here.
  177. def get_field(self):
  178. """Returns a field associated with ``self``. """
  179. return self
  180. def is_positive(self, a):
  181. """Returns True if ``a`` is positive. """
  182. return a.ex.as_coeff_mul()[0].is_positive
  183. def is_negative(self, a):
  184. """Returns True if ``a`` is negative. """
  185. return a.ex.could_extract_minus_sign()
  186. def is_nonpositive(self, a):
  187. """Returns True if ``a`` is non-positive. """
  188. return a.ex.as_coeff_mul()[0].is_nonpositive
  189. def is_nonnegative(self, a):
  190. """Returns True if ``a`` is non-negative. """
  191. return a.ex.as_coeff_mul()[0].is_nonnegative
  192. def numer(self, a):
  193. """Returns numerator of ``a``. """
  194. return a.numer()
  195. def denom(self, a):
  196. """Returns denominator of ``a``. """
  197. return a.denom()
  198. def gcd(self, a, b):
  199. return self(1)
  200. def lcm(self, a, b):
  201. return a.lcm(b)
  202. EX = ExpressionDomain()