ZhengyangZhang commited on
Commit
d7ff3e2
·
verified ·
1 Parent(s): 768c4ff

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. lib/python3.12/site-packages/sympy/polys/domains/__init__.py +57 -0
  2. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/__init__.cpython-312.pyc +0 -0
  3. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/algebraicfield.cpython-312.pyc +0 -0
  4. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/characteristiczero.cpython-312.pyc +0 -0
  5. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/complexfield.cpython-312.pyc +0 -0
  6. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/compositedomain.cpython-312.pyc +0 -0
  7. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/domain.cpython-312.pyc +0 -0
  8. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/domainelement.cpython-312.pyc +0 -0
  9. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/expressiondomain.cpython-312.pyc +0 -0
  10. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/expressionrawdomain.cpython-312.pyc +0 -0
  11. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/field.cpython-312.pyc +0 -0
  12. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/finitefield.cpython-312.pyc +0 -0
  13. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/fractionfield.cpython-312.pyc +0 -0
  14. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/gaussiandomains.cpython-312.pyc +0 -0
  15. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/gmpyfinitefield.cpython-312.pyc +0 -0
  16. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/gmpyintegerring.cpython-312.pyc +0 -0
  17. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/gmpyrationalfield.cpython-312.pyc +0 -0
  18. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/groundtypes.cpython-312.pyc +0 -0
  19. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/integerring.cpython-312.pyc +0 -0
  20. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/modularinteger.cpython-312.pyc +0 -0
  21. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/mpelements.cpython-312.pyc +0 -0
  22. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/old_fractionfield.cpython-312.pyc +0 -0
  23. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/old_polynomialring.cpython-312.pyc +0 -0
  24. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/polynomialring.cpython-312.pyc +0 -0
  25. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/pythonfinitefield.cpython-312.pyc +0 -0
  26. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/pythonintegerring.cpython-312.pyc +0 -0
  27. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/pythonrational.cpython-312.pyc +0 -0
  28. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/pythonrationalfield.cpython-312.pyc +0 -0
  29. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/quotientring.cpython-312.pyc +0 -0
  30. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/rationalfield.cpython-312.pyc +0 -0
  31. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/realfield.cpython-312.pyc +0 -0
  32. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/ring.cpython-312.pyc +0 -0
  33. lib/python3.12/site-packages/sympy/polys/domains/__pycache__/simpledomain.cpython-312.pyc +0 -0
  34. lib/python3.12/site-packages/sympy/polys/domains/algebraicfield.py +607 -0
  35. lib/python3.12/site-packages/sympy/polys/domains/characteristiczero.py +15 -0
  36. lib/python3.12/site-packages/sympy/polys/domains/complexfield.py +185 -0
  37. lib/python3.12/site-packages/sympy/polys/domains/compositedomain.py +52 -0
  38. lib/python3.12/site-packages/sympy/polys/domains/domain.py +1372 -0
  39. lib/python3.12/site-packages/sympy/polys/domains/domainelement.py +38 -0
  40. lib/python3.12/site-packages/sympy/polys/domains/expressiondomain.py +278 -0
  41. lib/python3.12/site-packages/sympy/polys/domains/expressionrawdomain.py +57 -0
  42. lib/python3.12/site-packages/sympy/polys/domains/field.py +104 -0
  43. lib/python3.12/site-packages/sympy/polys/domains/finitefield.py +328 -0
  44. lib/python3.12/site-packages/sympy/polys/domains/fractionfield.py +177 -0
  45. lib/python3.12/site-packages/sympy/polys/domains/gaussiandomains.py +686 -0
  46. lib/python3.12/site-packages/sympy/polys/domains/gmpyfinitefield.py +16 -0
  47. lib/python3.12/site-packages/sympy/polys/domains/gmpyintegerring.py +105 -0
  48. lib/python3.12/site-packages/sympy/polys/domains/gmpyrationalfield.py +100 -0
  49. lib/python3.12/site-packages/sympy/polys/domains/groundtypes.py +99 -0
  50. lib/python3.12/site-packages/sympy/polys/domains/integerring.py +276 -0
lib/python3.12/site-packages/sympy/polys/domains/__init__.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of mathematical domains. """
2
+
3
+ __all__ = [
4
+ 'Domain', 'FiniteField', 'IntegerRing', 'RationalField', 'RealField',
5
+ 'ComplexField', 'AlgebraicField', 'PolynomialRing', 'FractionField',
6
+ 'ExpressionDomain', 'PythonRational',
7
+
8
+ 'GF', 'FF', 'ZZ', 'QQ', 'ZZ_I', 'QQ_I', 'RR', 'CC', 'EX', 'EXRAW',
9
+ ]
10
+
11
+ from .domain import Domain
12
+ from .finitefield import FiniteField, FF, GF
13
+ from .integerring import IntegerRing, ZZ
14
+ from .rationalfield import RationalField, QQ
15
+ from .algebraicfield import AlgebraicField
16
+ from .gaussiandomains import ZZ_I, QQ_I
17
+ from .realfield import RealField, RR
18
+ from .complexfield import ComplexField, CC
19
+ from .polynomialring import PolynomialRing
20
+ from .fractionfield import FractionField
21
+ from .expressiondomain import ExpressionDomain, EX
22
+ from .expressionrawdomain import EXRAW
23
+ from .pythonrational import PythonRational
24
+
25
+
26
+ # This is imported purely for backwards compatibility because some parts of
27
+ # the codebase used to import this from here and it's possible that downstream
28
+ # does as well:
29
+ from sympy.external.gmpy import GROUND_TYPES # noqa: F401
30
+
31
+ #
32
+ # The rest of these are obsolete and provided only for backwards
33
+ # compatibility:
34
+ #
35
+
36
+ from .pythonfinitefield import PythonFiniteField
37
+ from .gmpyfinitefield import GMPYFiniteField
38
+ from .pythonintegerring import PythonIntegerRing
39
+ from .gmpyintegerring import GMPYIntegerRing
40
+ from .pythonrationalfield import PythonRationalField
41
+ from .gmpyrationalfield import GMPYRationalField
42
+
43
+ FF_python = PythonFiniteField
44
+ FF_gmpy = GMPYFiniteField
45
+
46
+ ZZ_python = PythonIntegerRing
47
+ ZZ_gmpy = GMPYIntegerRing
48
+
49
+ QQ_python = PythonRationalField
50
+ QQ_gmpy = GMPYRationalField
51
+
52
+ __all__.extend((
53
+ 'PythonFiniteField', 'GMPYFiniteField', 'PythonIntegerRing',
54
+ 'GMPYIntegerRing', 'PythonRational', 'GMPYRationalField',
55
+
56
+ 'FF_python', 'FF_gmpy', 'ZZ_python', 'ZZ_gmpy', 'QQ_python', 'QQ_gmpy',
57
+ ))
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (1.8 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/algebraicfield.cpython-312.pyc ADDED
Binary file (27.4 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/characteristiczero.cpython-312.pyc ADDED
Binary file (880 Bytes). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/complexfield.cpython-312.pyc ADDED
Binary file (10.1 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/compositedomain.cpython-312.pyc ADDED
Binary file (3.35 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/domain.cpython-312.pyc ADDED
Binary file (45.8 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/domainelement.cpython-312.pyc ADDED
Binary file (1.37 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/expressiondomain.cpython-312.pyc ADDED
Binary file (15.4 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/expressionrawdomain.cpython-312.pyc ADDED
Binary file (2.73 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/field.cpython-312.pyc ADDED
Binary file (4.24 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/finitefield.cpython-312.pyc ADDED
Binary file (14.1 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/fractionfield.cpython-312.pyc ADDED
Binary file (10.4 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/gaussiandomains.cpython-312.pyc ADDED
Binary file (28.8 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/gmpyfinitefield.cpython-312.pyc ADDED
Binary file (1.03 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/gmpyintegerring.cpython-312.pyc ADDED
Binary file (5.31 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/gmpyrationalfield.cpython-312.pyc ADDED
Binary file (5.59 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/groundtypes.cpython-312.pyc ADDED
Binary file (2.69 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/integerring.cpython-312.pyc ADDED
Binary file (10.6 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/modularinteger.cpython-312.pyc ADDED
Binary file (10.9 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/mpelements.cpython-312.pyc ADDED
Binary file (8.34 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/old_fractionfield.cpython-312.pyc ADDED
Binary file (12 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/old_polynomialring.cpython-312.pyc ADDED
Binary file (25.9 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/polynomialring.cpython-312.pyc ADDED
Binary file (11.9 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/pythonfinitefield.cpython-312.pyc ADDED
Binary file (1.05 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/pythonintegerring.cpython-312.pyc ADDED
Binary file (5.09 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/pythonrational.cpython-312.pyc ADDED
Binary file (924 Bytes). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/pythonrationalfield.cpython-312.pyc ADDED
Binary file (4.14 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/quotientring.cpython-312.pyc ADDED
Binary file (10.7 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/rationalfield.cpython-312.pyc ADDED
Binary file (9.12 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/realfield.cpython-312.pyc ADDED
Binary file (8.37 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/ring.cpython-312.pyc ADDED
Binary file (4.9 kB). View file
 
lib/python3.12/site-packages/sympy/polys/domains/__pycache__/simpledomain.cpython-312.pyc ADDED
Binary file (871 Bytes). View file
 
lib/python3.12/site-packages/sympy/polys/domains/algebraicfield.py ADDED
@@ -0,0 +1,607 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of :class:`AlgebraicField` class. """
2
+
3
+
4
+ from sympy.core.add import Add
5
+ from sympy.core.mul import Mul
6
+ from sympy.core.singleton import S
7
+ from sympy.polys.domains.characteristiczero import CharacteristicZero
8
+ from sympy.polys.domains.field import Field
9
+ from sympy.polys.domains.simpledomain import SimpleDomain
10
+ from sympy.polys.polyclasses import ANP
11
+ from sympy.polys.polyerrors import CoercionFailed, DomainError, NotAlgebraic, IsomorphismFailed
12
+ from sympy.utilities import public
13
+
14
+ @public
15
+ class AlgebraicField(Field, CharacteristicZero, SimpleDomain):
16
+ r"""Algebraic number field :ref:`QQ(a)`
17
+
18
+ A :ref:`QQ(a)` domain represents an `algebraic number field`_
19
+ `\mathbb{Q}(a)` as a :py:class:`~.Domain` in the domain system (see
20
+ :ref:`polys-domainsintro`).
21
+
22
+ A :py:class:`~.Poly` created from an expression involving `algebraic
23
+ numbers`_ will treat the algebraic numbers as generators if the generators
24
+ argument is not specified.
25
+
26
+ >>> from sympy import Poly, Symbol, sqrt
27
+ >>> x = Symbol('x')
28
+ >>> Poly(x**2 + sqrt(2))
29
+ Poly(x**2 + (sqrt(2)), x, sqrt(2), domain='ZZ')
30
+
31
+ That is a multivariate polynomial with ``sqrt(2)`` treated as one of the
32
+ generators (variables). If the generators are explicitly specified then
33
+ ``sqrt(2)`` will be considered to be a coefficient but by default the
34
+ :ref:`EX` domain is used. To make a :py:class:`~.Poly` with a :ref:`QQ(a)`
35
+ domain the argument ``extension=True`` can be given.
36
+
37
+ >>> Poly(x**2 + sqrt(2), x)
38
+ Poly(x**2 + sqrt(2), x, domain='EX')
39
+ >>> Poly(x**2 + sqrt(2), x, extension=True)
40
+ Poly(x**2 + sqrt(2), x, domain='QQ<sqrt(2)>')
41
+
42
+ A generator of the algebraic field extension can also be specified
43
+ explicitly which is particularly useful if the coefficients are all
44
+ rational but an extension field is needed (e.g. to factor the
45
+ polynomial).
46
+
47
+ >>> Poly(x**2 + 1)
48
+ Poly(x**2 + 1, x, domain='ZZ')
49
+ >>> Poly(x**2 + 1, extension=sqrt(2))
50
+ Poly(x**2 + 1, x, domain='QQ<sqrt(2)>')
51
+
52
+ It is possible to factorise a polynomial over a :ref:`QQ(a)` domain using
53
+ the ``extension`` argument to :py:func:`~.factor` or by specifying the domain
54
+ explicitly.
55
+
56
+ >>> from sympy import factor, QQ
57
+ >>> factor(x**2 - 2)
58
+ x**2 - 2
59
+ >>> factor(x**2 - 2, extension=sqrt(2))
60
+ (x - sqrt(2))*(x + sqrt(2))
61
+ >>> factor(x**2 - 2, domain='QQ<sqrt(2)>')
62
+ (x - sqrt(2))*(x + sqrt(2))
63
+ >>> factor(x**2 - 2, domain=QQ.algebraic_field(sqrt(2)))
64
+ (x - sqrt(2))*(x + sqrt(2))
65
+
66
+ The ``extension=True`` argument can be used but will only create an
67
+ extension that contains the coefficients which is usually not enough to
68
+ factorise the polynomial.
69
+
70
+ >>> p = x**3 + sqrt(2)*x**2 - 2*x - 2*sqrt(2)
71
+ >>> factor(p) # treats sqrt(2) as a symbol
72
+ (x + sqrt(2))*(x**2 - 2)
73
+ >>> factor(p, extension=True)
74
+ (x - sqrt(2))*(x + sqrt(2))**2
75
+ >>> factor(x**2 - 2, extension=True) # all rational coefficients
76
+ x**2 - 2
77
+
78
+ It is also possible to use :ref:`QQ(a)` with the :py:func:`~.cancel`
79
+ and :py:func:`~.gcd` functions.
80
+
81
+ >>> from sympy import cancel, gcd
82
+ >>> cancel((x**2 - 2)/(x - sqrt(2)))
83
+ (x**2 - 2)/(x - sqrt(2))
84
+ >>> cancel((x**2 - 2)/(x - sqrt(2)), extension=sqrt(2))
85
+ x + sqrt(2)
86
+ >>> gcd(x**2 - 2, x - sqrt(2))
87
+ 1
88
+ >>> gcd(x**2 - 2, x - sqrt(2), extension=sqrt(2))
89
+ x - sqrt(2)
90
+
91
+ When using the domain directly :ref:`QQ(a)` can be used as a constructor
92
+ to create instances which then support the operations ``+,-,*,**,/``. The
93
+ :py:meth:`~.Domain.algebraic_field` method is used to construct a
94
+ particular :ref:`QQ(a)` domain. The :py:meth:`~.Domain.from_sympy` method
95
+ can be used to create domain elements from normal SymPy expressions.
96
+
97
+ >>> K = QQ.algebraic_field(sqrt(2))
98
+ >>> K
99
+ QQ<sqrt(2)>
100
+ >>> xk = K.from_sympy(3 + 4*sqrt(2))
101
+ >>> xk # doctest: +SKIP
102
+ ANP([4, 3], [1, 0, -2], QQ)
103
+
104
+ Elements of :ref:`QQ(a)` are instances of :py:class:`~.ANP` which have
105
+ limited printing support. The raw display shows the internal
106
+ representation of the element as the list ``[4, 3]`` representing the
107
+ coefficients of ``1`` and ``sqrt(2)`` for this element in the form
108
+ ``a * sqrt(2) + b * 1`` where ``a`` and ``b`` are elements of :ref:`QQ`.
109
+ The minimal polynomial for the generator ``(x**2 - 2)`` is also shown in
110
+ the :ref:`dup-representation` as the list ``[1, 0, -2]``. We can use
111
+ :py:meth:`~.Domain.to_sympy` to get a better printed form for the
112
+ elements and to see the results of operations.
113
+
114
+ >>> xk = K.from_sympy(3 + 4*sqrt(2))
115
+ >>> yk = K.from_sympy(2 + 3*sqrt(2))
116
+ >>> xk * yk # doctest: +SKIP
117
+ ANP([17, 30], [1, 0, -2], QQ)
118
+ >>> K.to_sympy(xk * yk)
119
+ 17*sqrt(2) + 30
120
+ >>> K.to_sympy(xk + yk)
121
+ 5 + 7*sqrt(2)
122
+ >>> K.to_sympy(xk ** 2)
123
+ 24*sqrt(2) + 41
124
+ >>> K.to_sympy(xk / yk)
125
+ sqrt(2)/14 + 9/7
126
+
127
+ Any expression representing an algebraic number can be used to generate
128
+ a :ref:`QQ(a)` domain provided its `minimal polynomial`_ can be computed.
129
+ The function :py:func:`~.minpoly` function is used for this.
130
+
131
+ >>> from sympy import exp, I, pi, minpoly
132
+ >>> g = exp(2*I*pi/3)
133
+ >>> g
134
+ exp(2*I*pi/3)
135
+ >>> g.is_algebraic
136
+ True
137
+ >>> minpoly(g, x)
138
+ x**2 + x + 1
139
+ >>> factor(x**3 - 1, extension=g)
140
+ (x - 1)*(x - exp(2*I*pi/3))*(x + 1 + exp(2*I*pi/3))
141
+
142
+ It is also possible to make an algebraic field from multiple extension
143
+ elements.
144
+
145
+ >>> K = QQ.algebraic_field(sqrt(2), sqrt(3))
146
+ >>> K
147
+ QQ<sqrt(2) + sqrt(3)>
148
+ >>> p = x**4 - 5*x**2 + 6
149
+ >>> factor(p)
150
+ (x**2 - 3)*(x**2 - 2)
151
+ >>> factor(p, domain=K)
152
+ (x - sqrt(2))*(x + sqrt(2))*(x - sqrt(3))*(x + sqrt(3))
153
+ >>> factor(p, extension=[sqrt(2), sqrt(3)])
154
+ (x - sqrt(2))*(x + sqrt(2))*(x - sqrt(3))*(x + sqrt(3))
155
+
156
+ Multiple extension elements are always combined together to make a single
157
+ `primitive element`_. In the case of ``[sqrt(2), sqrt(3)]`` the primitive
158
+ element chosen is ``sqrt(2) + sqrt(3)`` which is why the domain displays
159
+ as ``QQ<sqrt(2) + sqrt(3)>``. The minimal polynomial for the primitive
160
+ element is computed using the :py:func:`~.primitive_element` function.
161
+
162
+ >>> from sympy import primitive_element
163
+ >>> primitive_element([sqrt(2), sqrt(3)], x)
164
+ (x**4 - 10*x**2 + 1, [1, 1])
165
+ >>> minpoly(sqrt(2) + sqrt(3), x)
166
+ x**4 - 10*x**2 + 1
167
+
168
+ The extension elements that generate the domain can be accessed from the
169
+ domain using the :py:attr:`~.ext` and :py:attr:`~.orig_ext` attributes as
170
+ instances of :py:class:`~.AlgebraicNumber`. The minimal polynomial for
171
+ the primitive element as a :py:class:`~.DMP` instance is available as
172
+ :py:attr:`~.mod`.
173
+
174
+ >>> K = QQ.algebraic_field(sqrt(2), sqrt(3))
175
+ >>> K
176
+ QQ<sqrt(2) + sqrt(3)>
177
+ >>> K.ext
178
+ sqrt(2) + sqrt(3)
179
+ >>> K.orig_ext
180
+ (sqrt(2), sqrt(3))
181
+ >>> K.mod # doctest: +SKIP
182
+ DMP_Python([1, 0, -10, 0, 1], QQ)
183
+
184
+ The `discriminant`_ of the field can be obtained from the
185
+ :py:meth:`~.discriminant` method, and an `integral basis`_ from the
186
+ :py:meth:`~.integral_basis` method. The latter returns a list of
187
+ :py:class:`~.ANP` instances by default, but can be made to return instances
188
+ of :py:class:`~.Expr` or :py:class:`~.AlgebraicNumber` by passing a ``fmt``
189
+ argument. The maximal order, or ring of integers, of the field can also be
190
+ obtained from the :py:meth:`~.maximal_order` method, as a
191
+ :py:class:`~sympy.polys.numberfields.modules.Submodule`.
192
+
193
+ >>> zeta5 = exp(2*I*pi/5)
194
+ >>> K = QQ.algebraic_field(zeta5)
195
+ >>> K
196
+ QQ<exp(2*I*pi/5)>
197
+ >>> K.discriminant()
198
+ 125
199
+ >>> K = QQ.algebraic_field(sqrt(5))
200
+ >>> K
201
+ QQ<sqrt(5)>
202
+ >>> K.integral_basis(fmt='sympy')
203
+ [1, 1/2 + sqrt(5)/2]
204
+ >>> K.maximal_order()
205
+ Submodule[[2, 0], [1, 1]]/2
206
+
207
+ The factorization of a rational prime into prime ideals of the field is
208
+ computed by the :py:meth:`~.primes_above` method, which returns a list
209
+ of :py:class:`~sympy.polys.numberfields.primes.PrimeIdeal` instances.
210
+
211
+ >>> zeta7 = exp(2*I*pi/7)
212
+ >>> K = QQ.algebraic_field(zeta7)
213
+ >>> K
214
+ QQ<exp(2*I*pi/7)>
215
+ >>> K.primes_above(11)
216
+ [(11, _x**3 + 5*_x**2 + 4*_x - 1), (11, _x**3 - 4*_x**2 - 5*_x - 1)]
217
+
218
+ The Galois group of the Galois closure of the field can be computed (when
219
+ the minimal polynomial of the field is of sufficiently small degree).
220
+
221
+ >>> K.galois_group(by_name=True)[0]
222
+ S6TransitiveSubgroups.C6
223
+
224
+ Notes
225
+ =====
226
+
227
+ It is not currently possible to generate an algebraic extension over any
228
+ domain other than :ref:`QQ`. Ideally it would be possible to generate
229
+ extensions like ``QQ(x)(sqrt(x**2 - 2))``. This is equivalent to the
230
+ quotient ring ``QQ(x)[y]/(y**2 - x**2 + 2)`` and there are two
231
+ implementations of this kind of quotient ring/extension in the
232
+ :py:class:`~.QuotientRing` and :py:class:`~.MonogenicFiniteExtension`
233
+ classes. Each of those implementations needs some work to make them fully
234
+ usable though.
235
+
236
+ .. _algebraic number field: https://en.wikipedia.org/wiki/Algebraic_number_field
237
+ .. _algebraic numbers: https://en.wikipedia.org/wiki/Algebraic_number
238
+ .. _discriminant: https://en.wikipedia.org/wiki/Discriminant_of_an_algebraic_number_field
239
+ .. _integral basis: https://en.wikipedia.org/wiki/Algebraic_number_field#Integral_basis
240
+ .. _minimal polynomial: https://en.wikipedia.org/wiki/Minimal_polynomial_(field_theory)
241
+ .. _primitive element: https://en.wikipedia.org/wiki/Primitive_element_theorem
242
+ """
243
+
244
+ dtype = ANP
245
+
246
+ is_AlgebraicField = is_Algebraic = True
247
+ is_Numerical = True
248
+
249
+ has_assoc_Ring = False
250
+ has_assoc_Field = True
251
+
252
+ def __init__(self, dom, *ext, alias=None):
253
+ r"""
254
+ Parameters
255
+ ==========
256
+
257
+ dom : :py:class:`~.Domain`
258
+ The base field over which this is an extension field.
259
+ Currently only :ref:`QQ` is accepted.
260
+
261
+ *ext : One or more :py:class:`~.Expr`
262
+ Generators of the extension. These should be expressions that are
263
+ algebraic over `\mathbb{Q}`.
264
+
265
+ alias : str, :py:class:`~.Symbol`, None, optional (default=None)
266
+ If provided, this will be used as the alias symbol for the
267
+ primitive element of the :py:class:`~.AlgebraicField`.
268
+ If ``None``, while ``ext`` consists of exactly one
269
+ :py:class:`~.AlgebraicNumber`, its alias (if any) will be used.
270
+ """
271
+ if not dom.is_QQ:
272
+ raise DomainError("ground domain must be a rational field")
273
+
274
+ from sympy.polys.numberfields import to_number_field
275
+ if len(ext) == 1 and isinstance(ext[0], tuple):
276
+ orig_ext = ext[0][1:]
277
+ else:
278
+ orig_ext = ext
279
+
280
+ if alias is None and len(ext) == 1:
281
+ alias = getattr(ext[0], 'alias', None)
282
+
283
+ self.orig_ext = orig_ext
284
+ """
285
+ Original elements given to generate the extension.
286
+
287
+ >>> from sympy import QQ, sqrt
288
+ >>> K = QQ.algebraic_field(sqrt(2), sqrt(3))
289
+ >>> K.orig_ext
290
+ (sqrt(2), sqrt(3))
291
+ """
292
+
293
+ self.ext = to_number_field(ext, alias=alias)
294
+ """
295
+ Primitive element used for the extension.
296
+
297
+ >>> from sympy import QQ, sqrt
298
+ >>> K = QQ.algebraic_field(sqrt(2), sqrt(3))
299
+ >>> K.ext
300
+ sqrt(2) + sqrt(3)
301
+ """
302
+
303
+ self.mod = self.ext.minpoly.rep
304
+ """
305
+ Minimal polynomial for the primitive element of the extension.
306
+
307
+ >>> from sympy import QQ, sqrt
308
+ >>> K = QQ.algebraic_field(sqrt(2))
309
+ >>> K.mod
310
+ DMP([1, 0, -2], QQ)
311
+ """
312
+
313
+ self.domain = self.dom = dom
314
+
315
+ self.ngens = 1
316
+ self.symbols = self.gens = (self.ext,)
317
+ self.unit = self([dom(1), dom(0)])
318
+
319
+ self.zero = self.dtype.zero(self.mod.to_list(), dom)
320
+ self.one = self.dtype.one(self.mod.to_list(), dom)
321
+
322
+ self._maximal_order = None
323
+ self._discriminant = None
324
+ self._nilradicals_mod_p = {}
325
+
326
+ def new(self, element):
327
+ return self.dtype(element, self.mod.to_list(), self.dom)
328
+
329
+ def __str__(self):
330
+ return str(self.dom) + '<' + str(self.ext) + '>'
331
+
332
+ def __hash__(self):
333
+ return hash((self.__class__.__name__, self.dtype, self.dom, self.ext))
334
+
335
+ def __eq__(self, other):
336
+ """Returns ``True`` if two domains are equivalent. """
337
+ if isinstance(other, AlgebraicField):
338
+ return self.dtype == other.dtype and self.ext == other.ext
339
+ else:
340
+ return NotImplemented
341
+
342
+ def algebraic_field(self, *extension, alias=None):
343
+ r"""Returns an algebraic field, i.e. `\mathbb{Q}(\alpha, \ldots)`. """
344
+ return AlgebraicField(self.dom, *((self.ext,) + extension), alias=alias)
345
+
346
+ def to_alg_num(self, a):
347
+ """Convert ``a`` of ``dtype`` to an :py:class:`~.AlgebraicNumber`. """
348
+ return self.ext.field_element(a)
349
+
350
+ def to_sympy(self, a):
351
+ """Convert ``a`` of ``dtype`` to a SymPy object. """
352
+ # Precompute a converter to be reused:
353
+ if not hasattr(self, '_converter'):
354
+ self._converter = _make_converter(self)
355
+
356
+ return self._converter(a)
357
+
358
+ def from_sympy(self, a):
359
+ """Convert SymPy's expression to ``dtype``. """
360
+ try:
361
+ return self([self.dom.from_sympy(a)])
362
+ except CoercionFailed:
363
+ pass
364
+
365
+ from sympy.polys.numberfields import to_number_field
366
+
367
+ try:
368
+ return self(to_number_field(a, self.ext).native_coeffs())
369
+ except (NotAlgebraic, IsomorphismFailed):
370
+ raise CoercionFailed(
371
+ "%s is not a valid algebraic number in %s" % (a, self))
372
+
373
+ def from_ZZ(K1, a, K0):
374
+ """Convert a Python ``int`` object to ``dtype``. """
375
+ return K1(K1.dom.convert(a, K0))
376
+
377
+ def from_ZZ_python(K1, a, K0):
378
+ """Convert a Python ``int`` object to ``dtype``. """
379
+ return K1(K1.dom.convert(a, K0))
380
+
381
+ def from_QQ(K1, a, K0):
382
+ """Convert a Python ``Fraction`` object to ``dtype``. """
383
+ return K1(K1.dom.convert(a, K0))
384
+
385
+ def from_QQ_python(K1, a, K0):
386
+ """Convert a Python ``Fraction`` object to ``dtype``. """
387
+ return K1(K1.dom.convert(a, K0))
388
+
389
+ def from_ZZ_gmpy(K1, a, K0):
390
+ """Convert a GMPY ``mpz`` object to ``dtype``. """
391
+ return K1(K1.dom.convert(a, K0))
392
+
393
+ def from_QQ_gmpy(K1, a, K0):
394
+ """Convert a GMPY ``mpq`` object to ``dtype``. """
395
+ return K1(K1.dom.convert(a, K0))
396
+
397
+ def from_RealField(K1, a, K0):
398
+ """Convert a mpmath ``mpf`` object to ``dtype``. """
399
+ return K1(K1.dom.convert(a, K0))
400
+
401
+ def get_ring(self):
402
+ """Returns a ring associated with ``self``. """
403
+ raise DomainError('there is no ring associated with %s' % self)
404
+
405
+ def is_positive(self, a):
406
+ """Returns True if ``a`` is positive. """
407
+ return self.dom.is_positive(a.LC())
408
+
409
+ def is_negative(self, a):
410
+ """Returns True if ``a`` is negative. """
411
+ return self.dom.is_negative(a.LC())
412
+
413
+ def is_nonpositive(self, a):
414
+ """Returns True if ``a`` is non-positive. """
415
+ return self.dom.is_nonpositive(a.LC())
416
+
417
+ def is_nonnegative(self, a):
418
+ """Returns True if ``a`` is non-negative. """
419
+ return self.dom.is_nonnegative(a.LC())
420
+
421
+ def numer(self, a):
422
+ """Returns numerator of ``a``. """
423
+ return a
424
+
425
+ def denom(self, a):
426
+ """Returns denominator of ``a``. """
427
+ return self.one
428
+
429
+ def from_AlgebraicField(K1, a, K0):
430
+ """Convert AlgebraicField element 'a' to another AlgebraicField """
431
+ return K1.from_sympy(K0.to_sympy(a))
432
+
433
+ def from_GaussianIntegerRing(K1, a, K0):
434
+ """Convert a GaussianInteger element 'a' to ``dtype``. """
435
+ return K1.from_sympy(K0.to_sympy(a))
436
+
437
+ def from_GaussianRationalField(K1, a, K0):
438
+ """Convert a GaussianRational element 'a' to ``dtype``. """
439
+ return K1.from_sympy(K0.to_sympy(a))
440
+
441
+ def _do_round_two(self):
442
+ from sympy.polys.numberfields.basis import round_two
443
+ ZK, dK = round_two(self, radicals=self._nilradicals_mod_p)
444
+ self._maximal_order = ZK
445
+ self._discriminant = dK
446
+
447
+ def maximal_order(self):
448
+ """
449
+ Compute the maximal order, or ring of integers, of the field.
450
+
451
+ Returns
452
+ =======
453
+
454
+ :py:class:`~sympy.polys.numberfields.modules.Submodule`.
455
+
456
+ See Also
457
+ ========
458
+
459
+ integral_basis
460
+
461
+ """
462
+ if self._maximal_order is None:
463
+ self._do_round_two()
464
+ return self._maximal_order
465
+
466
+ def integral_basis(self, fmt=None):
467
+ r"""
468
+ Get an integral basis for the field.
469
+
470
+ Parameters
471
+ ==========
472
+
473
+ fmt : str, None, optional (default=None)
474
+ If ``None``, return a list of :py:class:`~.ANP` instances.
475
+ If ``"sympy"``, convert each element of the list to an
476
+ :py:class:`~.Expr`, using ``self.to_sympy()``.
477
+ If ``"alg"``, convert each element of the list to an
478
+ :py:class:`~.AlgebraicNumber`, using ``self.to_alg_num()``.
479
+
480
+ Examples
481
+ ========
482
+
483
+ >>> from sympy import QQ, AlgebraicNumber, sqrt
484
+ >>> alpha = AlgebraicNumber(sqrt(5), alias='alpha')
485
+ >>> k = QQ.algebraic_field(alpha)
486
+ >>> B0 = k.integral_basis()
487
+ >>> B1 = k.integral_basis(fmt='sympy')
488
+ >>> B2 = k.integral_basis(fmt='alg')
489
+ >>> print(B0[1]) # doctest: +SKIP
490
+ ANP([mpq(1,2), mpq(1,2)], [mpq(1,1), mpq(0,1), mpq(-5,1)], QQ)
491
+ >>> print(B1[1])
492
+ 1/2 + alpha/2
493
+ >>> print(B2[1])
494
+ alpha/2 + 1/2
495
+
496
+ In the last two cases we get legible expressions, which print somewhat
497
+ differently because of the different types involved:
498
+
499
+ >>> print(type(B1[1]))
500
+ <class 'sympy.core.add.Add'>
501
+ >>> print(type(B2[1]))
502
+ <class 'sympy.core.numbers.AlgebraicNumber'>
503
+
504
+ See Also
505
+ ========
506
+
507
+ to_sympy
508
+ to_alg_num
509
+ maximal_order
510
+ """
511
+ ZK = self.maximal_order()
512
+ M = ZK.QQ_matrix
513
+ n = M.shape[1]
514
+ B = [self.new(list(reversed(M[:, j].flat()))) for j in range(n)]
515
+ if fmt == 'sympy':
516
+ return [self.to_sympy(b) for b in B]
517
+ elif fmt == 'alg':
518
+ return [self.to_alg_num(b) for b in B]
519
+ return B
520
+
521
+ def discriminant(self):
522
+ """Get the discriminant of the field."""
523
+ if self._discriminant is None:
524
+ self._do_round_two()
525
+ return self._discriminant
526
+
527
+ def primes_above(self, p):
528
+ """Compute the prime ideals lying above a given rational prime *p*."""
529
+ from sympy.polys.numberfields.primes import prime_decomp
530
+ ZK = self.maximal_order()
531
+ dK = self.discriminant()
532
+ rad = self._nilradicals_mod_p.get(p)
533
+ return prime_decomp(p, ZK=ZK, dK=dK, radical=rad)
534
+
535
+ def galois_group(self, by_name=False, max_tries=30, randomize=False):
536
+ """
537
+ Compute the Galois group of the Galois closure of this field.
538
+
539
+ Examples
540
+ ========
541
+
542
+ If the field is Galois, the order of the group will equal the degree
543
+ of the field:
544
+
545
+ >>> from sympy import QQ
546
+ >>> from sympy.abc import x
547
+ >>> k = QQ.alg_field_from_poly(x**4 + 1)
548
+ >>> G, _ = k.galois_group()
549
+ >>> G.order()
550
+ 4
551
+
552
+ If the field is not Galois, then its Galois closure is a proper
553
+ extension, and the order of the Galois group will be greater than the
554
+ degree of the field:
555
+
556
+ >>> k = QQ.alg_field_from_poly(x**4 - 2)
557
+ >>> G, _ = k.galois_group()
558
+ >>> G.order()
559
+ 8
560
+
561
+ See Also
562
+ ========
563
+
564
+ sympy.polys.numberfields.galoisgroups.galois_group
565
+
566
+ """
567
+ return self.ext.minpoly_of_element().galois_group(
568
+ by_name=by_name, max_tries=max_tries, randomize=randomize)
569
+
570
+
571
+ def _make_converter(K):
572
+ """Construct the converter to convert back to Expr"""
573
+ # Precompute the effect of converting to SymPy and expanding expressions
574
+ # like (sqrt(2) + sqrt(3))**2. Asking Expr to do the expansion on every
575
+ # conversion from K to Expr is slow. Here we compute the expansions for
576
+ # each power of the generator and collect together the resulting algebraic
577
+ # terms and the rational coefficients into a matrix.
578
+
579
+ gen = K.ext.as_expr()
580
+ todom = K.dom.from_sympy
581
+
582
+ # We'll let Expr compute the expansions. We won't make any presumptions
583
+ # about what this results in except that it is QQ-linear in some terms
584
+ # that we will call algebraics. The final result will be expressed in
585
+ # terms of those.
586
+ powers = [S.One, gen]
587
+ for n in range(2, K.mod.degree()):
588
+ powers.append((gen * powers[-1]).expand())
589
+
590
+ # Collect the rational coefficients and algebraic Expr that can
591
+ # map the ANP coefficients into an expanded SymPy expression
592
+ terms = [dict(t.as_coeff_Mul()[::-1] for t in Add.make_args(p)) for p in powers]
593
+ algebraics = set().union(*terms)
594
+ matrix = [[todom(t.get(a, S.Zero)) for t in terms] for a in algebraics]
595
+
596
+ # Create a function to do the conversion efficiently:
597
+
598
+ def converter(a):
599
+ """Convert a to Expr using converter"""
600
+ ai = a.to_list()[::-1]
601
+ tosympy = K.dom.to_sympy
602
+ coeffs_dom = [sum(mij*aj for mij, aj in zip(mi, ai)) for mi in matrix]
603
+ coeffs_sympy = [tosympy(c) for c in coeffs_dom]
604
+ res = Add(*(Mul(c, a) for c, a in zip(coeffs_sympy, algebraics)))
605
+ return res
606
+
607
+ return converter
lib/python3.12/site-packages/sympy/polys/domains/characteristiczero.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of :class:`CharacteristicZero` class. """
2
+
3
+
4
+ from sympy.polys.domains.domain import Domain
5
+ from sympy.utilities import public
6
+
7
+ @public
8
+ class CharacteristicZero(Domain):
9
+ """Domain that has infinite number of elements. """
10
+
11
+ has_CharacteristicZero = True
12
+
13
+ def characteristic(self):
14
+ """Return the characteristic of this domain. """
15
+ return 0
lib/python3.12/site-packages/sympy/polys/domains/complexfield.py ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of :class:`ComplexField` class. """
2
+
3
+
4
+ from sympy.external.gmpy import SYMPY_INTS
5
+ from sympy.core.numbers import Float, I
6
+ from sympy.polys.domains.characteristiczero import CharacteristicZero
7
+ from sympy.polys.domains.field import Field
8
+ from sympy.polys.domains.gaussiandomains import QQ_I
9
+ from sympy.polys.domains.mpelements import MPContext
10
+ from sympy.polys.domains.simpledomain import SimpleDomain
11
+ from sympy.polys.polyerrors import DomainError, CoercionFailed
12
+ from sympy.utilities import public
13
+
14
+ @public
15
+ class ComplexField(Field, CharacteristicZero, SimpleDomain):
16
+ """Complex numbers up to the given precision. """
17
+
18
+ rep = 'CC'
19
+
20
+ is_ComplexField = is_CC = True
21
+
22
+ is_Exact = False
23
+ is_Numerical = True
24
+
25
+ has_assoc_Ring = False
26
+ has_assoc_Field = True
27
+
28
+ _default_precision = 53
29
+
30
+ @property
31
+ def has_default_precision(self):
32
+ return self.precision == self._default_precision
33
+
34
+ @property
35
+ def precision(self):
36
+ return self._context.prec
37
+
38
+ @property
39
+ def dps(self):
40
+ return self._context.dps
41
+
42
+ @property
43
+ def tolerance(self):
44
+ return self._context.tolerance
45
+
46
+ def __init__(self, prec=_default_precision, dps=None, tol=None):
47
+ context = MPContext(prec, dps, tol, False)
48
+ context._parent = self
49
+ self._context = context
50
+
51
+ self._dtype = context.mpc
52
+ self.zero = self.dtype(0)
53
+ self.one = self.dtype(1)
54
+
55
+ @property
56
+ def tp(self):
57
+ # XXX: Domain treats tp as an alis of dtype. Here we need to two
58
+ # separate things: dtype is a callable to make/convert instances.
59
+ # We use tp with isinstance to check if an object is an instance
60
+ # of the domain already.
61
+ return self._dtype
62
+
63
+ def dtype(self, x, y=0):
64
+ # XXX: This is needed because mpmath does not recognise fmpz.
65
+ # It might be better to add conversion routines to mpmath and if that
66
+ # happens then this can be removed.
67
+ if isinstance(x, SYMPY_INTS):
68
+ x = int(x)
69
+ if isinstance(y, SYMPY_INTS):
70
+ y = int(y)
71
+ return self._dtype(x, y)
72
+
73
+ def __eq__(self, other):
74
+ return (isinstance(other, ComplexField)
75
+ and self.precision == other.precision
76
+ and self.tolerance == other.tolerance)
77
+
78
+ def __hash__(self):
79
+ return hash((self.__class__.__name__, self._dtype, self.precision, self.tolerance))
80
+
81
+ def to_sympy(self, element):
82
+ """Convert ``element`` to SymPy number. """
83
+ return Float(element.real, self.dps) + I*Float(element.imag, self.dps)
84
+
85
+ def from_sympy(self, expr):
86
+ """Convert SymPy's number to ``dtype``. """
87
+ number = expr.evalf(n=self.dps)
88
+ real, imag = number.as_real_imag()
89
+
90
+ if real.is_Number and imag.is_Number:
91
+ return self.dtype(real, imag)
92
+ else:
93
+ raise CoercionFailed("expected complex number, got %s" % expr)
94
+
95
+ def from_ZZ(self, element, base):
96
+ return self.dtype(element)
97
+
98
+ def from_ZZ_gmpy(self, element, base):
99
+ return self.dtype(int(element))
100
+
101
+ def from_ZZ_python(self, element, base):
102
+ return self.dtype(element)
103
+
104
+ def from_QQ(self, element, base):
105
+ return self.dtype(int(element.numerator)) / int(element.denominator)
106
+
107
+ def from_QQ_python(self, element, base):
108
+ return self.dtype(element.numerator) / element.denominator
109
+
110
+ def from_QQ_gmpy(self, element, base):
111
+ return self.dtype(int(element.numerator)) / int(element.denominator)
112
+
113
+ def from_GaussianIntegerRing(self, element, base):
114
+ return self.dtype(int(element.x), int(element.y))
115
+
116
+ def from_GaussianRationalField(self, element, base):
117
+ x = element.x
118
+ y = element.y
119
+ return (self.dtype(int(x.numerator)) / int(x.denominator) +
120
+ self.dtype(0, int(y.numerator)) / int(y.denominator))
121
+
122
+ def from_AlgebraicField(self, element, base):
123
+ return self.from_sympy(base.to_sympy(element).evalf(self.dps))
124
+
125
+ def from_RealField(self, element, base):
126
+ return self.dtype(element)
127
+
128
+ def from_ComplexField(self, element, base):
129
+ if self == base:
130
+ return element
131
+ else:
132
+ return self.dtype(element)
133
+
134
+ def get_ring(self):
135
+ """Returns a ring associated with ``self``. """
136
+ raise DomainError("there is no ring associated with %s" % self)
137
+
138
+ def get_exact(self):
139
+ """Returns an exact domain associated with ``self``. """
140
+ return QQ_I
141
+
142
+ def is_negative(self, element):
143
+ """Returns ``False`` for any ``ComplexElement``. """
144
+ return False
145
+
146
+ def is_positive(self, element):
147
+ """Returns ``False`` for any ``ComplexElement``. """
148
+ return False
149
+
150
+ def is_nonnegative(self, element):
151
+ """Returns ``False`` for any ``ComplexElement``. """
152
+ return False
153
+
154
+ def is_nonpositive(self, element):
155
+ """Returns ``False`` for any ``ComplexElement``. """
156
+ return False
157
+
158
+ def gcd(self, a, b):
159
+ """Returns GCD of ``a`` and ``b``. """
160
+ return self.one
161
+
162
+ def lcm(self, a, b):
163
+ """Returns LCM of ``a`` and ``b``. """
164
+ return a*b
165
+
166
+ def almosteq(self, a, b, tolerance=None):
167
+ """Check if ``a`` and ``b`` are almost equal. """
168
+ return self._context.almosteq(a, b, tolerance)
169
+
170
+ def is_square(self, a):
171
+ """Returns ``True``. Every complex number has a complex square root."""
172
+ return True
173
+
174
+ def exsqrt(self, a):
175
+ r"""Returns the principal complex square root of ``a``.
176
+
177
+ Explanation
178
+ ===========
179
+ The argument of the principal square root is always within
180
+ $(-\frac{\pi}{2}, \frac{\pi}{2}]$. The square root may be
181
+ slightly inaccurate due to floating point rounding error.
182
+ """
183
+ return a ** 0.5
184
+
185
+ CC = ComplexField()
lib/python3.12/site-packages/sympy/polys/domains/compositedomain.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of :class:`CompositeDomain` class. """
2
+
3
+
4
+ from sympy.polys.domains.domain import Domain
5
+ from sympy.polys.polyerrors import GeneratorsError
6
+
7
+ from sympy.utilities import public
8
+
9
+ @public
10
+ class CompositeDomain(Domain):
11
+ """Base class for composite domains, e.g. ZZ[x], ZZ(X). """
12
+
13
+ is_Composite = True
14
+
15
+ gens, ngens, symbols, domain = [None]*4
16
+
17
+ def inject(self, *symbols):
18
+ """Inject generators into this domain. """
19
+ if not (set(self.symbols) & set(symbols)):
20
+ return self.__class__(self.domain, self.symbols + symbols, self.order)
21
+ else:
22
+ raise GeneratorsError("common generators in %s and %s" % (self.symbols, symbols))
23
+
24
+ def drop(self, *symbols):
25
+ """Drop generators from this domain. """
26
+ symset = set(symbols)
27
+ newsyms = tuple(s for s in self.symbols if s not in symset)
28
+ domain = self.domain.drop(*symbols)
29
+ if not newsyms:
30
+ return domain
31
+ else:
32
+ return self.__class__(domain, newsyms, self.order)
33
+
34
+ def set_domain(self, domain):
35
+ """Set the ground domain of this domain. """
36
+ return self.__class__(domain, self.symbols, self.order)
37
+
38
+ @property
39
+ def is_Exact(self):
40
+ """Returns ``True`` if this domain is exact. """
41
+ return self.domain.is_Exact
42
+
43
+ def get_exact(self):
44
+ """Returns an exact version of this domain. """
45
+ return self.set_domain(self.domain.get_exact())
46
+
47
+ @property
48
+ def has_CharacteristicZero(self):
49
+ return self.domain.has_CharacteristicZero
50
+
51
+ def characteristic(self):
52
+ return self.domain.characteristic()
lib/python3.12/site-packages/sympy/polys/domains/domain.py ADDED
@@ -0,0 +1,1372 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of :class:`Domain` class. """
2
+
3
+ from __future__ import annotations
4
+ from typing import Any
5
+
6
+ from sympy.core.numbers import AlgebraicNumber
7
+ from sympy.core import Basic, sympify
8
+ from sympy.core.sorting import ordered
9
+ from sympy.external.gmpy import GROUND_TYPES
10
+ from sympy.polys.domains.domainelement import DomainElement
11
+ from sympy.polys.orderings import lex
12
+ from sympy.polys.polyerrors import UnificationFailed, CoercionFailed, DomainError
13
+ from sympy.polys.polyutils import _unify_gens, _not_a_coeff
14
+ from sympy.utilities import public
15
+ from sympy.utilities.iterables import is_sequence
16
+
17
+
18
+ @public
19
+ class Domain:
20
+ """Superclass for all domains in the polys domains system.
21
+
22
+ See :ref:`polys-domainsintro` for an introductory explanation of the
23
+ domains system.
24
+
25
+ The :py:class:`~.Domain` class is an abstract base class for all of the
26
+ concrete domain types. There are many different :py:class:`~.Domain`
27
+ subclasses each of which has an associated ``dtype`` which is a class
28
+ representing the elements of the domain. The coefficients of a
29
+ :py:class:`~.Poly` are elements of a domain which must be a subclass of
30
+ :py:class:`~.Domain`.
31
+
32
+ Examples
33
+ ========
34
+
35
+ The most common example domains are the integers :ref:`ZZ` and the
36
+ rationals :ref:`QQ`.
37
+
38
+ >>> from sympy import Poly, symbols, Domain
39
+ >>> x, y = symbols('x, y')
40
+ >>> p = Poly(x**2 + y)
41
+ >>> p
42
+ Poly(x**2 + y, x, y, domain='ZZ')
43
+ >>> p.domain
44
+ ZZ
45
+ >>> isinstance(p.domain, Domain)
46
+ True
47
+ >>> Poly(x**2 + y/2)
48
+ Poly(x**2 + 1/2*y, x, y, domain='QQ')
49
+
50
+ The domains can be used directly in which case the domain object e.g.
51
+ (:ref:`ZZ` or :ref:`QQ`) can be used as a constructor for elements of
52
+ ``dtype``.
53
+
54
+ >>> from sympy import ZZ, QQ
55
+ >>> ZZ(2)
56
+ 2
57
+ >>> ZZ.dtype # doctest: +SKIP
58
+ <class 'int'>
59
+ >>> type(ZZ(2)) # doctest: +SKIP
60
+ <class 'int'>
61
+ >>> QQ(1, 2)
62
+ 1/2
63
+ >>> type(QQ(1, 2)) # doctest: +SKIP
64
+ <class 'sympy.polys.domains.pythonrational.PythonRational'>
65
+
66
+ The corresponding domain elements can be used with the arithmetic
67
+ operations ``+,-,*,**`` and depending on the domain some combination of
68
+ ``/,//,%`` might be usable. For example in :ref:`ZZ` both ``//`` (floor
69
+ division) and ``%`` (modulo division) can be used but ``/`` (true
70
+ division) cannot. Since :ref:`QQ` is a :py:class:`~.Field` its elements
71
+ can be used with ``/`` but ``//`` and ``%`` should not be used. Some
72
+ domains have a :py:meth:`~.Domain.gcd` method.
73
+
74
+ >>> ZZ(2) + ZZ(3)
75
+ 5
76
+ >>> ZZ(5) // ZZ(2)
77
+ 2
78
+ >>> ZZ(5) % ZZ(2)
79
+ 1
80
+ >>> QQ(1, 2) / QQ(2, 3)
81
+ 3/4
82
+ >>> ZZ.gcd(ZZ(4), ZZ(2))
83
+ 2
84
+ >>> QQ.gcd(QQ(2,7), QQ(5,3))
85
+ 1/21
86
+ >>> ZZ.is_Field
87
+ False
88
+ >>> QQ.is_Field
89
+ True
90
+
91
+ There are also many other domains including:
92
+
93
+ 1. :ref:`GF(p)` for finite fields of prime order.
94
+ 2. :ref:`RR` for real (floating point) numbers.
95
+ 3. :ref:`CC` for complex (floating point) numbers.
96
+ 4. :ref:`QQ(a)` for algebraic number fields.
97
+ 5. :ref:`K[x]` for polynomial rings.
98
+ 6. :ref:`K(x)` for rational function fields.
99
+ 7. :ref:`EX` for arbitrary expressions.
100
+
101
+ Each domain is represented by a domain object and also an implementation
102
+ class (``dtype``) for the elements of the domain. For example the
103
+ :ref:`K[x]` domains are represented by a domain object which is an
104
+ instance of :py:class:`~.PolynomialRing` and the elements are always
105
+ instances of :py:class:`~.PolyElement`. The implementation class
106
+ represents particular types of mathematical expressions in a way that is
107
+ more efficient than a normal SymPy expression which is of type
108
+ :py:class:`~.Expr`. The domain methods :py:meth:`~.Domain.from_sympy` and
109
+ :py:meth:`~.Domain.to_sympy` are used to convert from :py:class:`~.Expr`
110
+ to a domain element and vice versa.
111
+
112
+ >>> from sympy import Symbol, ZZ, Expr
113
+ >>> x = Symbol('x')
114
+ >>> K = ZZ[x] # polynomial ring domain
115
+ >>> K
116
+ ZZ[x]
117
+ >>> type(K) # class of the domain
118
+ <class 'sympy.polys.domains.polynomialring.PolynomialRing'>
119
+ >>> K.dtype # class of the elements
120
+ <class 'sympy.polys.rings.PolyElement'>
121
+ >>> p_expr = x**2 + 1 # Expr
122
+ >>> p_expr
123
+ x**2 + 1
124
+ >>> type(p_expr)
125
+ <class 'sympy.core.add.Add'>
126
+ >>> isinstance(p_expr, Expr)
127
+ True
128
+ >>> p_domain = K.from_sympy(p_expr)
129
+ >>> p_domain # domain element
130
+ x**2 + 1
131
+ >>> type(p_domain)
132
+ <class 'sympy.polys.rings.PolyElement'>
133
+ >>> K.to_sympy(p_domain) == p_expr
134
+ True
135
+
136
+ The :py:meth:`~.Domain.convert_from` method is used to convert domain
137
+ elements from one domain to another.
138
+
139
+ >>> from sympy import ZZ, QQ
140
+ >>> ez = ZZ(2)
141
+ >>> eq = QQ.convert_from(ez, ZZ)
142
+ >>> type(ez) # doctest: +SKIP
143
+ <class 'int'>
144
+ >>> type(eq) # doctest: +SKIP
145
+ <class 'sympy.polys.domains.pythonrational.PythonRational'>
146
+
147
+ Elements from different domains should not be mixed in arithmetic or other
148
+ operations: they should be converted to a common domain first. The domain
149
+ method :py:meth:`~.Domain.unify` is used to find a domain that can
150
+ represent all the elements of two given domains.
151
+
152
+ >>> from sympy import ZZ, QQ, symbols
153
+ >>> x, y = symbols('x, y')
154
+ >>> ZZ.unify(QQ)
155
+ QQ
156
+ >>> ZZ[x].unify(QQ)
157
+ QQ[x]
158
+ >>> ZZ[x].unify(QQ[y])
159
+ QQ[x,y]
160
+
161
+ If a domain is a :py:class:`~.Ring` then is might have an associated
162
+ :py:class:`~.Field` and vice versa. The :py:meth:`~.Domain.get_field` and
163
+ :py:meth:`~.Domain.get_ring` methods will find or create the associated
164
+ domain.
165
+
166
+ >>> from sympy import ZZ, QQ, Symbol
167
+ >>> x = Symbol('x')
168
+ >>> ZZ.has_assoc_Field
169
+ True
170
+ >>> ZZ.get_field()
171
+ QQ
172
+ >>> QQ.has_assoc_Ring
173
+ True
174
+ >>> QQ.get_ring()
175
+ ZZ
176
+ >>> K = QQ[x]
177
+ >>> K
178
+ QQ[x]
179
+ >>> K.get_field()
180
+ QQ(x)
181
+
182
+ See also
183
+ ========
184
+
185
+ DomainElement: abstract base class for domain elements
186
+ construct_domain: construct a minimal domain for some expressions
187
+
188
+ """
189
+
190
+ dtype: type | None = None
191
+ """The type (class) of the elements of this :py:class:`~.Domain`:
192
+
193
+ >>> from sympy import ZZ, QQ, Symbol
194
+ >>> ZZ.dtype
195
+ <class 'int'>
196
+ >>> z = ZZ(2)
197
+ >>> z
198
+ 2
199
+ >>> type(z)
200
+ <class 'int'>
201
+ >>> type(z) == ZZ.dtype
202
+ True
203
+
204
+ Every domain has an associated **dtype** ("datatype") which is the
205
+ class of the associated domain elements.
206
+
207
+ See also
208
+ ========
209
+
210
+ of_type
211
+ """
212
+
213
+ zero: Any = None
214
+ """The zero element of the :py:class:`~.Domain`:
215
+
216
+ >>> from sympy import QQ
217
+ >>> QQ.zero
218
+ 0
219
+ >>> QQ.of_type(QQ.zero)
220
+ True
221
+
222
+ See also
223
+ ========
224
+
225
+ of_type
226
+ one
227
+ """
228
+
229
+ one: Any = None
230
+ """The one element of the :py:class:`~.Domain`:
231
+
232
+ >>> from sympy import QQ
233
+ >>> QQ.one
234
+ 1
235
+ >>> QQ.of_type(QQ.one)
236
+ True
237
+
238
+ See also
239
+ ========
240
+
241
+ of_type
242
+ zero
243
+ """
244
+
245
+ is_Ring = False
246
+ """Boolean flag indicating if the domain is a :py:class:`~.Ring`.
247
+
248
+ >>> from sympy import ZZ
249
+ >>> ZZ.is_Ring
250
+ True
251
+
252
+ Basically every :py:class:`~.Domain` represents a ring so this flag is
253
+ not that useful.
254
+
255
+ See also
256
+ ========
257
+
258
+ is_PID
259
+ is_Field
260
+ get_ring
261
+ has_assoc_Ring
262
+ """
263
+
264
+ is_Field = False
265
+ """Boolean flag indicating if the domain is a :py:class:`~.Field`.
266
+
267
+ >>> from sympy import ZZ, QQ
268
+ >>> ZZ.is_Field
269
+ False
270
+ >>> QQ.is_Field
271
+ True
272
+
273
+ See also
274
+ ========
275
+
276
+ is_PID
277
+ is_Ring
278
+ get_field
279
+ has_assoc_Field
280
+ """
281
+
282
+ has_assoc_Ring = False
283
+ """Boolean flag indicating if the domain has an associated
284
+ :py:class:`~.Ring`.
285
+
286
+ >>> from sympy import QQ
287
+ >>> QQ.has_assoc_Ring
288
+ True
289
+ >>> QQ.get_ring()
290
+ ZZ
291
+
292
+ See also
293
+ ========
294
+
295
+ is_Field
296
+ get_ring
297
+ """
298
+
299
+ has_assoc_Field = False
300
+ """Boolean flag indicating if the domain has an associated
301
+ :py:class:`~.Field`.
302
+
303
+ >>> from sympy import ZZ
304
+ >>> ZZ.has_assoc_Field
305
+ True
306
+ >>> ZZ.get_field()
307
+ QQ
308
+
309
+ See also
310
+ ========
311
+
312
+ is_Field
313
+ get_field
314
+ """
315
+
316
+ is_FiniteField = is_FF = False
317
+ is_IntegerRing = is_ZZ = False
318
+ is_RationalField = is_QQ = False
319
+ is_GaussianRing = is_ZZ_I = False
320
+ is_GaussianField = is_QQ_I = False
321
+ is_RealField = is_RR = False
322
+ is_ComplexField = is_CC = False
323
+ is_AlgebraicField = is_Algebraic = False
324
+ is_PolynomialRing = is_Poly = False
325
+ is_FractionField = is_Frac = False
326
+ is_SymbolicDomain = is_EX = False
327
+ is_SymbolicRawDomain = is_EXRAW = False
328
+ is_FiniteExtension = False
329
+
330
+ is_Exact = True
331
+ is_Numerical = False
332
+
333
+ is_Simple = False
334
+ is_Composite = False
335
+
336
+ is_PID = False
337
+ """Boolean flag indicating if the domain is a `principal ideal domain`_.
338
+
339
+ >>> from sympy import ZZ
340
+ >>> ZZ.has_assoc_Field
341
+ True
342
+ >>> ZZ.get_field()
343
+ QQ
344
+
345
+ .. _principal ideal domain: https://en.wikipedia.org/wiki/Principal_ideal_domain
346
+
347
+ See also
348
+ ========
349
+
350
+ is_Field
351
+ get_field
352
+ """
353
+
354
+ has_CharacteristicZero = False
355
+
356
+ rep: str | None = None
357
+ alias: str | None = None
358
+
359
+ def __init__(self):
360
+ raise NotImplementedError
361
+
362
+ def __str__(self):
363
+ return self.rep
364
+
365
+ def __repr__(self):
366
+ return str(self)
367
+
368
+ def __hash__(self):
369
+ return hash((self.__class__.__name__, self.dtype))
370
+
371
+ def new(self, *args):
372
+ return self.dtype(*args)
373
+
374
+ @property
375
+ def tp(self):
376
+ """Alias for :py:attr:`~.Domain.dtype`"""
377
+ return self.dtype
378
+
379
+ def __call__(self, *args):
380
+ """Construct an element of ``self`` domain from ``args``. """
381
+ return self.new(*args)
382
+
383
+ def normal(self, *args):
384
+ return self.dtype(*args)
385
+
386
+ def convert_from(self, element, base):
387
+ """Convert ``element`` to ``self.dtype`` given the base domain. """
388
+ if base.alias is not None:
389
+ method = "from_" + base.alias
390
+ else:
391
+ method = "from_" + base.__class__.__name__
392
+
393
+ _convert = getattr(self, method)
394
+
395
+ if _convert is not None:
396
+ result = _convert(element, base)
397
+
398
+ if result is not None:
399
+ return result
400
+
401
+ raise CoercionFailed("Cannot convert %s of type %s from %s to %s" % (element, type(element), base, self))
402
+
403
+ def convert(self, element, base=None):
404
+ """Convert ``element`` to ``self.dtype``. """
405
+
406
+ if base is not None:
407
+ if _not_a_coeff(element):
408
+ raise CoercionFailed('%s is not in any domain' % element)
409
+ return self.convert_from(element, base)
410
+
411
+ if self.of_type(element):
412
+ return element
413
+
414
+ if _not_a_coeff(element):
415
+ raise CoercionFailed('%s is not in any domain' % element)
416
+
417
+ from sympy.polys.domains import ZZ, QQ, RealField, ComplexField
418
+
419
+ if ZZ.of_type(element):
420
+ return self.convert_from(element, ZZ)
421
+
422
+ if isinstance(element, int):
423
+ return self.convert_from(ZZ(element), ZZ)
424
+
425
+ if GROUND_TYPES != 'python':
426
+ if isinstance(element, ZZ.tp):
427
+ return self.convert_from(element, ZZ)
428
+ if isinstance(element, QQ.tp):
429
+ return self.convert_from(element, QQ)
430
+
431
+ if isinstance(element, float):
432
+ parent = RealField(tol=False)
433
+ return self.convert_from(parent(element), parent)
434
+
435
+ if isinstance(element, complex):
436
+ parent = ComplexField(tol=False)
437
+ return self.convert_from(parent(element), parent)
438
+
439
+ if isinstance(element, DomainElement):
440
+ return self.convert_from(element, element.parent())
441
+
442
+ # TODO: implement this in from_ methods
443
+ if self.is_Numerical and getattr(element, 'is_ground', False):
444
+ return self.convert(element.LC())
445
+
446
+ if isinstance(element, Basic):
447
+ try:
448
+ return self.from_sympy(element)
449
+ except (TypeError, ValueError):
450
+ pass
451
+ else: # TODO: remove this branch
452
+ if not is_sequence(element):
453
+ try:
454
+ element = sympify(element, strict=True)
455
+ if isinstance(element, Basic):
456
+ return self.from_sympy(element)
457
+ except (TypeError, ValueError):
458
+ pass
459
+
460
+ raise CoercionFailed("Cannot convert %s of type %s to %s" % (element, type(element), self))
461
+
462
+ def of_type(self, element):
463
+ """Check if ``a`` is of type ``dtype``. """
464
+ return isinstance(element, self.tp) # XXX: this isn't correct, e.g. PolyElement
465
+
466
+ def __contains__(self, a):
467
+ """Check if ``a`` belongs to this domain. """
468
+ try:
469
+ if _not_a_coeff(a):
470
+ raise CoercionFailed
471
+ self.convert(a) # this might raise, too
472
+ except CoercionFailed:
473
+ return False
474
+
475
+ return True
476
+
477
+ def to_sympy(self, a):
478
+ """Convert domain element *a* to a SymPy expression (Expr).
479
+
480
+ Explanation
481
+ ===========
482
+
483
+ Convert a :py:class:`~.Domain` element *a* to :py:class:`~.Expr`. Most
484
+ public SymPy functions work with objects of type :py:class:`~.Expr`.
485
+ The elements of a :py:class:`~.Domain` have a different internal
486
+ representation. It is not possible to mix domain elements with
487
+ :py:class:`~.Expr` so each domain has :py:meth:`~.Domain.to_sympy` and
488
+ :py:meth:`~.Domain.from_sympy` methods to convert its domain elements
489
+ to and from :py:class:`~.Expr`.
490
+
491
+ Parameters
492
+ ==========
493
+
494
+ a: domain element
495
+ An element of this :py:class:`~.Domain`.
496
+
497
+ Returns
498
+ =======
499
+
500
+ expr: Expr
501
+ A normal SymPy expression of type :py:class:`~.Expr`.
502
+
503
+ Examples
504
+ ========
505
+
506
+ Construct an element of the :ref:`QQ` domain and then convert it to
507
+ :py:class:`~.Expr`.
508
+
509
+ >>> from sympy import QQ, Expr
510
+ >>> q_domain = QQ(2)
511
+ >>> q_domain
512
+ 2
513
+ >>> q_expr = QQ.to_sympy(q_domain)
514
+ >>> q_expr
515
+ 2
516
+
517
+ Although the printed forms look similar these objects are not of the
518
+ same type.
519
+
520
+ >>> isinstance(q_domain, Expr)
521
+ False
522
+ >>> isinstance(q_expr, Expr)
523
+ True
524
+
525
+ Construct an element of :ref:`K[x]` and convert to
526
+ :py:class:`~.Expr`.
527
+
528
+ >>> from sympy import Symbol
529
+ >>> x = Symbol('x')
530
+ >>> K = QQ[x]
531
+ >>> x_domain = K.gens[0] # generator x as a domain element
532
+ >>> p_domain = x_domain**2/3 + 1
533
+ >>> p_domain
534
+ 1/3*x**2 + 1
535
+ >>> p_expr = K.to_sympy(p_domain)
536
+ >>> p_expr
537
+ x**2/3 + 1
538
+
539
+ The :py:meth:`~.Domain.from_sympy` method is used for the opposite
540
+ conversion from a normal SymPy expression to a domain element.
541
+
542
+ >>> p_domain == p_expr
543
+ False
544
+ >>> K.from_sympy(p_expr) == p_domain
545
+ True
546
+ >>> K.to_sympy(p_domain) == p_expr
547
+ True
548
+ >>> K.from_sympy(K.to_sympy(p_domain)) == p_domain
549
+ True
550
+ >>> K.to_sympy(K.from_sympy(p_expr)) == p_expr
551
+ True
552
+
553
+ The :py:meth:`~.Domain.from_sympy` method makes it easier to construct
554
+ domain elements interactively.
555
+
556
+ >>> from sympy import Symbol
557
+ >>> x = Symbol('x')
558
+ >>> K = QQ[x]
559
+ >>> K.from_sympy(x**2/3 + 1)
560
+ 1/3*x**2 + 1
561
+
562
+ See also
563
+ ========
564
+
565
+ from_sympy
566
+ convert_from
567
+ """
568
+ raise NotImplementedError
569
+
570
+ def from_sympy(self, a):
571
+ """Convert a SymPy expression to an element of this domain.
572
+
573
+ Explanation
574
+ ===========
575
+
576
+ See :py:meth:`~.Domain.to_sympy` for explanation and examples.
577
+
578
+ Parameters
579
+ ==========
580
+
581
+ expr: Expr
582
+ A normal SymPy expression of type :py:class:`~.Expr`.
583
+
584
+ Returns
585
+ =======
586
+
587
+ a: domain element
588
+ An element of this :py:class:`~.Domain`.
589
+
590
+ See also
591
+ ========
592
+
593
+ to_sympy
594
+ convert_from
595
+ """
596
+ raise NotImplementedError
597
+
598
+ def sum(self, args):
599
+ return sum(args, start=self.zero)
600
+
601
+ def from_FF(K1, a, K0):
602
+ """Convert ``ModularInteger(int)`` to ``dtype``. """
603
+ return None
604
+
605
+ def from_FF_python(K1, a, K0):
606
+ """Convert ``ModularInteger(int)`` to ``dtype``. """
607
+ return None
608
+
609
+ def from_ZZ_python(K1, a, K0):
610
+ """Convert a Python ``int`` object to ``dtype``. """
611
+ return None
612
+
613
+ def from_QQ_python(K1, a, K0):
614
+ """Convert a Python ``Fraction`` object to ``dtype``. """
615
+ return None
616
+
617
+ def from_FF_gmpy(K1, a, K0):
618
+ """Convert ``ModularInteger(mpz)`` to ``dtype``. """
619
+ return None
620
+
621
+ def from_ZZ_gmpy(K1, a, K0):
622
+ """Convert a GMPY ``mpz`` object to ``dtype``. """
623
+ return None
624
+
625
+ def from_QQ_gmpy(K1, a, K0):
626
+ """Convert a GMPY ``mpq`` object to ``dtype``. """
627
+ return None
628
+
629
+ def from_RealField(K1, a, K0):
630
+ """Convert a real element object to ``dtype``. """
631
+ return None
632
+
633
+ def from_ComplexField(K1, a, K0):
634
+ """Convert a complex element to ``dtype``. """
635
+ return None
636
+
637
+ def from_AlgebraicField(K1, a, K0):
638
+ """Convert an algebraic number to ``dtype``. """
639
+ return None
640
+
641
+ def from_PolynomialRing(K1, a, K0):
642
+ """Convert a polynomial to ``dtype``. """
643
+ if a.is_ground:
644
+ return K1.convert(a.LC, K0.dom)
645
+
646
+ def from_FractionField(K1, a, K0):
647
+ """Convert a rational function to ``dtype``. """
648
+ return None
649
+
650
+ def from_MonogenicFiniteExtension(K1, a, K0):
651
+ """Convert an ``ExtensionElement`` to ``dtype``. """
652
+ return K1.convert_from(a.rep, K0.ring)
653
+
654
+ def from_ExpressionDomain(K1, a, K0):
655
+ """Convert a ``EX`` object to ``dtype``. """
656
+ return K1.from_sympy(a.ex)
657
+
658
+ def from_ExpressionRawDomain(K1, a, K0):
659
+ """Convert a ``EX`` object to ``dtype``. """
660
+ return K1.from_sympy(a)
661
+
662
+ def from_GlobalPolynomialRing(K1, a, K0):
663
+ """Convert a polynomial to ``dtype``. """
664
+ if a.degree() <= 0:
665
+ return K1.convert(a.LC(), K0.dom)
666
+
667
+ def from_GeneralizedPolynomialRing(K1, a, K0):
668
+ return K1.from_FractionField(a, K0)
669
+
670
+ def unify_with_symbols(K0, K1, symbols):
671
+ if (K0.is_Composite and (set(K0.symbols) & set(symbols))) or (K1.is_Composite and (set(K1.symbols) & set(symbols))):
672
+ raise UnificationFailed("Cannot unify %s with %s, given %s generators" % (K0, K1, tuple(symbols)))
673
+
674
+ return K0.unify(K1)
675
+
676
+ def unify_composite(K0, K1):
677
+ """Unify two domains where at least one is composite."""
678
+ K0_ground = K0.dom if K0.is_Composite else K0
679
+ K1_ground = K1.dom if K1.is_Composite else K1
680
+
681
+ K0_symbols = K0.symbols if K0.is_Composite else ()
682
+ K1_symbols = K1.symbols if K1.is_Composite else ()
683
+
684
+ domain = K0_ground.unify(K1_ground)
685
+ symbols = _unify_gens(K0_symbols, K1_symbols)
686
+ order = K0.order if K0.is_Composite else K1.order
687
+
688
+ # E.g. ZZ[x].unify(QQ.frac_field(x)) -> ZZ.frac_field(x)
689
+ if ((K0.is_FractionField and K1.is_PolynomialRing or
690
+ K1.is_FractionField and K0.is_PolynomialRing) and
691
+ (not K0_ground.is_Field or not K1_ground.is_Field) and domain.is_Field
692
+ and domain.has_assoc_Ring):
693
+ domain = domain.get_ring()
694
+
695
+ if K0.is_Composite and (not K1.is_Composite or K0.is_FractionField or K1.is_PolynomialRing):
696
+ cls = K0.__class__
697
+ else:
698
+ cls = K1.__class__
699
+
700
+ # Here cls might be PolynomialRing, FractionField, GlobalPolynomialRing
701
+ # (dense/old Polynomialring) or dense/old FractionField.
702
+
703
+ from sympy.polys.domains.old_polynomialring import GlobalPolynomialRing
704
+ if cls == GlobalPolynomialRing:
705
+ return cls(domain, symbols)
706
+
707
+ return cls(domain, symbols, order)
708
+
709
+ def unify(K0, K1, symbols=None):
710
+ """
711
+ Construct a minimal domain that contains elements of ``K0`` and ``K1``.
712
+
713
+ Known domains (from smallest to largest):
714
+
715
+ - ``GF(p)``
716
+ - ``ZZ``
717
+ - ``QQ``
718
+ - ``RR(prec, tol)``
719
+ - ``CC(prec, tol)``
720
+ - ``ALG(a, b, c)``
721
+ - ``K[x, y, z]``
722
+ - ``K(x, y, z)``
723
+ - ``EX``
724
+
725
+ """
726
+ if symbols is not None:
727
+ return K0.unify_with_symbols(K1, symbols)
728
+
729
+ if K0 == K1:
730
+ return K0
731
+
732
+ if not (K0.has_CharacteristicZero and K1.has_CharacteristicZero):
733
+ # Reject unification of domains with different characteristics.
734
+ if K0.characteristic() != K1.characteristic():
735
+ raise UnificationFailed("Cannot unify %s with %s" % (K0, K1))
736
+
737
+ # We do not get here if K0 == K1. The two domains have the same
738
+ # characteristic but are unequal so at least one is composite and
739
+ # we are unifying something like GF(3).unify(GF(3)[x]).
740
+ return K0.unify_composite(K1)
741
+
742
+ # From here we know both domains have characteristic zero and it can be
743
+ # acceptable to fall back on EX.
744
+
745
+ if K0.is_EXRAW:
746
+ return K0
747
+ if K1.is_EXRAW:
748
+ return K1
749
+
750
+ if K0.is_EX:
751
+ return K0
752
+ if K1.is_EX:
753
+ return K1
754
+
755
+ if K0.is_FiniteExtension or K1.is_FiniteExtension:
756
+ if K1.is_FiniteExtension:
757
+ K0, K1 = K1, K0
758
+ if K1.is_FiniteExtension:
759
+ # Unifying two extensions.
760
+ # Try to ensure that K0.unify(K1) == K1.unify(K0)
761
+ if list(ordered([K0.modulus, K1.modulus]))[1] == K0.modulus:
762
+ K0, K1 = K1, K0
763
+ return K1.set_domain(K0)
764
+ else:
765
+ # Drop the generator from other and unify with the base domain
766
+ K1 = K1.drop(K0.symbol)
767
+ K1 = K0.domain.unify(K1)
768
+ return K0.set_domain(K1)
769
+
770
+ if K0.is_Composite or K1.is_Composite:
771
+ return K0.unify_composite(K1)
772
+
773
+ def mkinexact(cls, K0, K1):
774
+ prec = max(K0.precision, K1.precision)
775
+ tol = max(K0.tolerance, K1.tolerance)
776
+ return cls(prec=prec, tol=tol)
777
+
778
+ if K1.is_ComplexField:
779
+ K0, K1 = K1, K0
780
+ if K0.is_ComplexField:
781
+ if K1.is_ComplexField or K1.is_RealField:
782
+ return mkinexact(K0.__class__, K0, K1)
783
+ else:
784
+ return K0
785
+
786
+ if K1.is_RealField:
787
+ K0, K1 = K1, K0
788
+ if K0.is_RealField:
789
+ if K1.is_RealField:
790
+ return mkinexact(K0.__class__, K0, K1)
791
+ elif K1.is_GaussianRing or K1.is_GaussianField:
792
+ from sympy.polys.domains.complexfield import ComplexField
793
+ return ComplexField(prec=K0.precision, tol=K0.tolerance)
794
+ else:
795
+ return K0
796
+
797
+ if K1.is_AlgebraicField:
798
+ K0, K1 = K1, K0
799
+ if K0.is_AlgebraicField:
800
+ if K1.is_GaussianRing:
801
+ K1 = K1.get_field()
802
+ if K1.is_GaussianField:
803
+ K1 = K1.as_AlgebraicField()
804
+ if K1.is_AlgebraicField:
805
+ return K0.__class__(K0.dom.unify(K1.dom), *_unify_gens(K0.orig_ext, K1.orig_ext))
806
+ else:
807
+ return K0
808
+
809
+ if K0.is_GaussianField:
810
+ return K0
811
+ if K1.is_GaussianField:
812
+ return K1
813
+
814
+ if K0.is_GaussianRing:
815
+ if K1.is_RationalField:
816
+ K0 = K0.get_field()
817
+ return K0
818
+ if K1.is_GaussianRing:
819
+ if K0.is_RationalField:
820
+ K1 = K1.get_field()
821
+ return K1
822
+
823
+ if K0.is_RationalField:
824
+ return K0
825
+ if K1.is_RationalField:
826
+ return K1
827
+
828
+ if K0.is_IntegerRing:
829
+ return K0
830
+ if K1.is_IntegerRing:
831
+ return K1
832
+
833
+ from sympy.polys.domains import EX
834
+ return EX
835
+
836
+ def __eq__(self, other):
837
+ """Returns ``True`` if two domains are equivalent. """
838
+ # XXX: Remove this.
839
+ return isinstance(other, Domain) and self.dtype == other.dtype
840
+
841
+ def __ne__(self, other):
842
+ """Returns ``False`` if two domains are equivalent. """
843
+ return not self == other
844
+
845
+ def map(self, seq):
846
+ """Rersively apply ``self`` to all elements of ``seq``. """
847
+ result = []
848
+
849
+ for elt in seq:
850
+ if isinstance(elt, list):
851
+ result.append(self.map(elt))
852
+ else:
853
+ result.append(self(elt))
854
+
855
+ return result
856
+
857
+ def get_ring(self):
858
+ """Returns a ring associated with ``self``. """
859
+ raise DomainError('there is no ring associated with %s' % self)
860
+
861
+ def get_field(self):
862
+ """Returns a field associated with ``self``. """
863
+ raise DomainError('there is no field associated with %s' % self)
864
+
865
+ def get_exact(self):
866
+ """Returns an exact domain associated with ``self``. """
867
+ return self
868
+
869
+ def __getitem__(self, symbols):
870
+ """The mathematical way to make a polynomial ring. """
871
+ if hasattr(symbols, '__iter__'):
872
+ return self.poly_ring(*symbols)
873
+ else:
874
+ return self.poly_ring(symbols)
875
+
876
+ def poly_ring(self, *symbols, order=lex):
877
+ """Returns a polynomial ring, i.e. `K[X]`. """
878
+ from sympy.polys.domains.polynomialring import PolynomialRing
879
+ return PolynomialRing(self, symbols, order)
880
+
881
+ def frac_field(self, *symbols, order=lex):
882
+ """Returns a fraction field, i.e. `K(X)`. """
883
+ from sympy.polys.domains.fractionfield import FractionField
884
+ return FractionField(self, symbols, order)
885
+
886
+ def old_poly_ring(self, *symbols, **kwargs):
887
+ """Returns a polynomial ring, i.e. `K[X]`. """
888
+ from sympy.polys.domains.old_polynomialring import PolynomialRing
889
+ return PolynomialRing(self, *symbols, **kwargs)
890
+
891
+ def old_frac_field(self, *symbols, **kwargs):
892
+ """Returns a fraction field, i.e. `K(X)`. """
893
+ from sympy.polys.domains.old_fractionfield import FractionField
894
+ return FractionField(self, *symbols, **kwargs)
895
+
896
+ def algebraic_field(self, *extension, alias=None):
897
+ r"""Returns an algebraic field, i.e. `K(\alpha, \ldots)`. """
898
+ raise DomainError("Cannot create algebraic field over %s" % self)
899
+
900
+ def alg_field_from_poly(self, poly, alias=None, root_index=-1):
901
+ r"""
902
+ Convenience method to construct an algebraic extension on a root of a
903
+ polynomial, chosen by root index.
904
+
905
+ Parameters
906
+ ==========
907
+
908
+ poly : :py:class:`~.Poly`
909
+ The polynomial whose root generates the extension.
910
+ alias : str, optional (default=None)
911
+ Symbol name for the generator of the extension.
912
+ E.g. "alpha" or "theta".
913
+ root_index : int, optional (default=-1)
914
+ Specifies which root of the polynomial is desired. The ordering is
915
+ as defined by the :py:class:`~.ComplexRootOf` class. The default of
916
+ ``-1`` selects the most natural choice in the common cases of
917
+ quadratic and cyclotomic fields (the square root on the positive
918
+ real or imaginary axis, resp. $\mathrm{e}^{2\pi i/n}$).
919
+
920
+ Examples
921
+ ========
922
+
923
+ >>> from sympy import QQ, Poly
924
+ >>> from sympy.abc import x
925
+ >>> f = Poly(x**2 - 2)
926
+ >>> K = QQ.alg_field_from_poly(f)
927
+ >>> K.ext.minpoly == f
928
+ True
929
+ >>> g = Poly(8*x**3 - 6*x - 1)
930
+ >>> L = QQ.alg_field_from_poly(g, "alpha")
931
+ >>> L.ext.minpoly == g
932
+ True
933
+ >>> L.to_sympy(L([1, 1, 1]))
934
+ alpha**2 + alpha + 1
935
+
936
+ """
937
+ from sympy.polys.rootoftools import CRootOf
938
+ root = CRootOf(poly, root_index)
939
+ alpha = AlgebraicNumber(root, alias=alias)
940
+ return self.algebraic_field(alpha, alias=alias)
941
+
942
+ def cyclotomic_field(self, n, ss=False, alias="zeta", gen=None, root_index=-1):
943
+ r"""
944
+ Convenience method to construct a cyclotomic field.
945
+
946
+ Parameters
947
+ ==========
948
+
949
+ n : int
950
+ Construct the nth cyclotomic field.
951
+ ss : boolean, optional (default=False)
952
+ If True, append *n* as a subscript on the alias string.
953
+ alias : str, optional (default="zeta")
954
+ Symbol name for the generator.
955
+ gen : :py:class:`~.Symbol`, optional (default=None)
956
+ Desired variable for the cyclotomic polynomial that defines the
957
+ field. If ``None``, a dummy variable will be used.
958
+ root_index : int, optional (default=-1)
959
+ Specifies which root of the polynomial is desired. The ordering is
960
+ as defined by the :py:class:`~.ComplexRootOf` class. The default of
961
+ ``-1`` selects the root $\mathrm{e}^{2\pi i/n}$.
962
+
963
+ Examples
964
+ ========
965
+
966
+ >>> from sympy import QQ, latex
967
+ >>> K = QQ.cyclotomic_field(5)
968
+ >>> K.to_sympy(K([-1, 1]))
969
+ 1 - zeta
970
+ >>> L = QQ.cyclotomic_field(7, True)
971
+ >>> a = L.to_sympy(L([-1, 1]))
972
+ >>> print(a)
973
+ 1 - zeta7
974
+ >>> print(latex(a))
975
+ 1 - \zeta_{7}
976
+
977
+ """
978
+ from sympy.polys.specialpolys import cyclotomic_poly
979
+ if ss:
980
+ alias += str(n)
981
+ return self.alg_field_from_poly(cyclotomic_poly(n, gen), alias=alias,
982
+ root_index=root_index)
983
+
984
+ def inject(self, *symbols):
985
+ """Inject generators into this domain. """
986
+ raise NotImplementedError
987
+
988
+ def drop(self, *symbols):
989
+ """Drop generators from this domain. """
990
+ if self.is_Simple:
991
+ return self
992
+ raise NotImplementedError # pragma: no cover
993
+
994
+ def is_zero(self, a):
995
+ """Returns True if ``a`` is zero. """
996
+ return not a
997
+
998
+ def is_one(self, a):
999
+ """Returns True if ``a`` is one. """
1000
+ return a == self.one
1001
+
1002
+ def is_positive(self, a):
1003
+ """Returns True if ``a`` is positive. """
1004
+ return a > 0
1005
+
1006
+ def is_negative(self, a):
1007
+ """Returns True if ``a`` is negative. """
1008
+ return a < 0
1009
+
1010
+ def is_nonpositive(self, a):
1011
+ """Returns True if ``a`` is non-positive. """
1012
+ return a <= 0
1013
+
1014
+ def is_nonnegative(self, a):
1015
+ """Returns True if ``a`` is non-negative. """
1016
+ return a >= 0
1017
+
1018
+ def canonical_unit(self, a):
1019
+ if self.is_negative(a):
1020
+ return -self.one
1021
+ else:
1022
+ return self.one
1023
+
1024
+ def abs(self, a):
1025
+ """Absolute value of ``a``, implies ``__abs__``. """
1026
+ return abs(a)
1027
+
1028
+ def neg(self, a):
1029
+ """Returns ``a`` negated, implies ``__neg__``. """
1030
+ return -a
1031
+
1032
+ def pos(self, a):
1033
+ """Returns ``a`` positive, implies ``__pos__``. """
1034
+ return +a
1035
+
1036
+ def add(self, a, b):
1037
+ """Sum of ``a`` and ``b``, implies ``__add__``. """
1038
+ return a + b
1039
+
1040
+ def sub(self, a, b):
1041
+ """Difference of ``a`` and ``b``, implies ``__sub__``. """
1042
+ return a - b
1043
+
1044
+ def mul(self, a, b):
1045
+ """Product of ``a`` and ``b``, implies ``__mul__``. """
1046
+ return a * b
1047
+
1048
+ def pow(self, a, b):
1049
+ """Raise ``a`` to power ``b``, implies ``__pow__``. """
1050
+ return a ** b
1051
+
1052
+ def exquo(self, a, b):
1053
+ """Exact quotient of *a* and *b*. Analogue of ``a / b``.
1054
+
1055
+ Explanation
1056
+ ===========
1057
+
1058
+ This is essentially the same as ``a / b`` except that an error will be
1059
+ raised if the division is inexact (if there is any remainder) and the
1060
+ result will always be a domain element. When working in a
1061
+ :py:class:`~.Domain` that is not a :py:class:`~.Field` (e.g. :ref:`ZZ`
1062
+ or :ref:`K[x]`) ``exquo`` should be used instead of ``/``.
1063
+
1064
+ The key invariant is that if ``q = K.exquo(a, b)`` (and ``exquo`` does
1065
+ not raise an exception) then ``a == b*q``.
1066
+
1067
+ Examples
1068
+ ========
1069
+
1070
+ We can use ``K.exquo`` instead of ``/`` for exact division.
1071
+
1072
+ >>> from sympy import ZZ
1073
+ >>> ZZ.exquo(ZZ(4), ZZ(2))
1074
+ 2
1075
+ >>> ZZ.exquo(ZZ(5), ZZ(2))
1076
+ Traceback (most recent call last):
1077
+ ...
1078
+ ExactQuotientFailed: 2 does not divide 5 in ZZ
1079
+
1080
+ Over a :py:class:`~.Field` such as :ref:`QQ`, division (with nonzero
1081
+ divisor) is always exact so in that case ``/`` can be used instead of
1082
+ :py:meth:`~.Domain.exquo`.
1083
+
1084
+ >>> from sympy import QQ
1085
+ >>> QQ.exquo(QQ(5), QQ(2))
1086
+ 5/2
1087
+ >>> QQ(5) / QQ(2)
1088
+ 5/2
1089
+
1090
+ Parameters
1091
+ ==========
1092
+
1093
+ a: domain element
1094
+ The dividend
1095
+ b: domain element
1096
+ The divisor
1097
+
1098
+ Returns
1099
+ =======
1100
+
1101
+ q: domain element
1102
+ The exact quotient
1103
+
1104
+ Raises
1105
+ ======
1106
+
1107
+ ExactQuotientFailed: if exact division is not possible.
1108
+ ZeroDivisionError: when the divisor is zero.
1109
+
1110
+ See also
1111
+ ========
1112
+
1113
+ quo: Analogue of ``a // b``
1114
+ rem: Analogue of ``a % b``
1115
+ div: Analogue of ``divmod(a, b)``
1116
+
1117
+ Notes
1118
+ =====
1119
+
1120
+ Since the default :py:attr:`~.Domain.dtype` for :ref:`ZZ` is ``int``
1121
+ (or ``mpz``) division as ``a / b`` should not be used as it would give
1122
+ a ``float`` which is not a domain element.
1123
+
1124
+ >>> ZZ(4) / ZZ(2) # doctest: +SKIP
1125
+ 2.0
1126
+ >>> ZZ(5) / ZZ(2) # doctest: +SKIP
1127
+ 2.5
1128
+
1129
+ On the other hand with `SYMPY_GROUND_TYPES=flint` elements of :ref:`ZZ`
1130
+ are ``flint.fmpz`` and division would raise an exception:
1131
+
1132
+ >>> ZZ(4) / ZZ(2) # doctest: +SKIP
1133
+ Traceback (most recent call last):
1134
+ ...
1135
+ TypeError: unsupported operand type(s) for /: 'fmpz' and 'fmpz'
1136
+
1137
+ Using ``/`` with :ref:`ZZ` will lead to incorrect results so
1138
+ :py:meth:`~.Domain.exquo` should be used instead.
1139
+
1140
+ """
1141
+ raise NotImplementedError
1142
+
1143
+ def quo(self, a, b):
1144
+ """Quotient of *a* and *b*. Analogue of ``a // b``.
1145
+
1146
+ ``K.quo(a, b)`` is equivalent to ``K.div(a, b)[0]``. See
1147
+ :py:meth:`~.Domain.div` for more explanation.
1148
+
1149
+ See also
1150
+ ========
1151
+
1152
+ rem: Analogue of ``a % b``
1153
+ div: Analogue of ``divmod(a, b)``
1154
+ exquo: Analogue of ``a / b``
1155
+ """
1156
+ raise NotImplementedError
1157
+
1158
+ def rem(self, a, b):
1159
+ """Modulo division of *a* and *b*. Analogue of ``a % b``.
1160
+
1161
+ ``K.rem(a, b)`` is equivalent to ``K.div(a, b)[1]``. See
1162
+ :py:meth:`~.Domain.div` for more explanation.
1163
+
1164
+ See also
1165
+ ========
1166
+
1167
+ quo: Analogue of ``a // b``
1168
+ div: Analogue of ``divmod(a, b)``
1169
+ exquo: Analogue of ``a / b``
1170
+ """
1171
+ raise NotImplementedError
1172
+
1173
+ def div(self, a, b):
1174
+ """Quotient and remainder for *a* and *b*. Analogue of ``divmod(a, b)``
1175
+
1176
+ Explanation
1177
+ ===========
1178
+
1179
+ This is essentially the same as ``divmod(a, b)`` except that is more
1180
+ consistent when working over some :py:class:`~.Field` domains such as
1181
+ :ref:`QQ`. When working over an arbitrary :py:class:`~.Domain` the
1182
+ :py:meth:`~.Domain.div` method should be used instead of ``divmod``.
1183
+
1184
+ The key invariant is that if ``q, r = K.div(a, b)`` then
1185
+ ``a == b*q + r``.
1186
+
1187
+ The result of ``K.div(a, b)`` is the same as the tuple
1188
+ ``(K.quo(a, b), K.rem(a, b))`` except that if both quotient and
1189
+ remainder are needed then it is more efficient to use
1190
+ :py:meth:`~.Domain.div`.
1191
+
1192
+ Examples
1193
+ ========
1194
+
1195
+ We can use ``K.div`` instead of ``divmod`` for floor division and
1196
+ remainder.
1197
+
1198
+ >>> from sympy import ZZ, QQ
1199
+ >>> ZZ.div(ZZ(5), ZZ(2))
1200
+ (2, 1)
1201
+
1202
+ If ``K`` is a :py:class:`~.Field` then the division is always exact
1203
+ with a remainder of :py:attr:`~.Domain.zero`.
1204
+
1205
+ >>> QQ.div(QQ(5), QQ(2))
1206
+ (5/2, 0)
1207
+
1208
+ Parameters
1209
+ ==========
1210
+
1211
+ a: domain element
1212
+ The dividend
1213
+ b: domain element
1214
+ The divisor
1215
+
1216
+ Returns
1217
+ =======
1218
+
1219
+ (q, r): tuple of domain elements
1220
+ The quotient and remainder
1221
+
1222
+ Raises
1223
+ ======
1224
+
1225
+ ZeroDivisionError: when the divisor is zero.
1226
+
1227
+ See also
1228
+ ========
1229
+
1230
+ quo: Analogue of ``a // b``
1231
+ rem: Analogue of ``a % b``
1232
+ exquo: Analogue of ``a / b``
1233
+
1234
+ Notes
1235
+ =====
1236
+
1237
+ If ``gmpy`` is installed then the ``gmpy.mpq`` type will be used as
1238
+ the :py:attr:`~.Domain.dtype` for :ref:`QQ`. The ``gmpy.mpq`` type
1239
+ defines ``divmod`` in a way that is undesirable so
1240
+ :py:meth:`~.Domain.div` should be used instead of ``divmod``.
1241
+
1242
+ >>> a = QQ(1)
1243
+ >>> b = QQ(3, 2)
1244
+ >>> a # doctest: +SKIP
1245
+ mpq(1,1)
1246
+ >>> b # doctest: +SKIP
1247
+ mpq(3,2)
1248
+ >>> divmod(a, b) # doctest: +SKIP
1249
+ (mpz(0), mpq(1,1))
1250
+ >>> QQ.div(a, b) # doctest: +SKIP
1251
+ (mpq(2,3), mpq(0,1))
1252
+
1253
+ Using ``//`` or ``%`` with :ref:`QQ` will lead to incorrect results so
1254
+ :py:meth:`~.Domain.div` should be used instead.
1255
+
1256
+ """
1257
+ raise NotImplementedError
1258
+
1259
+ def invert(self, a, b):
1260
+ """Returns inversion of ``a mod b``, implies something. """
1261
+ raise NotImplementedError
1262
+
1263
+ def revert(self, a):
1264
+ """Returns ``a**(-1)`` if possible. """
1265
+ raise NotImplementedError
1266
+
1267
+ def numer(self, a):
1268
+ """Returns numerator of ``a``. """
1269
+ raise NotImplementedError
1270
+
1271
+ def denom(self, a):
1272
+ """Returns denominator of ``a``. """
1273
+ raise NotImplementedError
1274
+
1275
+ def half_gcdex(self, a, b):
1276
+ """Half extended GCD of ``a`` and ``b``. """
1277
+ s, t, h = self.gcdex(a, b)
1278
+ return s, h
1279
+
1280
+ def gcdex(self, a, b):
1281
+ """Extended GCD of ``a`` and ``b``. """
1282
+ raise NotImplementedError
1283
+
1284
+ def cofactors(self, a, b):
1285
+ """Returns GCD and cofactors of ``a`` and ``b``. """
1286
+ gcd = self.gcd(a, b)
1287
+ cfa = self.quo(a, gcd)
1288
+ cfb = self.quo(b, gcd)
1289
+ return gcd, cfa, cfb
1290
+
1291
+ def gcd(self, a, b):
1292
+ """Returns GCD of ``a`` and ``b``. """
1293
+ raise NotImplementedError
1294
+
1295
+ def lcm(self, a, b):
1296
+ """Returns LCM of ``a`` and ``b``. """
1297
+ raise NotImplementedError
1298
+
1299
+ def log(self, a, b):
1300
+ """Returns b-base logarithm of ``a``. """
1301
+ raise NotImplementedError
1302
+
1303
+ def sqrt(self, a):
1304
+ """Returns a (possibly inexact) square root of ``a``.
1305
+
1306
+ Explanation
1307
+ ===========
1308
+ There is no universal definition of "inexact square root" for all
1309
+ domains. It is not recommended to implement this method for domains
1310
+ other then :ref:`ZZ`.
1311
+
1312
+ See also
1313
+ ========
1314
+ exsqrt
1315
+ """
1316
+ raise NotImplementedError
1317
+
1318
+ def is_square(self, a):
1319
+ """Returns whether ``a`` is a square in the domain.
1320
+
1321
+ Explanation
1322
+ ===========
1323
+ Returns ``True`` if there is an element ``b`` in the domain such that
1324
+ ``b * b == a``, otherwise returns ``False``. For inexact domains like
1325
+ :ref:`RR` and :ref:`CC`, a tiny difference in this equality can be
1326
+ tolerated.
1327
+
1328
+ See also
1329
+ ========
1330
+ exsqrt
1331
+ """
1332
+ raise NotImplementedError
1333
+
1334
+ def exsqrt(self, a):
1335
+ """Principal square root of a within the domain if ``a`` is square.
1336
+
1337
+ Explanation
1338
+ ===========
1339
+ The implementation of this method should return an element ``b`` in the
1340
+ domain such that ``b * b == a``, or ``None`` if there is no such ``b``.
1341
+ For inexact domains like :ref:`RR` and :ref:`CC`, a tiny difference in
1342
+ this equality can be tolerated. The choice of a "principal" square root
1343
+ should follow a consistent rule whenever possible.
1344
+
1345
+ See also
1346
+ ========
1347
+ sqrt, is_square
1348
+ """
1349
+ raise NotImplementedError
1350
+
1351
+ def evalf(self, a, prec=None, **options):
1352
+ """Returns numerical approximation of ``a``. """
1353
+ return self.to_sympy(a).evalf(prec, **options)
1354
+
1355
+ n = evalf
1356
+
1357
+ def real(self, a):
1358
+ return a
1359
+
1360
+ def imag(self, a):
1361
+ return self.zero
1362
+
1363
+ def almosteq(self, a, b, tolerance=None):
1364
+ """Check if ``a`` and ``b`` are almost equal. """
1365
+ return a == b
1366
+
1367
+ def characteristic(self):
1368
+ """Return the characteristic of this domain. """
1369
+ raise NotImplementedError('characteristic()')
1370
+
1371
+
1372
+ __all__ = ['Domain']
lib/python3.12/site-packages/sympy/polys/domains/domainelement.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Trait for implementing domain elements. """
2
+
3
+
4
+ from sympy.utilities import public
5
+
6
+ @public
7
+ class DomainElement:
8
+ """
9
+ Represents an element of a domain.
10
+
11
+ Mix in this trait into a class whose instances should be recognized as
12
+ elements of a domain. Method ``parent()`` gives that domain.
13
+ """
14
+
15
+ __slots__ = ()
16
+
17
+ def parent(self):
18
+ """Get the domain associated with ``self``
19
+
20
+ Examples
21
+ ========
22
+
23
+ >>> from sympy import ZZ, symbols
24
+ >>> x, y = symbols('x, y')
25
+ >>> K = ZZ[x,y]
26
+ >>> p = K(x)**2 + K(y)**2
27
+ >>> p
28
+ x**2 + y**2
29
+ >>> p.parent()
30
+ ZZ[x,y]
31
+
32
+ Notes
33
+ =====
34
+
35
+ This is used by :py:meth:`~.Domain.convert` to identify the domain
36
+ associated with a domain element.
37
+ """
38
+ raise NotImplementedError("abstract method")
lib/python3.12/site-packages/sympy/polys/domains/expressiondomain.py ADDED
@@ -0,0 +1,278 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of :class:`ExpressionDomain` class. """
2
+
3
+
4
+ from sympy.core import sympify, SympifyError
5
+ from sympy.polys.domains.domainelement import DomainElement
6
+ from sympy.polys.domains.characteristiczero import CharacteristicZero
7
+ from sympy.polys.domains.field import Field
8
+ from sympy.polys.domains.simpledomain import SimpleDomain
9
+ from sympy.polys.polyutils import PicklableWithSlots
10
+ from sympy.utilities import public
11
+
12
+ eflags = {"deep": False, "mul": True, "power_exp": False, "power_base": False,
13
+ "basic": False, "multinomial": False, "log": False}
14
+
15
+ @public
16
+ class ExpressionDomain(Field, CharacteristicZero, SimpleDomain):
17
+ """A class for arbitrary expressions. """
18
+
19
+ is_SymbolicDomain = is_EX = True
20
+
21
+ class Expression(DomainElement, PicklableWithSlots):
22
+ """An arbitrary expression. """
23
+
24
+ __slots__ = ('ex',)
25
+
26
+ def __init__(self, ex):
27
+ if not isinstance(ex, self.__class__):
28
+ self.ex = sympify(ex)
29
+ else:
30
+ self.ex = ex.ex
31
+
32
+ def __repr__(f):
33
+ return 'EX(%s)' % repr(f.ex)
34
+
35
+ def __str__(f):
36
+ return 'EX(%s)' % str(f.ex)
37
+
38
+ def __hash__(self):
39
+ return hash((self.__class__.__name__, self.ex))
40
+
41
+ def parent(self):
42
+ return EX
43
+
44
+ def as_expr(f):
45
+ return f.ex
46
+
47
+ def numer(f):
48
+ return f.__class__(f.ex.as_numer_denom()[0])
49
+
50
+ def denom(f):
51
+ return f.__class__(f.ex.as_numer_denom()[1])
52
+
53
+ def simplify(f, ex):
54
+ return f.__class__(ex.cancel().expand(**eflags))
55
+
56
+ def __abs__(f):
57
+ return f.__class__(abs(f.ex))
58
+
59
+ def __neg__(f):
60
+ return f.__class__(-f.ex)
61
+
62
+ def _to_ex(f, g):
63
+ try:
64
+ return f.__class__(g)
65
+ except SympifyError:
66
+ return None
67
+
68
+ def __lt__(f, g):
69
+ return f.ex.sort_key() < g.ex.sort_key()
70
+
71
+ def __add__(f, g):
72
+ g = f._to_ex(g)
73
+
74
+ if g is None:
75
+ return NotImplemented
76
+ elif g == EX.zero:
77
+ return f
78
+ elif f == EX.zero:
79
+ return g
80
+ else:
81
+ return f.simplify(f.ex + g.ex)
82
+
83
+ def __radd__(f, g):
84
+ return f.simplify(f.__class__(g).ex + f.ex)
85
+
86
+ def __sub__(f, g):
87
+ g = f._to_ex(g)
88
+
89
+ if g is None:
90
+ return NotImplemented
91
+ elif g == EX.zero:
92
+ return f
93
+ elif f == EX.zero:
94
+ return -g
95
+ else:
96
+ return f.simplify(f.ex - g.ex)
97
+
98
+ def __rsub__(f, g):
99
+ return f.simplify(f.__class__(g).ex - f.ex)
100
+
101
+ def __mul__(f, g):
102
+ g = f._to_ex(g)
103
+
104
+ if g is None:
105
+ return NotImplemented
106
+
107
+ if EX.zero in (f, g):
108
+ return EX.zero
109
+ elif f.ex.is_Number and g.ex.is_Number:
110
+ return f.__class__(f.ex*g.ex)
111
+
112
+ return f.simplify(f.ex*g.ex)
113
+
114
+ def __rmul__(f, g):
115
+ return f.simplify(f.__class__(g).ex*f.ex)
116
+
117
+ def __pow__(f, n):
118
+ n = f._to_ex(n)
119
+
120
+ if n is not None:
121
+ return f.simplify(f.ex**n.ex)
122
+ else:
123
+ return NotImplemented
124
+
125
+ def __truediv__(f, g):
126
+ g = f._to_ex(g)
127
+
128
+ if g is not None:
129
+ return f.simplify(f.ex/g.ex)
130
+ else:
131
+ return NotImplemented
132
+
133
+ def __rtruediv__(f, g):
134
+ return f.simplify(f.__class__(g).ex/f.ex)
135
+
136
+ def __eq__(f, g):
137
+ return f.ex == f.__class__(g).ex
138
+
139
+ def __ne__(f, g):
140
+ return not f == g
141
+
142
+ def __bool__(f):
143
+ return not f.ex.is_zero
144
+
145
+ def gcd(f, g):
146
+ from sympy.polys import gcd
147
+ return f.__class__(gcd(f.ex, f.__class__(g).ex))
148
+
149
+ def lcm(f, g):
150
+ from sympy.polys import lcm
151
+ return f.__class__(lcm(f.ex, f.__class__(g).ex))
152
+
153
+ dtype = Expression
154
+
155
+ zero = Expression(0)
156
+ one = Expression(1)
157
+
158
+ rep = 'EX'
159
+
160
+ has_assoc_Ring = False
161
+ has_assoc_Field = True
162
+
163
+ def __init__(self):
164
+ pass
165
+
166
+ def __eq__(self, other):
167
+ if isinstance(other, ExpressionDomain):
168
+ return True
169
+ else:
170
+ return NotImplemented
171
+
172
+ def __hash__(self):
173
+ return hash("EX")
174
+
175
+ def to_sympy(self, a):
176
+ """Convert ``a`` to a SymPy object. """
177
+ return a.as_expr()
178
+
179
+ def from_sympy(self, a):
180
+ """Convert SymPy's expression to ``dtype``. """
181
+ return self.dtype(a)
182
+
183
+ def from_ZZ(K1, a, K0):
184
+ """Convert a Python ``int`` object to ``dtype``. """
185
+ return K1(K0.to_sympy(a))
186
+
187
+ def from_ZZ_python(K1, a, K0):
188
+ """Convert a Python ``int`` object to ``dtype``. """
189
+ return K1(K0.to_sympy(a))
190
+
191
+ def from_QQ(K1, a, K0):
192
+ """Convert a Python ``Fraction`` object to ``dtype``. """
193
+ return K1(K0.to_sympy(a))
194
+
195
+ def from_QQ_python(K1, a, K0):
196
+ """Convert a Python ``Fraction`` object to ``dtype``. """
197
+ return K1(K0.to_sympy(a))
198
+
199
+ def from_ZZ_gmpy(K1, a, K0):
200
+ """Convert a GMPY ``mpz`` object to ``dtype``. """
201
+ return K1(K0.to_sympy(a))
202
+
203
+ def from_QQ_gmpy(K1, a, K0):
204
+ """Convert a GMPY ``mpq`` object to ``dtype``. """
205
+ return K1(K0.to_sympy(a))
206
+
207
+ def from_GaussianIntegerRing(K1, a, K0):
208
+ """Convert a ``GaussianRational`` object to ``dtype``. """
209
+ return K1(K0.to_sympy(a))
210
+
211
+ def from_GaussianRationalField(K1, a, K0):
212
+ """Convert a ``GaussianRational`` object to ``dtype``. """
213
+ return K1(K0.to_sympy(a))
214
+
215
+ def from_AlgebraicField(K1, a, K0):
216
+ """Convert an ``ANP`` object to ``dtype``. """
217
+ return K1(K0.to_sympy(a))
218
+
219
+ def from_RealField(K1, a, K0):
220
+ """Convert a mpmath ``mpf`` object to ``dtype``. """
221
+ return K1(K0.to_sympy(a))
222
+
223
+ def from_ComplexField(K1, a, K0):
224
+ """Convert a mpmath ``mpc`` object to ``dtype``. """
225
+ return K1(K0.to_sympy(a))
226
+
227
+ def from_PolynomialRing(K1, a, K0):
228
+ """Convert a ``DMP`` object to ``dtype``. """
229
+ return K1(K0.to_sympy(a))
230
+
231
+ def from_FractionField(K1, a, K0):
232
+ """Convert a ``DMF`` object to ``dtype``. """
233
+ return K1(K0.to_sympy(a))
234
+
235
+ def from_ExpressionDomain(K1, a, K0):
236
+ """Convert a ``EX`` object to ``dtype``. """
237
+ return a
238
+
239
+ def get_ring(self):
240
+ """Returns a ring associated with ``self``. """
241
+ return self # XXX: EX is not a ring but we don't have much choice here.
242
+
243
+ def get_field(self):
244
+ """Returns a field associated with ``self``. """
245
+ return self
246
+
247
+ def is_positive(self, a):
248
+ """Returns True if ``a`` is positive. """
249
+ return a.ex.as_coeff_mul()[0].is_positive
250
+
251
+ def is_negative(self, a):
252
+ """Returns True if ``a`` is negative. """
253
+ return a.ex.could_extract_minus_sign()
254
+
255
+ def is_nonpositive(self, a):
256
+ """Returns True if ``a`` is non-positive. """
257
+ return a.ex.as_coeff_mul()[0].is_nonpositive
258
+
259
+ def is_nonnegative(self, a):
260
+ """Returns True if ``a`` is non-negative. """
261
+ return a.ex.as_coeff_mul()[0].is_nonnegative
262
+
263
+ def numer(self, a):
264
+ """Returns numerator of ``a``. """
265
+ return a.numer()
266
+
267
+ def denom(self, a):
268
+ """Returns denominator of ``a``. """
269
+ return a.denom()
270
+
271
+ def gcd(self, a, b):
272
+ return self(1)
273
+
274
+ def lcm(self, a, b):
275
+ return a.lcm(b)
276
+
277
+
278
+ EX = ExpressionDomain()
lib/python3.12/site-packages/sympy/polys/domains/expressionrawdomain.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of :class:`ExpressionRawDomain` class. """
2
+
3
+
4
+ from sympy.core import Expr, S, sympify, Add
5
+ from sympy.polys.domains.characteristiczero import CharacteristicZero
6
+ from sympy.polys.domains.field import Field
7
+ from sympy.polys.domains.simpledomain import SimpleDomain
8
+ from sympy.polys.polyerrors import CoercionFailed
9
+ from sympy.utilities import public
10
+
11
+
12
+ @public
13
+ class ExpressionRawDomain(Field, CharacteristicZero, SimpleDomain):
14
+ """A class for arbitrary expressions but without automatic simplification. """
15
+
16
+ is_SymbolicRawDomain = is_EXRAW = True
17
+
18
+ dtype = Expr
19
+
20
+ zero = S.Zero
21
+ one = S.One
22
+
23
+ rep = 'EXRAW'
24
+
25
+ has_assoc_Ring = False
26
+ has_assoc_Field = True
27
+
28
+ def __init__(self):
29
+ pass
30
+
31
+ @classmethod
32
+ def new(self, a):
33
+ return sympify(a)
34
+
35
+ def to_sympy(self, a):
36
+ """Convert ``a`` to a SymPy object. """
37
+ return a
38
+
39
+ def from_sympy(self, a):
40
+ """Convert SymPy's expression to ``dtype``. """
41
+ if not isinstance(a, Expr):
42
+ raise CoercionFailed(f"Expecting an Expr instance but found: {type(a).__name__}")
43
+ return a
44
+
45
+ def convert_from(self, a, K):
46
+ """Convert a domain element from another domain to EXRAW"""
47
+ return K.to_sympy(a)
48
+
49
+ def get_field(self):
50
+ """Returns a field associated with ``self``. """
51
+ return self
52
+
53
+ def sum(self, items):
54
+ return Add(*items)
55
+
56
+
57
+ EXRAW = ExpressionRawDomain()
lib/python3.12/site-packages/sympy/polys/domains/field.py ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of :class:`Field` class. """
2
+
3
+
4
+ from sympy.polys.domains.ring import Ring
5
+ from sympy.polys.polyerrors import NotReversible, DomainError
6
+ from sympy.utilities import public
7
+
8
+ @public
9
+ class Field(Ring):
10
+ """Represents a field domain. """
11
+
12
+ is_Field = True
13
+ is_PID = True
14
+
15
+ def get_ring(self):
16
+ """Returns a ring associated with ``self``. """
17
+ raise DomainError('there is no ring associated with %s' % self)
18
+
19
+ def get_field(self):
20
+ """Returns a field associated with ``self``. """
21
+ return self
22
+
23
+ def exquo(self, a, b):
24
+ """Exact quotient of ``a`` and ``b``, implies ``__truediv__``. """
25
+ return a / b
26
+
27
+ def quo(self, a, b):
28
+ """Quotient of ``a`` and ``b``, implies ``__truediv__``. """
29
+ return a / b
30
+
31
+ def rem(self, a, b):
32
+ """Remainder of ``a`` and ``b``, implies nothing. """
33
+ return self.zero
34
+
35
+ def div(self, a, b):
36
+ """Division of ``a`` and ``b``, implies ``__truediv__``. """
37
+ return a / b, self.zero
38
+
39
+ def gcd(self, a, b):
40
+ """
41
+ Returns GCD of ``a`` and ``b``.
42
+
43
+ This definition of GCD over fields allows to clear denominators
44
+ in `primitive()`.
45
+
46
+ Examples
47
+ ========
48
+
49
+ >>> from sympy.polys.domains import QQ
50
+ >>> from sympy import S, gcd, primitive
51
+ >>> from sympy.abc import x
52
+
53
+ >>> QQ.gcd(QQ(2, 3), QQ(4, 9))
54
+ 2/9
55
+ >>> gcd(S(2)/3, S(4)/9)
56
+ 2/9
57
+ >>> primitive(2*x/3 + S(4)/9)
58
+ (2/9, 3*x + 2)
59
+
60
+ """
61
+ try:
62
+ ring = self.get_ring()
63
+ except DomainError:
64
+ return self.one
65
+
66
+ p = ring.gcd(self.numer(a), self.numer(b))
67
+ q = ring.lcm(self.denom(a), self.denom(b))
68
+
69
+ return self.convert(p, ring)/q
70
+
71
+ def lcm(self, a, b):
72
+ """
73
+ Returns LCM of ``a`` and ``b``.
74
+
75
+ >>> from sympy.polys.domains import QQ
76
+ >>> from sympy import S, lcm
77
+
78
+ >>> QQ.lcm(QQ(2, 3), QQ(4, 9))
79
+ 4/3
80
+ >>> lcm(S(2)/3, S(4)/9)
81
+ 4/3
82
+
83
+ """
84
+
85
+ try:
86
+ ring = self.get_ring()
87
+ except DomainError:
88
+ return a*b
89
+
90
+ p = ring.lcm(self.numer(a), self.numer(b))
91
+ q = ring.gcd(self.denom(a), self.denom(b))
92
+
93
+ return self.convert(p, ring)/q
94
+
95
+ def revert(self, a):
96
+ """Returns ``a**(-1)`` if possible. """
97
+ if a:
98
+ return 1/a
99
+ else:
100
+ raise NotReversible('zero is not reversible')
101
+
102
+ def is_unit(self, a):
103
+ """Return true if ``a`` is a invertible"""
104
+ return bool(a)
lib/python3.12/site-packages/sympy/polys/domains/finitefield.py ADDED
@@ -0,0 +1,328 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of :class:`FiniteField` class. """
2
+
3
+ import operator
4
+
5
+ from sympy.external.gmpy import GROUND_TYPES
6
+ from sympy.utilities.decorator import doctest_depends_on
7
+
8
+ from sympy.core.numbers import int_valued
9
+ from sympy.polys.domains.field import Field
10
+
11
+ from sympy.polys.domains.modularinteger import ModularIntegerFactory
12
+ from sympy.polys.domains.simpledomain import SimpleDomain
13
+ from sympy.polys.galoistools import gf_zassenhaus, gf_irred_p_rabin
14
+ from sympy.polys.polyerrors import CoercionFailed
15
+ from sympy.utilities import public
16
+ from sympy.polys.domains.groundtypes import SymPyInteger
17
+
18
+
19
+ if GROUND_TYPES == 'flint':
20
+ __doctest_skip__ = ['FiniteField']
21
+
22
+
23
+ if GROUND_TYPES == 'flint':
24
+ import flint
25
+ # Don't use python-flint < 0.5.0 because nmod was missing some features in
26
+ # previous versions of python-flint and fmpz_mod was not yet added.
27
+ _major, _minor, *_ = flint.__version__.split('.')
28
+ if (int(_major), int(_minor)) < (0, 5):
29
+ flint = None
30
+ else:
31
+ flint = None
32
+
33
+
34
+ def _modular_int_factory(mod, dom, symmetric, self):
35
+
36
+ # Use flint if available
37
+ if flint is not None:
38
+
39
+ nmod = flint.nmod
40
+ fmpz_mod_ctx = flint.fmpz_mod_ctx
41
+ index = operator.index
42
+
43
+ try:
44
+ mod = dom.convert(mod)
45
+ except CoercionFailed:
46
+ raise ValueError('modulus must be an integer, got %s' % mod)
47
+
48
+ # mod might be e.g. Integer
49
+ try:
50
+ fmpz_mod_ctx(mod)
51
+ except TypeError:
52
+ mod = index(mod)
53
+
54
+ # flint's nmod is only for moduli up to 2^64-1 (on a 64-bit machine)
55
+ try:
56
+ nmod(0, mod)
57
+ except OverflowError:
58
+ # Use fmpz_mod
59
+ fctx = fmpz_mod_ctx(mod)
60
+
61
+ def ctx(x):
62
+ try:
63
+ return fctx(x)
64
+ except TypeError:
65
+ # x might be Integer
66
+ return fctx(index(x))
67
+ else:
68
+ # Use nmod
69
+ def ctx(x):
70
+ try:
71
+ return nmod(x, mod)
72
+ except TypeError:
73
+ return nmod(index(x), mod)
74
+
75
+ return ctx
76
+
77
+ # Use the Python implementation
78
+ return ModularIntegerFactory(mod, dom, symmetric, self)
79
+
80
+
81
+ @public
82
+ @doctest_depends_on(modules=['python', 'gmpy'])
83
+ class FiniteField(Field, SimpleDomain):
84
+ r"""Finite field of prime order :ref:`GF(p)`
85
+
86
+ A :ref:`GF(p)` domain represents a `finite field`_ `\mathbb{F}_p` of prime
87
+ order as :py:class:`~.Domain` in the domain system (see
88
+ :ref:`polys-domainsintro`).
89
+
90
+ A :py:class:`~.Poly` created from an expression with integer
91
+ coefficients will have the domain :ref:`ZZ`. However, if the ``modulus=p``
92
+ option is given then the domain will be a finite field instead.
93
+
94
+ >>> from sympy import Poly, Symbol
95
+ >>> x = Symbol('x')
96
+ >>> p = Poly(x**2 + 1)
97
+ >>> p
98
+ Poly(x**2 + 1, x, domain='ZZ')
99
+ >>> p.domain
100
+ ZZ
101
+ >>> p2 = Poly(x**2 + 1, modulus=2)
102
+ >>> p2
103
+ Poly(x**2 + 1, x, modulus=2)
104
+ >>> p2.domain
105
+ GF(2)
106
+
107
+ It is possible to factorise a polynomial over :ref:`GF(p)` using the
108
+ modulus argument to :py:func:`~.factor` or by specifying the domain
109
+ explicitly. The domain can also be given as a string.
110
+
111
+ >>> from sympy import factor, GF
112
+ >>> factor(x**2 + 1)
113
+ x**2 + 1
114
+ >>> factor(x**2 + 1, modulus=2)
115
+ (x + 1)**2
116
+ >>> factor(x**2 + 1, domain=GF(2))
117
+ (x + 1)**2
118
+ >>> factor(x**2 + 1, domain='GF(2)')
119
+ (x + 1)**2
120
+
121
+ It is also possible to use :ref:`GF(p)` with the :py:func:`~.cancel`
122
+ and :py:func:`~.gcd` functions.
123
+
124
+ >>> from sympy import cancel, gcd
125
+ >>> cancel((x**2 + 1)/(x + 1))
126
+ (x**2 + 1)/(x + 1)
127
+ >>> cancel((x**2 + 1)/(x + 1), domain=GF(2))
128
+ x + 1
129
+ >>> gcd(x**2 + 1, x + 1)
130
+ 1
131
+ >>> gcd(x**2 + 1, x + 1, domain=GF(2))
132
+ x + 1
133
+
134
+ When using the domain directly :ref:`GF(p)` can be used as a constructor
135
+ to create instances which then support the operations ``+,-,*,**,/``
136
+
137
+ >>> from sympy import GF
138
+ >>> K = GF(5)
139
+ >>> K
140
+ GF(5)
141
+ >>> x = K(3)
142
+ >>> y = K(2)
143
+ >>> x
144
+ 3 mod 5
145
+ >>> y
146
+ 2 mod 5
147
+ >>> x * y
148
+ 1 mod 5
149
+ >>> x / y
150
+ 4 mod 5
151
+
152
+ Notes
153
+ =====
154
+
155
+ It is also possible to create a :ref:`GF(p)` domain of **non-prime**
156
+ order but the resulting ring is **not** a field: it is just the ring of
157
+ the integers modulo ``n``.
158
+
159
+ >>> K = GF(9)
160
+ >>> z = K(3)
161
+ >>> z
162
+ 3 mod 9
163
+ >>> z**2
164
+ 0 mod 9
165
+
166
+ It would be good to have a proper implementation of prime power fields
167
+ (``GF(p**n)``) but these are not yet implemented in SymPY.
168
+
169
+ .. _finite field: https://en.wikipedia.org/wiki/Finite_field
170
+ """
171
+
172
+ rep = 'FF'
173
+ alias = 'FF'
174
+
175
+ is_FiniteField = is_FF = True
176
+ is_Numerical = True
177
+
178
+ has_assoc_Ring = False
179
+ has_assoc_Field = True
180
+
181
+ dom = None
182
+ mod = None
183
+
184
+ def __init__(self, mod, symmetric=True):
185
+ from sympy.polys.domains import ZZ
186
+ dom = ZZ
187
+
188
+ if mod <= 0:
189
+ raise ValueError('modulus must be a positive integer, got %s' % mod)
190
+
191
+ self.dtype = _modular_int_factory(mod, dom, symmetric, self)
192
+ self.zero = self.dtype(0)
193
+ self.one = self.dtype(1)
194
+ self.dom = dom
195
+ self.mod = mod
196
+ self.sym = symmetric
197
+ self._tp = type(self.zero)
198
+
199
+ @property
200
+ def tp(self):
201
+ return self._tp
202
+
203
+ def __str__(self):
204
+ return 'GF(%s)' % self.mod
205
+
206
+ def __hash__(self):
207
+ return hash((self.__class__.__name__, self.dtype, self.mod, self.dom))
208
+
209
+ def __eq__(self, other):
210
+ """Returns ``True`` if two domains are equivalent. """
211
+ return isinstance(other, FiniteField) and \
212
+ self.mod == other.mod and self.dom == other.dom
213
+
214
+ def characteristic(self):
215
+ """Return the characteristic of this domain. """
216
+ return self.mod
217
+
218
+ def get_field(self):
219
+ """Returns a field associated with ``self``. """
220
+ return self
221
+
222
+ def to_sympy(self, a):
223
+ """Convert ``a`` to a SymPy object. """
224
+ return SymPyInteger(self.to_int(a))
225
+
226
+ def from_sympy(self, a):
227
+ """Convert SymPy's Integer to SymPy's ``Integer``. """
228
+ if a.is_Integer:
229
+ return self.dtype(self.dom.dtype(int(a)))
230
+ elif int_valued(a):
231
+ return self.dtype(self.dom.dtype(int(a)))
232
+ else:
233
+ raise CoercionFailed("expected an integer, got %s" % a)
234
+
235
+ def to_int(self, a):
236
+ """Convert ``val`` to a Python ``int`` object. """
237
+ aval = int(a)
238
+ if self.sym and aval > self.mod // 2:
239
+ aval -= self.mod
240
+ return aval
241
+
242
+ def is_positive(self, a):
243
+ """Returns True if ``a`` is positive. """
244
+ return bool(a)
245
+
246
+ def is_nonnegative(self, a):
247
+ """Returns True if ``a`` is non-negative. """
248
+ return True
249
+
250
+ def is_negative(self, a):
251
+ """Returns True if ``a`` is negative. """
252
+ return False
253
+
254
+ def is_nonpositive(self, a):
255
+ """Returns True if ``a`` is non-positive. """
256
+ return not a
257
+
258
+ def from_FF(K1, a, K0=None):
259
+ """Convert ``ModularInteger(int)`` to ``dtype``. """
260
+ return K1.dtype(K1.dom.from_ZZ(int(a), K0.dom))
261
+
262
+ def from_FF_python(K1, a, K0=None):
263
+ """Convert ``ModularInteger(int)`` to ``dtype``. """
264
+ return K1.dtype(K1.dom.from_ZZ_python(int(a), K0.dom))
265
+
266
+ def from_ZZ(K1, a, K0=None):
267
+ """Convert Python's ``int`` to ``dtype``. """
268
+ return K1.dtype(K1.dom.from_ZZ_python(a, K0))
269
+
270
+ def from_ZZ_python(K1, a, K0=None):
271
+ """Convert Python's ``int`` to ``dtype``. """
272
+ return K1.dtype(K1.dom.from_ZZ_python(a, K0))
273
+
274
+ def from_QQ(K1, a, K0=None):
275
+ """Convert Python's ``Fraction`` to ``dtype``. """
276
+ if a.denominator == 1:
277
+ return K1.from_ZZ_python(a.numerator)
278
+
279
+ def from_QQ_python(K1, a, K0=None):
280
+ """Convert Python's ``Fraction`` to ``dtype``. """
281
+ if a.denominator == 1:
282
+ return K1.from_ZZ_python(a.numerator)
283
+
284
+ def from_FF_gmpy(K1, a, K0=None):
285
+ """Convert ``ModularInteger(mpz)`` to ``dtype``. """
286
+ return K1.dtype(K1.dom.from_ZZ_gmpy(a.val, K0.dom))
287
+
288
+ def from_ZZ_gmpy(K1, a, K0=None):
289
+ """Convert GMPY's ``mpz`` to ``dtype``. """
290
+ return K1.dtype(K1.dom.from_ZZ_gmpy(a, K0))
291
+
292
+ def from_QQ_gmpy(K1, a, K0=None):
293
+ """Convert GMPY's ``mpq`` to ``dtype``. """
294
+ if a.denominator == 1:
295
+ return K1.from_ZZ_gmpy(a.numerator)
296
+
297
+ def from_RealField(K1, a, K0):
298
+ """Convert mpmath's ``mpf`` to ``dtype``. """
299
+ p, q = K0.to_rational(a)
300
+
301
+ if q == 1:
302
+ return K1.dtype(K1.dom.dtype(p))
303
+
304
+ def is_square(self, a):
305
+ """Returns True if ``a`` is a quadratic residue modulo p. """
306
+ # a is not a square <=> x**2-a is irreducible
307
+ poly = [int(x) for x in [self.one, self.zero, -a]]
308
+ return not gf_irred_p_rabin(poly, self.mod, self.dom)
309
+
310
+ def exsqrt(self, a):
311
+ """Square root modulo p of ``a`` if it is a quadratic residue.
312
+
313
+ Explanation
314
+ ===========
315
+ Always returns the square root that is no larger than ``p // 2``.
316
+ """
317
+ # x**2-a is not square-free if a=0 or the field is characteristic 2
318
+ if self.mod == 2 or a == 0:
319
+ return a
320
+ # Otherwise, use square-free factorization routine to factorize x**2-a
321
+ poly = [int(x) for x in [self.one, self.zero, -a]]
322
+ for factor in gf_zassenhaus(poly, self.mod, self.dom):
323
+ if len(factor) == 2 and factor[1] <= self.mod // 2:
324
+ return self.dtype(factor[1])
325
+ return None
326
+
327
+
328
+ FF = GF = FiniteField
lib/python3.12/site-packages/sympy/polys/domains/fractionfield.py ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of :class:`FractionField` class. """
2
+
3
+
4
+ from sympy.polys.domains.compositedomain import CompositeDomain
5
+ from sympy.polys.domains.field import Field
6
+ from sympy.polys.polyerrors import CoercionFailed, GeneratorsError
7
+ from sympy.utilities import public
8
+
9
+ @public
10
+ class FractionField(Field, CompositeDomain):
11
+ """A class for representing multivariate rational function fields. """
12
+
13
+ is_FractionField = is_Frac = True
14
+
15
+ has_assoc_Ring = True
16
+ has_assoc_Field = True
17
+
18
+ def __init__(self, domain_or_field, symbols=None, order=None):
19
+ from sympy.polys.fields import FracField
20
+
21
+ if isinstance(domain_or_field, FracField) and symbols is None and order is None:
22
+ field = domain_or_field
23
+ else:
24
+ field = FracField(symbols, domain_or_field, order)
25
+
26
+ self.field = field
27
+ self.dtype = field.dtype
28
+
29
+ self.gens = field.gens
30
+ self.ngens = field.ngens
31
+ self.symbols = field.symbols
32
+ self.domain = field.domain
33
+
34
+ # TODO: remove this
35
+ self.dom = self.domain
36
+
37
+ def new(self, element):
38
+ return self.field.field_new(element)
39
+
40
+ @property
41
+ def zero(self):
42
+ return self.field.zero
43
+
44
+ @property
45
+ def one(self):
46
+ return self.field.one
47
+
48
+ @property
49
+ def order(self):
50
+ return self.field.order
51
+
52
+ def __str__(self):
53
+ return str(self.domain) + '(' + ','.join(map(str, self.symbols)) + ')'
54
+
55
+ def __hash__(self):
56
+ return hash((self.__class__.__name__, self.dtype.field, self.domain, self.symbols))
57
+
58
+ def __eq__(self, other):
59
+ """Returns ``True`` if two domains are equivalent. """
60
+ return isinstance(other, FractionField) and \
61
+ (self.dtype.field, self.domain, self.symbols) ==\
62
+ (other.dtype.field, other.domain, other.symbols)
63
+
64
+ def to_sympy(self, a):
65
+ """Convert ``a`` to a SymPy object. """
66
+ return a.as_expr()
67
+
68
+ def from_sympy(self, a):
69
+ """Convert SymPy's expression to ``dtype``. """
70
+ return self.field.from_expr(a)
71
+
72
+ def from_ZZ(K1, a, K0):
73
+ """Convert a Python ``int`` object to ``dtype``. """
74
+ return K1(K1.domain.convert(a, K0))
75
+
76
+ def from_ZZ_python(K1, a, K0):
77
+ """Convert a Python ``int`` object to ``dtype``. """
78
+ return K1(K1.domain.convert(a, K0))
79
+
80
+ def from_QQ(K1, a, K0):
81
+ """Convert a Python ``Fraction`` object to ``dtype``. """
82
+ dom = K1.domain
83
+ conv = dom.convert_from
84
+ if dom.is_ZZ:
85
+ return K1(conv(K0.numer(a), K0)) / K1(conv(K0.denom(a), K0))
86
+ else:
87
+ return K1(conv(a, K0))
88
+
89
+ def from_QQ_python(K1, a, K0):
90
+ """Convert a Python ``Fraction`` object to ``dtype``. """
91
+ return K1(K1.domain.convert(a, K0))
92
+
93
+ def from_ZZ_gmpy(K1, a, K0):
94
+ """Convert a GMPY ``mpz`` object to ``dtype``. """
95
+ return K1(K1.domain.convert(a, K0))
96
+
97
+ def from_QQ_gmpy(K1, a, K0):
98
+ """Convert a GMPY ``mpq`` object to ``dtype``. """
99
+ return K1(K1.domain.convert(a, K0))
100
+
101
+ def from_GaussianRationalField(K1, a, K0):
102
+ """Convert a ``GaussianRational`` object to ``dtype``. """
103
+ return K1(K1.domain.convert(a, K0))
104
+
105
+ def from_GaussianIntegerRing(K1, a, K0):
106
+ """Convert a ``GaussianInteger`` object to ``dtype``. """
107
+ return K1(K1.domain.convert(a, K0))
108
+
109
+ def from_RealField(K1, a, K0):
110
+ """Convert a mpmath ``mpf`` object to ``dtype``. """
111
+ return K1(K1.domain.convert(a, K0))
112
+
113
+ def from_ComplexField(K1, a, K0):
114
+ """Convert a mpmath ``mpf`` object to ``dtype``. """
115
+ return K1(K1.domain.convert(a, K0))
116
+
117
+ def from_AlgebraicField(K1, a, K0):
118
+ """Convert an algebraic number to ``dtype``. """
119
+ if K1.domain != K0:
120
+ a = K1.domain.convert_from(a, K0)
121
+ if a is not None:
122
+ return K1.new(a)
123
+
124
+ def from_PolynomialRing(K1, a, K0):
125
+ """Convert a polynomial to ``dtype``. """
126
+ if a.is_ground:
127
+ return K1.convert_from(a.coeff(1), K0.domain)
128
+ try:
129
+ return K1.new(a.set_ring(K1.field.ring))
130
+ except (CoercionFailed, GeneratorsError):
131
+ # XXX: We get here if K1=ZZ(x,y) and K0=QQ[x,y]
132
+ # and the poly a in K0 has non-integer coefficients.
133
+ # It seems that K1.new can handle this but K1.new doesn't work
134
+ # when K0.domain is an algebraic field...
135
+ try:
136
+ return K1.new(a)
137
+ except (CoercionFailed, GeneratorsError):
138
+ return None
139
+
140
+ def from_FractionField(K1, a, K0):
141
+ """Convert a rational function to ``dtype``. """
142
+ try:
143
+ return a.set_field(K1.field)
144
+ except (CoercionFailed, GeneratorsError):
145
+ return None
146
+
147
+ def get_ring(self):
148
+ """Returns a field associated with ``self``. """
149
+ return self.field.to_ring().to_domain()
150
+
151
+ def is_positive(self, a):
152
+ """Returns True if ``LC(a)`` is positive. """
153
+ return self.domain.is_positive(a.numer.LC)
154
+
155
+ def is_negative(self, a):
156
+ """Returns True if ``LC(a)`` is negative. """
157
+ return self.domain.is_negative(a.numer.LC)
158
+
159
+ def is_nonpositive(self, a):
160
+ """Returns True if ``LC(a)`` is non-positive. """
161
+ return self.domain.is_nonpositive(a.numer.LC)
162
+
163
+ def is_nonnegative(self, a):
164
+ """Returns True if ``LC(a)`` is non-negative. """
165
+ return self.domain.is_nonnegative(a.numer.LC)
166
+
167
+ def numer(self, a):
168
+ """Returns numerator of ``a``. """
169
+ return a.numer
170
+
171
+ def denom(self, a):
172
+ """Returns denominator of ``a``. """
173
+ return a.denom
174
+
175
+ def factorial(self, a):
176
+ """Returns factorial of ``a``. """
177
+ return self.dtype(self.domain.factorial(a))
lib/python3.12/site-packages/sympy/polys/domains/gaussiandomains.py ADDED
@@ -0,0 +1,686 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Domains of Gaussian type."""
2
+
3
+ from sympy.core.numbers import I
4
+ from sympy.polys.polyerrors import CoercionFailed
5
+ from sympy.polys.domains.integerring import ZZ
6
+ from sympy.polys.domains.rationalfield import QQ
7
+ from sympy.polys.domains.algebraicfield import AlgebraicField
8
+ from sympy.polys.domains.domain import Domain
9
+ from sympy.polys.domains.domainelement import DomainElement
10
+ from sympy.polys.domains.field import Field
11
+ from sympy.polys.domains.ring import Ring
12
+
13
+
14
+ class GaussianElement(DomainElement):
15
+ """Base class for elements of Gaussian type domains."""
16
+ base: Domain
17
+ _parent: Domain
18
+
19
+ __slots__ = ('x', 'y')
20
+
21
+ def __new__(cls, x, y=0):
22
+ conv = cls.base.convert
23
+ return cls.new(conv(x), conv(y))
24
+
25
+ @classmethod
26
+ def new(cls, x, y):
27
+ """Create a new GaussianElement of the same domain."""
28
+ obj = super().__new__(cls)
29
+ obj.x = x
30
+ obj.y = y
31
+ return obj
32
+
33
+ def parent(self):
34
+ """The domain that this is an element of (ZZ_I or QQ_I)"""
35
+ return self._parent
36
+
37
+ def __hash__(self):
38
+ return hash((self.x, self.y))
39
+
40
+ def __eq__(self, other):
41
+ if isinstance(other, self.__class__):
42
+ return self.x == other.x and self.y == other.y
43
+ else:
44
+ return NotImplemented
45
+
46
+ def __lt__(self, other):
47
+ if not isinstance(other, GaussianElement):
48
+ return NotImplemented
49
+ return [self.y, self.x] < [other.y, other.x]
50
+
51
+ def __pos__(self):
52
+ return self
53
+
54
+ def __neg__(self):
55
+ return self.new(-self.x, -self.y)
56
+
57
+ def __repr__(self):
58
+ return "%s(%s, %s)" % (self._parent.rep, self.x, self.y)
59
+
60
+ def __str__(self):
61
+ return str(self._parent.to_sympy(self))
62
+
63
+ @classmethod
64
+ def _get_xy(cls, other):
65
+ if not isinstance(other, cls):
66
+ try:
67
+ other = cls._parent.convert(other)
68
+ except CoercionFailed:
69
+ return None, None
70
+ return other.x, other.y
71
+
72
+ def __add__(self, other):
73
+ x, y = self._get_xy(other)
74
+ if x is not None:
75
+ return self.new(self.x + x, self.y + y)
76
+ else:
77
+ return NotImplemented
78
+
79
+ __radd__ = __add__
80
+
81
+ def __sub__(self, other):
82
+ x, y = self._get_xy(other)
83
+ if x is not None:
84
+ return self.new(self.x - x, self.y - y)
85
+ else:
86
+ return NotImplemented
87
+
88
+ def __rsub__(self, other):
89
+ x, y = self._get_xy(other)
90
+ if x is not None:
91
+ return self.new(x - self.x, y - self.y)
92
+ else:
93
+ return NotImplemented
94
+
95
+ def __mul__(self, other):
96
+ x, y = self._get_xy(other)
97
+ if x is not None:
98
+ return self.new(self.x*x - self.y*y, self.x*y + self.y*x)
99
+ else:
100
+ return NotImplemented
101
+
102
+ __rmul__ = __mul__
103
+
104
+ def __pow__(self, exp):
105
+ if exp == 0:
106
+ return self.new(1, 0)
107
+ if exp < 0:
108
+ self, exp = 1/self, -exp
109
+ if exp == 1:
110
+ return self
111
+ pow2 = self
112
+ prod = self if exp % 2 else self._parent.one
113
+ exp //= 2
114
+ while exp:
115
+ pow2 *= pow2
116
+ if exp % 2:
117
+ prod *= pow2
118
+ exp //= 2
119
+ return prod
120
+
121
+ def __bool__(self):
122
+ return bool(self.x) or bool(self.y)
123
+
124
+ def quadrant(self):
125
+ """Return quadrant index 0-3.
126
+
127
+ 0 is included in quadrant 0.
128
+ """
129
+ if self.y > 0:
130
+ return 0 if self.x > 0 else 1
131
+ elif self.y < 0:
132
+ return 2 if self.x < 0 else 3
133
+ else:
134
+ return 0 if self.x >= 0 else 2
135
+
136
+ def __rdivmod__(self, other):
137
+ try:
138
+ other = self._parent.convert(other)
139
+ except CoercionFailed:
140
+ return NotImplemented
141
+ else:
142
+ return other.__divmod__(self)
143
+
144
+ def __rtruediv__(self, other):
145
+ try:
146
+ other = QQ_I.convert(other)
147
+ except CoercionFailed:
148
+ return NotImplemented
149
+ else:
150
+ return other.__truediv__(self)
151
+
152
+ def __floordiv__(self, other):
153
+ qr = self.__divmod__(other)
154
+ return qr if qr is NotImplemented else qr[0]
155
+
156
+ def __rfloordiv__(self, other):
157
+ qr = self.__rdivmod__(other)
158
+ return qr if qr is NotImplemented else qr[0]
159
+
160
+ def __mod__(self, other):
161
+ qr = self.__divmod__(other)
162
+ return qr if qr is NotImplemented else qr[1]
163
+
164
+ def __rmod__(self, other):
165
+ qr = self.__rdivmod__(other)
166
+ return qr if qr is NotImplemented else qr[1]
167
+
168
+
169
+ class GaussianInteger(GaussianElement):
170
+ """Gaussian integer: domain element for :ref:`ZZ_I`
171
+
172
+ >>> from sympy import ZZ_I
173
+ >>> z = ZZ_I(2, 3)
174
+ >>> z
175
+ (2 + 3*I)
176
+ >>> type(z)
177
+ <class 'sympy.polys.domains.gaussiandomains.GaussianInteger'>
178
+ """
179
+ base = ZZ
180
+
181
+ def __truediv__(self, other):
182
+ """Return a Gaussian rational."""
183
+ return QQ_I.convert(self)/other
184
+
185
+ def __divmod__(self, other):
186
+ if not other:
187
+ raise ZeroDivisionError('divmod({}, 0)'.format(self))
188
+ x, y = self._get_xy(other)
189
+ if x is None:
190
+ return NotImplemented
191
+
192
+ # multiply self and other by x - I*y
193
+ # self/other == (a + I*b)/c
194
+ a, b = self.x*x + self.y*y, -self.x*y + self.y*x
195
+ c = x*x + y*y
196
+
197
+ # find integers qx and qy such that
198
+ # |a - qx*c| <= c/2 and |b - qy*c| <= c/2
199
+ qx = (2*a + c) // (2*c) # -c <= 2*a - qx*2*c < c
200
+ qy = (2*b + c) // (2*c)
201
+
202
+ q = GaussianInteger(qx, qy)
203
+ # |self/other - q| < 1 since
204
+ # |a/c - qx|**2 + |b/c - qy|**2 <= 1/4 + 1/4 < 1
205
+
206
+ return q, self - q*other # |r| < |other|
207
+
208
+
209
+ class GaussianRational(GaussianElement):
210
+ """Gaussian rational: domain element for :ref:`QQ_I`
211
+
212
+ >>> from sympy import QQ_I, QQ
213
+ >>> z = QQ_I(QQ(2, 3), QQ(4, 5))
214
+ >>> z
215
+ (2/3 + 4/5*I)
216
+ >>> type(z)
217
+ <class 'sympy.polys.domains.gaussiandomains.GaussianRational'>
218
+ """
219
+ base = QQ
220
+
221
+ def __truediv__(self, other):
222
+ """Return a Gaussian rational."""
223
+ if not other:
224
+ raise ZeroDivisionError('{} / 0'.format(self))
225
+ x, y = self._get_xy(other)
226
+ if x is None:
227
+ return NotImplemented
228
+ c = x*x + y*y
229
+
230
+ return GaussianRational((self.x*x + self.y*y)/c,
231
+ (-self.x*y + self.y*x)/c)
232
+
233
+ def __divmod__(self, other):
234
+ try:
235
+ other = self._parent.convert(other)
236
+ except CoercionFailed:
237
+ return NotImplemented
238
+ if not other:
239
+ raise ZeroDivisionError('{} % 0'.format(self))
240
+ else:
241
+ return self/other, QQ_I.zero
242
+
243
+
244
+ class GaussianDomain():
245
+ """Base class for Gaussian domains."""
246
+ dom = None # type: Domain
247
+
248
+ is_Numerical = True
249
+ is_Exact = True
250
+
251
+ has_assoc_Ring = True
252
+ has_assoc_Field = True
253
+
254
+ def to_sympy(self, a):
255
+ """Convert ``a`` to a SymPy object. """
256
+ conv = self.dom.to_sympy
257
+ return conv(a.x) + I*conv(a.y)
258
+
259
+ def from_sympy(self, a):
260
+ """Convert a SymPy object to ``self.dtype``."""
261
+ r, b = a.as_coeff_Add()
262
+ x = self.dom.from_sympy(r) # may raise CoercionFailed
263
+ if not b:
264
+ return self.new(x, 0)
265
+ r, b = b.as_coeff_Mul()
266
+ y = self.dom.from_sympy(r)
267
+ if b is I:
268
+ return self.new(x, y)
269
+ else:
270
+ raise CoercionFailed("{} is not Gaussian".format(a))
271
+
272
+ def inject(self, *gens):
273
+ """Inject generators into this domain. """
274
+ return self.poly_ring(*gens)
275
+
276
+ def canonical_unit(self, d):
277
+ unit = self.units[-d.quadrant()] # - for inverse power
278
+ return unit
279
+
280
+ def is_negative(self, element):
281
+ """Returns ``False`` for any ``GaussianElement``. """
282
+ return False
283
+
284
+ def is_positive(self, element):
285
+ """Returns ``False`` for any ``GaussianElement``. """
286
+ return False
287
+
288
+ def is_nonnegative(self, element):
289
+ """Returns ``False`` for any ``GaussianElement``. """
290
+ return False
291
+
292
+ def is_nonpositive(self, element):
293
+ """Returns ``False`` for any ``GaussianElement``. """
294
+ return False
295
+
296
+ def from_ZZ_gmpy(K1, a, K0):
297
+ """Convert a GMPY mpz to ``self.dtype``."""
298
+ return K1(a)
299
+
300
+ def from_ZZ(K1, a, K0):
301
+ """Convert a ZZ_python element to ``self.dtype``."""
302
+ return K1(a)
303
+
304
+ def from_ZZ_python(K1, a, K0):
305
+ """Convert a ZZ_python element to ``self.dtype``."""
306
+ return K1(a)
307
+
308
+ def from_QQ(K1, a, K0):
309
+ """Convert a GMPY mpq to ``self.dtype``."""
310
+ return K1(a)
311
+
312
+ def from_QQ_gmpy(K1, a, K0):
313
+ """Convert a GMPY mpq to ``self.dtype``."""
314
+ return K1(a)
315
+
316
+ def from_QQ_python(K1, a, K0):
317
+ """Convert a QQ_python element to ``self.dtype``."""
318
+ return K1(a)
319
+
320
+ def from_AlgebraicField(K1, a, K0):
321
+ """Convert an element from ZZ<I> or QQ<I> to ``self.dtype``."""
322
+ if K0.ext.args[0] == I:
323
+ return K1.from_sympy(K0.to_sympy(a))
324
+
325
+
326
+ class GaussianIntegerRing(GaussianDomain, Ring):
327
+ r"""Ring of Gaussian integers ``ZZ_I``
328
+
329
+ The :ref:`ZZ_I` domain represents the `Gaussian integers`_ `\mathbb{Z}[i]`
330
+ as a :py:class:`~.Domain` in the domain system (see
331
+ :ref:`polys-domainsintro`).
332
+
333
+ By default a :py:class:`~.Poly` created from an expression with
334
+ coefficients that are combinations of integers and ``I`` (`\sqrt{-1}`)
335
+ will have the domain :ref:`ZZ_I`.
336
+
337
+ >>> from sympy import Poly, Symbol, I
338
+ >>> x = Symbol('x')
339
+ >>> p = Poly(x**2 + I)
340
+ >>> p
341
+ Poly(x**2 + I, x, domain='ZZ_I')
342
+ >>> p.domain
343
+ ZZ_I
344
+
345
+ The :ref:`ZZ_I` domain can be used to factorise polynomials that are
346
+ reducible over the Gaussian integers.
347
+
348
+ >>> from sympy import factor
349
+ >>> factor(x**2 + 1)
350
+ x**2 + 1
351
+ >>> factor(x**2 + 1, domain='ZZ_I')
352
+ (x - I)*(x + I)
353
+
354
+ The corresponding `field of fractions`_ is the domain of the Gaussian
355
+ rationals :ref:`QQ_I`. Conversely :ref:`ZZ_I` is the `ring of integers`_
356
+ of :ref:`QQ_I`.
357
+
358
+ >>> from sympy import ZZ_I, QQ_I
359
+ >>> ZZ_I.get_field()
360
+ QQ_I
361
+ >>> QQ_I.get_ring()
362
+ ZZ_I
363
+
364
+ When using the domain directly :ref:`ZZ_I` can be used as a constructor.
365
+
366
+ >>> ZZ_I(3, 4)
367
+ (3 + 4*I)
368
+ >>> ZZ_I(5)
369
+ (5 + 0*I)
370
+
371
+ The domain elements of :ref:`ZZ_I` are instances of
372
+ :py:class:`~.GaussianInteger` which support the rings operations
373
+ ``+,-,*,**``.
374
+
375
+ >>> z1 = ZZ_I(5, 1)
376
+ >>> z2 = ZZ_I(2, 3)
377
+ >>> z1
378
+ (5 + 1*I)
379
+ >>> z2
380
+ (2 + 3*I)
381
+ >>> z1 + z2
382
+ (7 + 4*I)
383
+ >>> z1 * z2
384
+ (7 + 17*I)
385
+ >>> z1 ** 2
386
+ (24 + 10*I)
387
+
388
+ Both floor (``//``) and modulo (``%``) division work with
389
+ :py:class:`~.GaussianInteger` (see the :py:meth:`~.Domain.div` method).
390
+
391
+ >>> z3, z4 = ZZ_I(5), ZZ_I(1, 3)
392
+ >>> z3 // z4 # floor division
393
+ (1 + -1*I)
394
+ >>> z3 % z4 # modulo division (remainder)
395
+ (1 + -2*I)
396
+ >>> (z3//z4)*z4 + z3%z4 == z3
397
+ True
398
+
399
+ True division (``/``) in :ref:`ZZ_I` gives an element of :ref:`QQ_I`. The
400
+ :py:meth:`~.Domain.exquo` method can be used to divide in :ref:`ZZ_I` when
401
+ exact division is possible.
402
+
403
+ >>> z1 / z2
404
+ (1 + -1*I)
405
+ >>> ZZ_I.exquo(z1, z2)
406
+ (1 + -1*I)
407
+ >>> z3 / z4
408
+ (1/2 + -3/2*I)
409
+ >>> ZZ_I.exquo(z3, z4)
410
+ Traceback (most recent call last):
411
+ ...
412
+ ExactQuotientFailed: (1 + 3*I) does not divide (5 + 0*I) in ZZ_I
413
+
414
+ The :py:meth:`~.Domain.gcd` method can be used to compute the `gcd`_ of any
415
+ two elements.
416
+
417
+ >>> ZZ_I.gcd(ZZ_I(10), ZZ_I(2))
418
+ (2 + 0*I)
419
+ >>> ZZ_I.gcd(ZZ_I(5), ZZ_I(2, 1))
420
+ (2 + 1*I)
421
+
422
+ .. _Gaussian integers: https://en.wikipedia.org/wiki/Gaussian_integer
423
+ .. _gcd: https://en.wikipedia.org/wiki/Greatest_common_divisor
424
+
425
+ """
426
+ dom = ZZ
427
+ dtype = GaussianInteger
428
+ zero = dtype(ZZ(0), ZZ(0))
429
+ one = dtype(ZZ(1), ZZ(0))
430
+ imag_unit = dtype(ZZ(0), ZZ(1))
431
+ units = (one, imag_unit, -one, -imag_unit) # powers of i
432
+
433
+ rep = 'ZZ_I'
434
+
435
+ is_GaussianRing = True
436
+ is_ZZ_I = True
437
+
438
+ def __init__(self): # override Domain.__init__
439
+ """For constructing ZZ_I."""
440
+
441
+ def __eq__(self, other):
442
+ """Returns ``True`` if two domains are equivalent. """
443
+ if isinstance(other, GaussianIntegerRing):
444
+ return True
445
+ else:
446
+ return NotImplemented
447
+
448
+ def __hash__(self):
449
+ """Compute hash code of ``self``. """
450
+ return hash('ZZ_I')
451
+
452
+ @property
453
+ def has_CharacteristicZero(self):
454
+ return True
455
+
456
+ def characteristic(self):
457
+ return 0
458
+
459
+ def get_ring(self):
460
+ """Returns a ring associated with ``self``. """
461
+ return self
462
+
463
+ def get_field(self):
464
+ """Returns a field associated with ``self``. """
465
+ return QQ_I
466
+
467
+ def normalize(self, d, *args):
468
+ """Return first quadrant element associated with ``d``.
469
+
470
+ Also multiply the other arguments by the same power of i.
471
+ """
472
+ unit = self.canonical_unit(d)
473
+ d *= unit
474
+ args = tuple(a*unit for a in args)
475
+ return (d,) + args if args else d
476
+
477
+ def gcd(self, a, b):
478
+ """Greatest common divisor of a and b over ZZ_I."""
479
+ while b:
480
+ a, b = b, a % b
481
+ return self.normalize(a)
482
+
483
+ def lcm(self, a, b):
484
+ """Least common multiple of a and b over ZZ_I."""
485
+ return (a * b) // self.gcd(a, b)
486
+
487
+ def from_GaussianIntegerRing(K1, a, K0):
488
+ """Convert a ZZ_I element to ZZ_I."""
489
+ return a
490
+
491
+ def from_GaussianRationalField(K1, a, K0):
492
+ """Convert a QQ_I element to ZZ_I."""
493
+ return K1.new(ZZ.convert(a.x), ZZ.convert(a.y))
494
+
495
+ ZZ_I = GaussianInteger._parent = GaussianIntegerRing()
496
+
497
+
498
+ class GaussianRationalField(GaussianDomain, Field):
499
+ r"""Field of Gaussian rationals ``QQ_I``
500
+
501
+ The :ref:`QQ_I` domain represents the `Gaussian rationals`_ `\mathbb{Q}(i)`
502
+ as a :py:class:`~.Domain` in the domain system (see
503
+ :ref:`polys-domainsintro`).
504
+
505
+ By default a :py:class:`~.Poly` created from an expression with
506
+ coefficients that are combinations of rationals and ``I`` (`\sqrt{-1}`)
507
+ will have the domain :ref:`QQ_I`.
508
+
509
+ >>> from sympy import Poly, Symbol, I
510
+ >>> x = Symbol('x')
511
+ >>> p = Poly(x**2 + I/2)
512
+ >>> p
513
+ Poly(x**2 + I/2, x, domain='QQ_I')
514
+ >>> p.domain
515
+ QQ_I
516
+
517
+ The polys option ``gaussian=True`` can be used to specify that the domain
518
+ should be :ref:`QQ_I` even if the coefficients do not contain ``I`` or are
519
+ all integers.
520
+
521
+ >>> Poly(x**2)
522
+ Poly(x**2, x, domain='ZZ')
523
+ >>> Poly(x**2 + I)
524
+ Poly(x**2 + I, x, domain='ZZ_I')
525
+ >>> Poly(x**2/2)
526
+ Poly(1/2*x**2, x, domain='QQ')
527
+ >>> Poly(x**2, gaussian=True)
528
+ Poly(x**2, x, domain='QQ_I')
529
+ >>> Poly(x**2 + I, gaussian=True)
530
+ Poly(x**2 + I, x, domain='QQ_I')
531
+ >>> Poly(x**2/2, gaussian=True)
532
+ Poly(1/2*x**2, x, domain='QQ_I')
533
+
534
+ The :ref:`QQ_I` domain can be used to factorise polynomials that are
535
+ reducible over the Gaussian rationals.
536
+
537
+ >>> from sympy import factor, QQ_I
538
+ >>> factor(x**2/4 + 1)
539
+ (x**2 + 4)/4
540
+ >>> factor(x**2/4 + 1, domain='QQ_I')
541
+ (x - 2*I)*(x + 2*I)/4
542
+ >>> factor(x**2/4 + 1, domain=QQ_I)
543
+ (x - 2*I)*(x + 2*I)/4
544
+
545
+ It is also possible to specify the :ref:`QQ_I` domain explicitly with
546
+ polys functions like :py:func:`~.apart`.
547
+
548
+ >>> from sympy import apart
549
+ >>> apart(1/(1 + x**2))
550
+ 1/(x**2 + 1)
551
+ >>> apart(1/(1 + x**2), domain=QQ_I)
552
+ I/(2*(x + I)) - I/(2*(x - I))
553
+
554
+ The corresponding `ring of integers`_ is the domain of the Gaussian
555
+ integers :ref:`ZZ_I`. Conversely :ref:`QQ_I` is the `field of fractions`_
556
+ of :ref:`ZZ_I`.
557
+
558
+ >>> from sympy import ZZ_I, QQ_I, QQ
559
+ >>> ZZ_I.get_field()
560
+ QQ_I
561
+ >>> QQ_I.get_ring()
562
+ ZZ_I
563
+
564
+ When using the domain directly :ref:`QQ_I` can be used as a constructor.
565
+
566
+ >>> QQ_I(3, 4)
567
+ (3 + 4*I)
568
+ >>> QQ_I(5)
569
+ (5 + 0*I)
570
+ >>> QQ_I(QQ(2, 3), QQ(4, 5))
571
+ (2/3 + 4/5*I)
572
+
573
+ The domain elements of :ref:`QQ_I` are instances of
574
+ :py:class:`~.GaussianRational` which support the field operations
575
+ ``+,-,*,**,/``.
576
+
577
+ >>> z1 = QQ_I(5, 1)
578
+ >>> z2 = QQ_I(2, QQ(1, 2))
579
+ >>> z1
580
+ (5 + 1*I)
581
+ >>> z2
582
+ (2 + 1/2*I)
583
+ >>> z1 + z2
584
+ (7 + 3/2*I)
585
+ >>> z1 * z2
586
+ (19/2 + 9/2*I)
587
+ >>> z2 ** 2
588
+ (15/4 + 2*I)
589
+
590
+ True division (``/``) in :ref:`QQ_I` gives an element of :ref:`QQ_I` and
591
+ is always exact.
592
+
593
+ >>> z1 / z2
594
+ (42/17 + -2/17*I)
595
+ >>> QQ_I.exquo(z1, z2)
596
+ (42/17 + -2/17*I)
597
+ >>> z1 == (z1/z2)*z2
598
+ True
599
+
600
+ Both floor (``//``) and modulo (``%``) division can be used with
601
+ :py:class:`~.GaussianRational` (see :py:meth:`~.Domain.div`)
602
+ but division is always exact so there is no remainder.
603
+
604
+ >>> z1 // z2
605
+ (42/17 + -2/17*I)
606
+ >>> z1 % z2
607
+ (0 + 0*I)
608
+ >>> QQ_I.div(z1, z2)
609
+ ((42/17 + -2/17*I), (0 + 0*I))
610
+ >>> (z1//z2)*z2 + z1%z2 == z1
611
+ True
612
+
613
+ .. _Gaussian rationals: https://en.wikipedia.org/wiki/Gaussian_rational
614
+ """
615
+ dom = QQ
616
+ dtype = GaussianRational
617
+ zero = dtype(QQ(0), QQ(0))
618
+ one = dtype(QQ(1), QQ(0))
619
+ imag_unit = dtype(QQ(0), QQ(1))
620
+ units = (one, imag_unit, -one, -imag_unit) # powers of i
621
+
622
+ rep = 'QQ_I'
623
+
624
+ is_GaussianField = True
625
+ is_QQ_I = True
626
+
627
+ def __init__(self): # override Domain.__init__
628
+ """For constructing QQ_I."""
629
+
630
+ def __eq__(self, other):
631
+ """Returns ``True`` if two domains are equivalent. """
632
+ if isinstance(other, GaussianRationalField):
633
+ return True
634
+ else:
635
+ return NotImplemented
636
+
637
+ def __hash__(self):
638
+ """Compute hash code of ``self``. """
639
+ return hash('QQ_I')
640
+
641
+ @property
642
+ def has_CharacteristicZero(self):
643
+ return True
644
+
645
+ def characteristic(self):
646
+ return 0
647
+
648
+ def get_ring(self):
649
+ """Returns a ring associated with ``self``. """
650
+ return ZZ_I
651
+
652
+ def get_field(self):
653
+ """Returns a field associated with ``self``. """
654
+ return self
655
+
656
+ def as_AlgebraicField(self):
657
+ """Get equivalent domain as an ``AlgebraicField``. """
658
+ return AlgebraicField(self.dom, I)
659
+
660
+ def numer(self, a):
661
+ """Get the numerator of ``a``."""
662
+ ZZ_I = self.get_ring()
663
+ return ZZ_I.convert(a * self.denom(a))
664
+
665
+ def denom(self, a):
666
+ """Get the denominator of ``a``."""
667
+ ZZ = self.dom.get_ring()
668
+ QQ = self.dom
669
+ ZZ_I = self.get_ring()
670
+ denom_ZZ = ZZ.lcm(QQ.denom(a.x), QQ.denom(a.y))
671
+ return ZZ_I(denom_ZZ, ZZ.zero)
672
+
673
+ def from_GaussianIntegerRing(K1, a, K0):
674
+ """Convert a ZZ_I element to QQ_I."""
675
+ return K1.new(a.x, a.y)
676
+
677
+ def from_GaussianRationalField(K1, a, K0):
678
+ """Convert a QQ_I element to QQ_I."""
679
+ return a
680
+
681
+ def from_ComplexField(K1, a, K0):
682
+ """Convert a ComplexField element to QQ_I."""
683
+ return K1.new(QQ.convert(a.real), QQ.convert(a.imag))
684
+
685
+
686
+ QQ_I = GaussianRational._parent = GaussianRationalField()
lib/python3.12/site-packages/sympy/polys/domains/gmpyfinitefield.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of :class:`GMPYFiniteField` class. """
2
+
3
+
4
+ from sympy.polys.domains.finitefield import FiniteField
5
+ from sympy.polys.domains.gmpyintegerring import GMPYIntegerRing
6
+
7
+ from sympy.utilities import public
8
+
9
+ @public
10
+ class GMPYFiniteField(FiniteField):
11
+ """Finite field based on GMPY integers. """
12
+
13
+ alias = 'FF_gmpy'
14
+
15
+ def __init__(self, mod, symmetric=True):
16
+ super().__init__(mod, GMPYIntegerRing(), symmetric)
lib/python3.12/site-packages/sympy/polys/domains/gmpyintegerring.py ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of :class:`GMPYIntegerRing` class. """
2
+
3
+
4
+ from sympy.polys.domains.groundtypes import (
5
+ GMPYInteger, SymPyInteger,
6
+ factorial as gmpy_factorial,
7
+ gmpy_gcdex, gmpy_gcd, gmpy_lcm, sqrt as gmpy_sqrt,
8
+ )
9
+ from sympy.core.numbers import int_valued
10
+ from sympy.polys.domains.integerring import IntegerRing
11
+ from sympy.polys.polyerrors import CoercionFailed
12
+ from sympy.utilities import public
13
+
14
+ @public
15
+ class GMPYIntegerRing(IntegerRing):
16
+ """Integer ring based on GMPY's ``mpz`` type.
17
+
18
+ This will be the implementation of :ref:`ZZ` if ``gmpy`` or ``gmpy2`` is
19
+ installed. Elements will be of type ``gmpy.mpz``.
20
+ """
21
+
22
+ dtype = GMPYInteger
23
+ zero = dtype(0)
24
+ one = dtype(1)
25
+ tp = type(one)
26
+ alias = 'ZZ_gmpy'
27
+
28
+ def __init__(self):
29
+ """Allow instantiation of this domain. """
30
+
31
+ def to_sympy(self, a):
32
+ """Convert ``a`` to a SymPy object. """
33
+ return SymPyInteger(int(a))
34
+
35
+ def from_sympy(self, a):
36
+ """Convert SymPy's Integer to ``dtype``. """
37
+ if a.is_Integer:
38
+ return GMPYInteger(a.p)
39
+ elif int_valued(a):
40
+ return GMPYInteger(int(a))
41
+ else:
42
+ raise CoercionFailed("expected an integer, got %s" % a)
43
+
44
+ def from_FF_python(K1, a, K0):
45
+ """Convert ``ModularInteger(int)`` to GMPY's ``mpz``. """
46
+ return K0.to_int(a)
47
+
48
+ def from_ZZ_python(K1, a, K0):
49
+ """Convert Python's ``int`` to GMPY's ``mpz``. """
50
+ return GMPYInteger(a)
51
+
52
+ def from_QQ(K1, a, K0):
53
+ """Convert Python's ``Fraction`` to GMPY's ``mpz``. """
54
+ if a.denominator == 1:
55
+ return GMPYInteger(a.numerator)
56
+
57
+ def from_QQ_python(K1, a, K0):
58
+ """Convert Python's ``Fraction`` to GMPY's ``mpz``. """
59
+ if a.denominator == 1:
60
+ return GMPYInteger(a.numerator)
61
+
62
+ def from_FF_gmpy(K1, a, K0):
63
+ """Convert ``ModularInteger(mpz)`` to GMPY's ``mpz``. """
64
+ return K0.to_int(a)
65
+
66
+ def from_ZZ_gmpy(K1, a, K0):
67
+ """Convert GMPY's ``mpz`` to GMPY's ``mpz``. """
68
+ return a
69
+
70
+ def from_QQ_gmpy(K1, a, K0):
71
+ """Convert GMPY ``mpq`` to GMPY's ``mpz``. """
72
+ if a.denominator == 1:
73
+ return a.numerator
74
+
75
+ def from_RealField(K1, a, K0):
76
+ """Convert mpmath's ``mpf`` to GMPY's ``mpz``. """
77
+ p, q = K0.to_rational(a)
78
+
79
+ if q == 1:
80
+ return GMPYInteger(p)
81
+
82
+ def from_GaussianIntegerRing(K1, a, K0):
83
+ if a.y == 0:
84
+ return a.x
85
+
86
+ def gcdex(self, a, b):
87
+ """Compute extended GCD of ``a`` and ``b``. """
88
+ h, s, t = gmpy_gcdex(a, b)
89
+ return s, t, h
90
+
91
+ def gcd(self, a, b):
92
+ """Compute GCD of ``a`` and ``b``. """
93
+ return gmpy_gcd(a, b)
94
+
95
+ def lcm(self, a, b):
96
+ """Compute LCM of ``a`` and ``b``. """
97
+ return gmpy_lcm(a, b)
98
+
99
+ def sqrt(self, a):
100
+ """Compute square root of ``a``. """
101
+ return gmpy_sqrt(a)
102
+
103
+ def factorial(self, a):
104
+ """Compute factorial of ``a``. """
105
+ return gmpy_factorial(a)
lib/python3.12/site-packages/sympy/polys/domains/gmpyrationalfield.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of :class:`GMPYRationalField` class. """
2
+
3
+
4
+ from sympy.polys.domains.groundtypes import (
5
+ GMPYRational, SymPyRational,
6
+ gmpy_numer, gmpy_denom, factorial as gmpy_factorial,
7
+ )
8
+ from sympy.polys.domains.rationalfield import RationalField
9
+ from sympy.polys.polyerrors import CoercionFailed
10
+ from sympy.utilities import public
11
+
12
+ @public
13
+ class GMPYRationalField(RationalField):
14
+ """Rational field based on GMPY's ``mpq`` type.
15
+
16
+ This will be the implementation of :ref:`QQ` if ``gmpy`` or ``gmpy2`` is
17
+ installed. Elements will be of type ``gmpy.mpq``.
18
+ """
19
+
20
+ dtype = GMPYRational
21
+ zero = dtype(0)
22
+ one = dtype(1)
23
+ tp = type(one)
24
+ alias = 'QQ_gmpy'
25
+
26
+ def __init__(self):
27
+ pass
28
+
29
+ def get_ring(self):
30
+ """Returns ring associated with ``self``. """
31
+ from sympy.polys.domains import GMPYIntegerRing
32
+ return GMPYIntegerRing()
33
+
34
+ def to_sympy(self, a):
35
+ """Convert ``a`` to a SymPy object. """
36
+ return SymPyRational(int(gmpy_numer(a)),
37
+ int(gmpy_denom(a)))
38
+
39
+ def from_sympy(self, a):
40
+ """Convert SymPy's Integer to ``dtype``. """
41
+ if a.is_Rational:
42
+ return GMPYRational(a.p, a.q)
43
+ elif a.is_Float:
44
+ from sympy.polys.domains import RR
45
+ return GMPYRational(*map(int, RR.to_rational(a)))
46
+ else:
47
+ raise CoercionFailed("expected ``Rational`` object, got %s" % a)
48
+
49
+ def from_ZZ_python(K1, a, K0):
50
+ """Convert a Python ``int`` object to ``dtype``. """
51
+ return GMPYRational(a)
52
+
53
+ def from_QQ_python(K1, a, K0):
54
+ """Convert a Python ``Fraction`` object to ``dtype``. """
55
+ return GMPYRational(a.numerator, a.denominator)
56
+
57
+ def from_ZZ_gmpy(K1, a, K0):
58
+ """Convert a GMPY ``mpz`` object to ``dtype``. """
59
+ return GMPYRational(a)
60
+
61
+ def from_QQ_gmpy(K1, a, K0):
62
+ """Convert a GMPY ``mpq`` object to ``dtype``. """
63
+ return a
64
+
65
+ def from_GaussianRationalField(K1, a, K0):
66
+ """Convert a ``GaussianElement`` object to ``dtype``. """
67
+ if a.y == 0:
68
+ return GMPYRational(a.x)
69
+
70
+ def from_RealField(K1, a, K0):
71
+ """Convert a mpmath ``mpf`` object to ``dtype``. """
72
+ return GMPYRational(*map(int, K0.to_rational(a)))
73
+
74
+ def exquo(self, a, b):
75
+ """Exact quotient of ``a`` and ``b``, implies ``__truediv__``. """
76
+ return GMPYRational(a) / GMPYRational(b)
77
+
78
+ def quo(self, a, b):
79
+ """Quotient of ``a`` and ``b``, implies ``__truediv__``. """
80
+ return GMPYRational(a) / GMPYRational(b)
81
+
82
+ def rem(self, a, b):
83
+ """Remainder of ``a`` and ``b``, implies nothing. """
84
+ return self.zero
85
+
86
+ def div(self, a, b):
87
+ """Division of ``a`` and ``b``, implies ``__truediv__``. """
88
+ return GMPYRational(a) / GMPYRational(b), self.zero
89
+
90
+ def numer(self, a):
91
+ """Returns numerator of ``a``. """
92
+ return a.numerator
93
+
94
+ def denom(self, a):
95
+ """Returns denominator of ``a``. """
96
+ return a.denominator
97
+
98
+ def factorial(self, a):
99
+ """Returns factorial of ``a``. """
100
+ return GMPYRational(gmpy_factorial(int(a)))
lib/python3.12/site-packages/sympy/polys/domains/groundtypes.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Ground types for various mathematical domains in SymPy. """
2
+
3
+ import builtins
4
+ from sympy.external.gmpy import GROUND_TYPES, factorial, sqrt, is_square, sqrtrem
5
+
6
+ PythonInteger = builtins.int
7
+ PythonReal = builtins.float
8
+ PythonComplex = builtins.complex
9
+
10
+ from .pythonrational import PythonRational
11
+
12
+ from sympy.core.intfunc import (
13
+ igcdex as python_gcdex,
14
+ igcd2 as python_gcd,
15
+ ilcm as python_lcm,
16
+ )
17
+
18
+ from sympy.core.numbers import (Float as SymPyReal, Integer as SymPyInteger, Rational as SymPyRational)
19
+
20
+
21
+ class _GMPYInteger:
22
+ def __init__(self, obj):
23
+ pass
24
+
25
+ class _GMPYRational:
26
+ def __init__(self, obj):
27
+ pass
28
+
29
+
30
+ if GROUND_TYPES == 'gmpy':
31
+
32
+ from gmpy2 import (
33
+ mpz as GMPYInteger,
34
+ mpq as GMPYRational,
35
+ numer as gmpy_numer,
36
+ denom as gmpy_denom,
37
+ gcdext as gmpy_gcdex,
38
+ gcd as gmpy_gcd,
39
+ lcm as gmpy_lcm,
40
+ qdiv as gmpy_qdiv,
41
+ )
42
+ gcdex = gmpy_gcdex
43
+ gcd = gmpy_gcd
44
+ lcm = gmpy_lcm
45
+
46
+ elif GROUND_TYPES == 'flint':
47
+
48
+ from flint import fmpz as _fmpz
49
+
50
+ GMPYInteger = _GMPYInteger
51
+ GMPYRational = _GMPYRational
52
+ gmpy_numer = None
53
+ gmpy_denom = None
54
+ gmpy_gcdex = None
55
+ gmpy_gcd = None
56
+ gmpy_lcm = None
57
+ gmpy_qdiv = None
58
+
59
+ def gcd(a, b):
60
+ return a.gcd(b)
61
+
62
+ def gcdex(a, b):
63
+ x, y, g = python_gcdex(a, b)
64
+ return _fmpz(x), _fmpz(y), _fmpz(g)
65
+
66
+ def lcm(a, b):
67
+ return a.lcm(b)
68
+
69
+ else:
70
+ GMPYInteger = _GMPYInteger
71
+ GMPYRational = _GMPYRational
72
+ gmpy_numer = None
73
+ gmpy_denom = None
74
+ gmpy_gcdex = None
75
+ gmpy_gcd = None
76
+ gmpy_lcm = None
77
+ gmpy_qdiv = None
78
+ gcdex = python_gcdex
79
+ gcd = python_gcd
80
+ lcm = python_lcm
81
+
82
+
83
+ __all__ = [
84
+ 'PythonInteger', 'PythonReal', 'PythonComplex',
85
+
86
+ 'PythonRational',
87
+
88
+ 'python_gcdex', 'python_gcd', 'python_lcm',
89
+
90
+ 'SymPyReal', 'SymPyInteger', 'SymPyRational',
91
+
92
+ 'GMPYInteger', 'GMPYRational', 'gmpy_numer',
93
+ 'gmpy_denom', 'gmpy_gcdex', 'gmpy_gcd', 'gmpy_lcm',
94
+ 'gmpy_qdiv',
95
+
96
+ 'factorial', 'sqrt', 'is_square', 'sqrtrem',
97
+
98
+ 'GMPYInteger', 'GMPYRational',
99
+ ]
lib/python3.12/site-packages/sympy/polys/domains/integerring.py ADDED
@@ -0,0 +1,276 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of :class:`IntegerRing` class. """
2
+
3
+ from sympy.external.gmpy import MPZ, GROUND_TYPES
4
+
5
+ from sympy.core.numbers import int_valued
6
+ from sympy.polys.domains.groundtypes import (
7
+ SymPyInteger,
8
+ factorial,
9
+ gcdex, gcd, lcm, sqrt, is_square, sqrtrem,
10
+ )
11
+
12
+ from sympy.polys.domains.characteristiczero import CharacteristicZero
13
+ from sympy.polys.domains.ring import Ring
14
+ from sympy.polys.domains.simpledomain import SimpleDomain
15
+ from sympy.polys.polyerrors import CoercionFailed
16
+ from sympy.utilities import public
17
+
18
+ import math
19
+
20
+ @public
21
+ class IntegerRing(Ring, CharacteristicZero, SimpleDomain):
22
+ r"""The domain ``ZZ`` representing the integers `\mathbb{Z}`.
23
+
24
+ The :py:class:`IntegerRing` class represents the ring of integers as a
25
+ :py:class:`~.Domain` in the domain system. :py:class:`IntegerRing` is a
26
+ super class of :py:class:`PythonIntegerRing` and
27
+ :py:class:`GMPYIntegerRing` one of which will be the implementation for
28
+ :ref:`ZZ` depending on whether or not ``gmpy`` or ``gmpy2`` is installed.
29
+
30
+ See also
31
+ ========
32
+
33
+ Domain
34
+ """
35
+
36
+ rep = 'ZZ'
37
+ alias = 'ZZ'
38
+ dtype = MPZ
39
+ zero = dtype(0)
40
+ one = dtype(1)
41
+ tp = type(one)
42
+
43
+
44
+ is_IntegerRing = is_ZZ = True
45
+ is_Numerical = True
46
+ is_PID = True
47
+
48
+ has_assoc_Ring = True
49
+ has_assoc_Field = True
50
+
51
+ def __init__(self):
52
+ """Allow instantiation of this domain. """
53
+
54
+ def __eq__(self, other):
55
+ """Returns ``True`` if two domains are equivalent. """
56
+ if isinstance(other, IntegerRing):
57
+ return True
58
+ else:
59
+ return NotImplemented
60
+
61
+ def __hash__(self):
62
+ """Compute a hash value for this domain. """
63
+ return hash('ZZ')
64
+
65
+ def to_sympy(self, a):
66
+ """Convert ``a`` to a SymPy object. """
67
+ return SymPyInteger(int(a))
68
+
69
+ def from_sympy(self, a):
70
+ """Convert SymPy's Integer to ``dtype``. """
71
+ if a.is_Integer:
72
+ return MPZ(a.p)
73
+ elif int_valued(a):
74
+ return MPZ(int(a))
75
+ else:
76
+ raise CoercionFailed("expected an integer, got %s" % a)
77
+
78
+ def get_field(self):
79
+ r"""Return the associated field of fractions :ref:`QQ`
80
+
81
+ Returns
82
+ =======
83
+
84
+ :ref:`QQ`:
85
+ The associated field of fractions :ref:`QQ`, a
86
+ :py:class:`~.Domain` representing the rational numbers
87
+ `\mathbb{Q}`.
88
+
89
+ Examples
90
+ ========
91
+
92
+ >>> from sympy import ZZ
93
+ >>> ZZ.get_field()
94
+ QQ
95
+ """
96
+ from sympy.polys.domains import QQ
97
+ return QQ
98
+
99
+ def algebraic_field(self, *extension, alias=None):
100
+ r"""Returns an algebraic field, i.e. `\mathbb{Q}(\alpha, \ldots)`.
101
+
102
+ Parameters
103
+ ==========
104
+
105
+ *extension : One or more :py:class:`~.Expr`.
106
+ Generators of the extension. These should be expressions that are
107
+ algebraic over `\mathbb{Q}`.
108
+
109
+ alias : str, :py:class:`~.Symbol`, None, optional (default=None)
110
+ If provided, this will be used as the alias symbol for the
111
+ primitive element of the returned :py:class:`~.AlgebraicField`.
112
+
113
+ Returns
114
+ =======
115
+
116
+ :py:class:`~.AlgebraicField`
117
+ A :py:class:`~.Domain` representing the algebraic field extension.
118
+
119
+ Examples
120
+ ========
121
+
122
+ >>> from sympy import ZZ, sqrt
123
+ >>> ZZ.algebraic_field(sqrt(2))
124
+ QQ<sqrt(2)>
125
+ """
126
+ return self.get_field().algebraic_field(*extension, alias=alias)
127
+
128
+ def from_AlgebraicField(K1, a, K0):
129
+ """Convert a :py:class:`~.ANP` object to :ref:`ZZ`.
130
+
131
+ See :py:meth:`~.Domain.convert`.
132
+ """
133
+ if a.is_ground:
134
+ return K1.convert(a.LC(), K0.dom)
135
+
136
+ def log(self, a, b):
137
+ r"""Logarithm of *a* to the base *b*.
138
+
139
+ Parameters
140
+ ==========
141
+
142
+ a: number
143
+ b: number
144
+
145
+ Returns
146
+ =======
147
+
148
+ $\\lfloor\log(a, b)\\rfloor$:
149
+ Floor of the logarithm of *a* to the base *b*
150
+
151
+ Examples
152
+ ========
153
+
154
+ >>> from sympy import ZZ
155
+ >>> ZZ.log(ZZ(8), ZZ(2))
156
+ 3
157
+ >>> ZZ.log(ZZ(9), ZZ(2))
158
+ 3
159
+
160
+ Notes
161
+ =====
162
+
163
+ This function uses ``math.log`` which is based on ``float`` so it will
164
+ fail for large integer arguments.
165
+ """
166
+ return self.dtype(int(math.log(int(a), b)))
167
+
168
+ def from_FF(K1, a, K0):
169
+ """Convert ``ModularInteger(int)`` to GMPY's ``mpz``. """
170
+ return MPZ(K0.to_int(a))
171
+
172
+ def from_FF_python(K1, a, K0):
173
+ """Convert ``ModularInteger(int)`` to GMPY's ``mpz``. """
174
+ return MPZ(K0.to_int(a))
175
+
176
+ def from_ZZ(K1, a, K0):
177
+ """Convert Python's ``int`` to GMPY's ``mpz``. """
178
+ return MPZ(a)
179
+
180
+ def from_ZZ_python(K1, a, K0):
181
+ """Convert Python's ``int`` to GMPY's ``mpz``. """
182
+ return MPZ(a)
183
+
184
+ def from_QQ(K1, a, K0):
185
+ """Convert Python's ``Fraction`` to GMPY's ``mpz``. """
186
+ if a.denominator == 1:
187
+ return MPZ(a.numerator)
188
+
189
+ def from_QQ_python(K1, a, K0):
190
+ """Convert Python's ``Fraction`` to GMPY's ``mpz``. """
191
+ if a.denominator == 1:
192
+ return MPZ(a.numerator)
193
+
194
+ def from_FF_gmpy(K1, a, K0):
195
+ """Convert ``ModularInteger(mpz)`` to GMPY's ``mpz``. """
196
+ return MPZ(K0.to_int(a))
197
+
198
+ def from_ZZ_gmpy(K1, a, K0):
199
+ """Convert GMPY's ``mpz`` to GMPY's ``mpz``. """
200
+ return a
201
+
202
+ def from_QQ_gmpy(K1, a, K0):
203
+ """Convert GMPY ``mpq`` to GMPY's ``mpz``. """
204
+ if a.denominator == 1:
205
+ return a.numerator
206
+
207
+ def from_RealField(K1, a, K0):
208
+ """Convert mpmath's ``mpf`` to GMPY's ``mpz``. """
209
+ p, q = K0.to_rational(a)
210
+
211
+ if q == 1:
212
+ # XXX: If MPZ is flint.fmpz and p is a gmpy2.mpz, then we need
213
+ # to convert via int because fmpz and mpz do not know about each
214
+ # other.
215
+ return MPZ(int(p))
216
+
217
+ def from_GaussianIntegerRing(K1, a, K0):
218
+ if a.y == 0:
219
+ return a.x
220
+
221
+ def from_EX(K1, a, K0):
222
+ """Convert ``Expression`` to GMPY's ``mpz``. """
223
+ if a.is_Integer:
224
+ return K1.from_sympy(a)
225
+
226
+ def gcdex(self, a, b):
227
+ """Compute extended GCD of ``a`` and ``b``. """
228
+ h, s, t = gcdex(a, b)
229
+ # XXX: This conditional logic should be handled somewhere else.
230
+ if GROUND_TYPES == 'gmpy':
231
+ return s, t, h
232
+ else:
233
+ return h, s, t
234
+
235
+ def gcd(self, a, b):
236
+ """Compute GCD of ``a`` and ``b``. """
237
+ return gcd(a, b)
238
+
239
+ def lcm(self, a, b):
240
+ """Compute LCM of ``a`` and ``b``. """
241
+ return lcm(a, b)
242
+
243
+ def sqrt(self, a):
244
+ """Compute square root of ``a``. """
245
+ return sqrt(a)
246
+
247
+ def is_square(self, a):
248
+ """Return ``True`` if ``a`` is a square.
249
+
250
+ Explanation
251
+ ===========
252
+ An integer is a square if and only if there exists an integer
253
+ ``b`` such that ``b * b == a``.
254
+ """
255
+ return is_square(a)
256
+
257
+ def exsqrt(self, a):
258
+ """Non-negative square root of ``a`` if ``a`` is a square.
259
+
260
+ See also
261
+ ========
262
+ is_square
263
+ """
264
+ if a < 0:
265
+ return None
266
+ root, rem = sqrtrem(a)
267
+ if rem != 0:
268
+ return None
269
+ return root
270
+
271
+ def factorial(self, a):
272
+ """Compute factorial of ``a``. """
273
+ return factorial(a)
274
+
275
+
276
+ ZZ = IntegerRing()