integerring.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. """Implementation of :class:`IntegerRing` class. """
  2. from sympy.external.gmpy import MPZ, GROUND_TYPES
  3. from sympy.core.numbers import int_valued
  4. from sympy.polys.domains.groundtypes import (
  5. SymPyInteger,
  6. factorial,
  7. gcdex, gcd, lcm, sqrt, is_square, sqrtrem,
  8. )
  9. from sympy.polys.domains.characteristiczero import CharacteristicZero
  10. from sympy.polys.domains.ring import Ring
  11. from sympy.polys.domains.simpledomain import SimpleDomain
  12. from sympy.polys.polyerrors import CoercionFailed
  13. from sympy.utilities import public
  14. import math
  15. @public
  16. class IntegerRing(Ring, CharacteristicZero, SimpleDomain):
  17. r"""The domain ``ZZ`` representing the integers `\mathbb{Z}`.
  18. The :py:class:`IntegerRing` class represents the ring of integers as a
  19. :py:class:`~.Domain` in the domain system. :py:class:`IntegerRing` is a
  20. super class of :py:class:`PythonIntegerRing` and
  21. :py:class:`GMPYIntegerRing` one of which will be the implementation for
  22. :ref:`ZZ` depending on whether or not ``gmpy`` or ``gmpy2`` is installed.
  23. See also
  24. ========
  25. Domain
  26. """
  27. rep = 'ZZ'
  28. alias = 'ZZ'
  29. dtype = MPZ
  30. zero = dtype(0)
  31. one = dtype(1)
  32. tp = type(one)
  33. is_IntegerRing = is_ZZ = True
  34. is_Numerical = True
  35. is_PID = True
  36. has_assoc_Ring = True
  37. has_assoc_Field = True
  38. def __init__(self):
  39. """Allow instantiation of this domain. """
  40. def __eq__(self, other):
  41. """Returns ``True`` if two domains are equivalent. """
  42. if isinstance(other, IntegerRing):
  43. return True
  44. else:
  45. return NotImplemented
  46. def __hash__(self):
  47. """Compute a hash value for this domain. """
  48. return hash('ZZ')
  49. def to_sympy(self, a):
  50. """Convert ``a`` to a SymPy object. """
  51. return SymPyInteger(int(a))
  52. def from_sympy(self, a):
  53. """Convert SymPy's Integer to ``dtype``. """
  54. if a.is_Integer:
  55. return MPZ(a.p)
  56. elif int_valued(a):
  57. return MPZ(int(a))
  58. else:
  59. raise CoercionFailed("expected an integer, got %s" % a)
  60. def get_field(self):
  61. r"""Return the associated field of fractions :ref:`QQ`
  62. Returns
  63. =======
  64. :ref:`QQ`:
  65. The associated field of fractions :ref:`QQ`, a
  66. :py:class:`~.Domain` representing the rational numbers
  67. `\mathbb{Q}`.
  68. Examples
  69. ========
  70. >>> from sympy import ZZ
  71. >>> ZZ.get_field()
  72. QQ
  73. """
  74. from sympy.polys.domains import QQ
  75. return QQ
  76. def algebraic_field(self, *extension, alias=None):
  77. r"""Returns an algebraic field, i.e. `\mathbb{Q}(\alpha, \ldots)`.
  78. Parameters
  79. ==========
  80. *extension : One or more :py:class:`~.Expr`.
  81. Generators of the extension. These should be expressions that are
  82. algebraic over `\mathbb{Q}`.
  83. alias : str, :py:class:`~.Symbol`, None, optional (default=None)
  84. If provided, this will be used as the alias symbol for the
  85. primitive element of the returned :py:class:`~.AlgebraicField`.
  86. Returns
  87. =======
  88. :py:class:`~.AlgebraicField`
  89. A :py:class:`~.Domain` representing the algebraic field extension.
  90. Examples
  91. ========
  92. >>> from sympy import ZZ, sqrt
  93. >>> ZZ.algebraic_field(sqrt(2))
  94. QQ<sqrt(2)>
  95. """
  96. return self.get_field().algebraic_field(*extension, alias=alias)
  97. def from_AlgebraicField(K1, a, K0):
  98. """Convert a :py:class:`~.ANP` object to :ref:`ZZ`.
  99. See :py:meth:`~.Domain.convert`.
  100. """
  101. if a.is_ground:
  102. return K1.convert(a.LC(), K0.dom)
  103. def log(self, a, b):
  104. r"""Logarithm of *a* to the base *b*.
  105. Parameters
  106. ==========
  107. a: number
  108. b: number
  109. Returns
  110. =======
  111. $\\lfloor\log(a, b)\\rfloor$:
  112. Floor of the logarithm of *a* to the base *b*
  113. Examples
  114. ========
  115. >>> from sympy import ZZ
  116. >>> ZZ.log(ZZ(8), ZZ(2))
  117. 3
  118. >>> ZZ.log(ZZ(9), ZZ(2))
  119. 3
  120. Notes
  121. =====
  122. This function uses ``math.log`` which is based on ``float`` so it will
  123. fail for large integer arguments.
  124. """
  125. return self.dtype(int(math.log(int(a), b)))
  126. def from_FF(K1, a, K0):
  127. """Convert ``ModularInteger(int)`` to GMPY's ``mpz``. """
  128. return MPZ(K0.to_int(a))
  129. def from_FF_python(K1, a, K0):
  130. """Convert ``ModularInteger(int)`` to GMPY's ``mpz``. """
  131. return MPZ(K0.to_int(a))
  132. def from_ZZ(K1, a, K0):
  133. """Convert Python's ``int`` to GMPY's ``mpz``. """
  134. return MPZ(a)
  135. def from_ZZ_python(K1, a, K0):
  136. """Convert Python's ``int`` to GMPY's ``mpz``. """
  137. return MPZ(a)
  138. def from_QQ(K1, a, K0):
  139. """Convert Python's ``Fraction`` to GMPY's ``mpz``. """
  140. if a.denominator == 1:
  141. return MPZ(a.numerator)
  142. def from_QQ_python(K1, a, K0):
  143. """Convert Python's ``Fraction`` to GMPY's ``mpz``. """
  144. if a.denominator == 1:
  145. return MPZ(a.numerator)
  146. def from_FF_gmpy(K1, a, K0):
  147. """Convert ``ModularInteger(mpz)`` to GMPY's ``mpz``. """
  148. return MPZ(K0.to_int(a))
  149. def from_ZZ_gmpy(K1, a, K0):
  150. """Convert GMPY's ``mpz`` to GMPY's ``mpz``. """
  151. return a
  152. def from_QQ_gmpy(K1, a, K0):
  153. """Convert GMPY ``mpq`` to GMPY's ``mpz``. """
  154. if a.denominator == 1:
  155. return a.numerator
  156. def from_RealField(K1, a, K0):
  157. """Convert mpmath's ``mpf`` to GMPY's ``mpz``. """
  158. p, q = K0.to_rational(a)
  159. if q == 1:
  160. # XXX: If MPZ is flint.fmpz and p is a gmpy2.mpz, then we need
  161. # to convert via int because fmpz and mpz do not know about each
  162. # other.
  163. return MPZ(int(p))
  164. def from_GaussianIntegerRing(K1, a, K0):
  165. if a.y == 0:
  166. return a.x
  167. def from_EX(K1, a, K0):
  168. """Convert ``Expression`` to GMPY's ``mpz``. """
  169. if a.is_Integer:
  170. return K1.from_sympy(a)
  171. def gcdex(self, a, b):
  172. """Compute extended GCD of ``a`` and ``b``. """
  173. h, s, t = gcdex(a, b)
  174. # XXX: This conditional logic should be handled somewhere else.
  175. if GROUND_TYPES == 'gmpy':
  176. return s, t, h
  177. else:
  178. return h, s, t
  179. def gcd(self, a, b):
  180. """Compute GCD of ``a`` and ``b``. """
  181. return gcd(a, b)
  182. def lcm(self, a, b):
  183. """Compute LCM of ``a`` and ``b``. """
  184. return lcm(a, b)
  185. def sqrt(self, a):
  186. """Compute square root of ``a``. """
  187. return sqrt(a)
  188. def is_square(self, a):
  189. """Return ``True`` if ``a`` is a square.
  190. Explanation
  191. ===========
  192. An integer is a square if and only if there exists an integer
  193. ``b`` such that ``b * b == a``.
  194. """
  195. return is_square(a)
  196. def exsqrt(self, a):
  197. """Non-negative square root of ``a`` if ``a`` is a square.
  198. See also
  199. ========
  200. is_square
  201. """
  202. if a < 0:
  203. return None
  204. root, rem = sqrtrem(a)
  205. if rem != 0:
  206. return None
  207. return root
  208. def factorial(self, a):
  209. """Compute factorial of ``a``. """
  210. return factorial(a)
  211. ZZ = IntegerRing()