rationalfield.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. """Implementation of :class:`RationalField` class. """
  2. from sympy.external.gmpy import MPQ
  3. from sympy.polys.domains.groundtypes import SymPyRational, is_square, sqrtrem
  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.polyerrors import CoercionFailed
  8. from sympy.utilities import public
  9. @public
  10. class RationalField(Field, CharacteristicZero, SimpleDomain):
  11. r"""Abstract base class for the domain :ref:`QQ`.
  12. The :py:class:`RationalField` class represents the field of rational
  13. numbers $\mathbb{Q}$ as a :py:class:`~.Domain` in the domain system.
  14. :py:class:`RationalField` is a superclass of
  15. :py:class:`PythonRationalField` and :py:class:`GMPYRationalField` one of
  16. which will be the implementation for :ref:`QQ` depending on whether either
  17. of ``gmpy`` or ``gmpy2`` is installed or not.
  18. See also
  19. ========
  20. Domain
  21. """
  22. rep = 'QQ'
  23. alias = 'QQ'
  24. is_RationalField = is_QQ = True
  25. is_Numerical = True
  26. has_assoc_Ring = True
  27. has_assoc_Field = True
  28. dtype = MPQ
  29. zero = dtype(0)
  30. one = dtype(1)
  31. tp = type(one)
  32. def __init__(self):
  33. pass
  34. def __eq__(self, other):
  35. """Returns ``True`` if two domains are equivalent. """
  36. if isinstance(other, RationalField):
  37. return True
  38. else:
  39. return NotImplemented
  40. def __hash__(self):
  41. """Returns hash code of ``self``. """
  42. return hash('QQ')
  43. def get_ring(self):
  44. """Returns ring associated with ``self``. """
  45. from sympy.polys.domains import ZZ
  46. return ZZ
  47. def to_sympy(self, a):
  48. """Convert ``a`` to a SymPy object. """
  49. return SymPyRational(int(a.numerator), int(a.denominator))
  50. def from_sympy(self, a):
  51. """Convert SymPy's Integer to ``dtype``. """
  52. if a.is_Rational:
  53. return MPQ(a.p, a.q)
  54. elif a.is_Float:
  55. from sympy.polys.domains import RR
  56. return MPQ(*map(int, RR.to_rational(a)))
  57. else:
  58. raise CoercionFailed("expected `Rational` object, got %s" % a)
  59. def algebraic_field(self, *extension, alias=None):
  60. r"""Returns an algebraic field, i.e. `\mathbb{Q}(\alpha, \ldots)`.
  61. Parameters
  62. ==========
  63. *extension : One or more :py:class:`~.Expr`
  64. Generators of the extension. These should be expressions that are
  65. algebraic over `\mathbb{Q}`.
  66. alias : str, :py:class:`~.Symbol`, None, optional (default=None)
  67. If provided, this will be used as the alias symbol for the
  68. primitive element of the returned :py:class:`~.AlgebraicField`.
  69. Returns
  70. =======
  71. :py:class:`~.AlgebraicField`
  72. A :py:class:`~.Domain` representing the algebraic field extension.
  73. Examples
  74. ========
  75. >>> from sympy import QQ, sqrt
  76. >>> QQ.algebraic_field(sqrt(2))
  77. QQ<sqrt(2)>
  78. """
  79. from sympy.polys.domains import AlgebraicField
  80. return AlgebraicField(self, *extension, alias=alias)
  81. def from_AlgebraicField(K1, a, K0):
  82. """Convert a :py:class:`~.ANP` object to :ref:`QQ`.
  83. See :py:meth:`~.Domain.convert`
  84. """
  85. if a.is_ground:
  86. return K1.convert(a.LC(), K0.dom)
  87. def from_ZZ(K1, a, K0):
  88. """Convert a Python ``int`` object to ``dtype``. """
  89. return MPQ(a)
  90. def from_ZZ_python(K1, a, K0):
  91. """Convert a Python ``int`` object to ``dtype``. """
  92. return MPQ(a)
  93. def from_QQ(K1, a, K0):
  94. """Convert a Python ``Fraction`` object to ``dtype``. """
  95. return MPQ(a.numerator, a.denominator)
  96. def from_QQ_python(K1, a, K0):
  97. """Convert a Python ``Fraction`` object to ``dtype``. """
  98. return MPQ(a.numerator, a.denominator)
  99. def from_ZZ_gmpy(K1, a, K0):
  100. """Convert a GMPY ``mpz`` object to ``dtype``. """
  101. return MPQ(a)
  102. def from_QQ_gmpy(K1, a, K0):
  103. """Convert a GMPY ``mpq`` object to ``dtype``. """
  104. return a
  105. def from_GaussianRationalField(K1, a, K0):
  106. """Convert a ``GaussianElement`` object to ``dtype``. """
  107. if a.y == 0:
  108. return MPQ(a.x)
  109. def from_RealField(K1, a, K0):
  110. """Convert a mpmath ``mpf`` object to ``dtype``. """
  111. return MPQ(*map(int, K0.to_rational(a)))
  112. def exquo(self, a, b):
  113. """Exact quotient of ``a`` and ``b``, implies ``__truediv__``. """
  114. return MPQ(a) / MPQ(b)
  115. def quo(self, a, b):
  116. """Quotient of ``a`` and ``b``, implies ``__truediv__``. """
  117. return MPQ(a) / MPQ(b)
  118. def rem(self, a, b):
  119. """Remainder of ``a`` and ``b``, implies nothing. """
  120. return self.zero
  121. def div(self, a, b):
  122. """Division of ``a`` and ``b``, implies ``__truediv__``. """
  123. return MPQ(a) / MPQ(b), self.zero
  124. def numer(self, a):
  125. """Returns numerator of ``a``. """
  126. return a.numerator
  127. def denom(self, a):
  128. """Returns denominator of ``a``. """
  129. return a.denominator
  130. def is_square(self, a):
  131. """Return ``True`` if ``a`` is a square.
  132. Explanation
  133. ===========
  134. A rational number is a square if and only if there exists
  135. a rational number ``b`` such that ``b * b == a``.
  136. """
  137. return is_square(a.numerator) and is_square(a.denominator)
  138. def exsqrt(self, a):
  139. """Non-negative square root of ``a`` if ``a`` is a square.
  140. See also
  141. ========
  142. is_square
  143. """
  144. if a.numerator < 0: # denominator is always positive
  145. return None
  146. p_sqrt, p_rem = sqrtrem(a.numerator)
  147. if p_rem != 0:
  148. return None
  149. q_sqrt, q_rem = sqrtrem(a.denominator)
  150. if q_rem != 0:
  151. return None
  152. return MPQ(p_sqrt, q_sqrt)
  153. QQ = RationalField()