Coverage for /usr/lib/python3/dist-packages/sympy/polys/domains/polynomialring.py: 41%
116 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1"""Implementation of :class:`PolynomialRing` class. """
4from sympy.polys.domains.ring import Ring
5from sympy.polys.domains.compositedomain import CompositeDomain
7from sympy.polys.polyerrors import CoercionFailed, GeneratorsError
8from sympy.utilities import public
10@public
11class PolynomialRing(Ring, CompositeDomain):
12 """A class for representing multivariate polynomial rings. """
14 is_PolynomialRing = is_Poly = True
16 has_assoc_Ring = True
17 has_assoc_Field = True
19 def __init__(self, domain_or_ring, symbols=None, order=None):
20 from sympy.polys.rings import PolyRing
22 if isinstance(domain_or_ring, PolyRing) and symbols is None and order is None:
23 ring = domain_or_ring
24 else:
25 ring = PolyRing(symbols, domain_or_ring, order)
27 self.ring = ring
28 self.dtype = ring.dtype
30 self.gens = ring.gens
31 self.ngens = ring.ngens
32 self.symbols = ring.symbols
33 self.domain = ring.domain
36 if symbols:
37 if ring.domain.is_Field and ring.domain.is_Exact and len(symbols)==1:
38 self.is_PID = True
40 # TODO: remove this
41 self.dom = self.domain
43 def new(self, element):
44 return self.ring.ring_new(element)
46 @property
47 def zero(self):
48 return self.ring.zero
50 @property
51 def one(self):
52 return self.ring.one
54 @property
55 def order(self):
56 return self.ring.order
58 def __str__(self):
59 return str(self.domain) + '[' + ','.join(map(str, self.symbols)) + ']'
61 def __hash__(self):
62 return hash((self.__class__.__name__, self.dtype.ring, self.domain, self.symbols))
64 def __eq__(self, other):
65 """Returns `True` if two domains are equivalent. """
66 return isinstance(other, PolynomialRing) and \
67 (self.dtype.ring, self.domain, self.symbols) == \
68 (other.dtype.ring, other.domain, other.symbols)
70 def is_unit(self, a):
71 """Returns ``True`` if ``a`` is a unit of ``self``"""
72 if not a.is_ground:
73 return False
74 K = self.domain
75 return K.is_unit(K.convert_from(a, self))
77 def canonical_unit(self, a):
78 u = self.domain.canonical_unit(a.LC)
79 return self.ring.ground_new(u)
81 def to_sympy(self, a):
82 """Convert `a` to a SymPy object. """
83 return a.as_expr()
85 def from_sympy(self, a):
86 """Convert SymPy's expression to `dtype`. """
87 return self.ring.from_expr(a)
89 def from_ZZ(K1, a, K0):
90 """Convert a Python `int` object to `dtype`. """
91 return K1(K1.domain.convert(a, K0))
93 def from_ZZ_python(K1, a, K0):
94 """Convert a Python `int` object to `dtype`. """
95 return K1(K1.domain.convert(a, K0))
97 def from_QQ(K1, a, K0):
98 """Convert a Python `Fraction` object to `dtype`. """
99 return K1(K1.domain.convert(a, K0))
101 def from_QQ_python(K1, a, K0):
102 """Convert a Python `Fraction` object to `dtype`. """
103 return K1(K1.domain.convert(a, K0))
105 def from_ZZ_gmpy(K1, a, K0):
106 """Convert a GMPY `mpz` object to `dtype`. """
107 return K1(K1.domain.convert(a, K0))
109 def from_QQ_gmpy(K1, a, K0):
110 """Convert a GMPY `mpq` object to `dtype`. """
111 return K1(K1.domain.convert(a, K0))
113 def from_GaussianIntegerRing(K1, a, K0):
114 """Convert a `GaussianInteger` object to `dtype`. """
115 return K1(K1.domain.convert(a, K0))
117 def from_GaussianRationalField(K1, a, K0):
118 """Convert a `GaussianRational` object to `dtype`. """
119 return K1(K1.domain.convert(a, K0))
121 def from_RealField(K1, a, K0):
122 """Convert a mpmath `mpf` object to `dtype`. """
123 return K1(K1.domain.convert(a, K0))
125 def from_ComplexField(K1, a, K0):
126 """Convert a mpmath `mpf` object to `dtype`. """
127 return K1(K1.domain.convert(a, K0))
129 def from_AlgebraicField(K1, a, K0):
130 """Convert an algebraic number to ``dtype``. """
131 if K1.domain != K0:
132 a = K1.domain.convert_from(a, K0)
133 if a is not None:
134 return K1.new(a)
136 def from_PolynomialRing(K1, a, K0):
137 """Convert a polynomial to ``dtype``. """
138 try:
139 return a.set_ring(K1.ring)
140 except (CoercionFailed, GeneratorsError):
141 return None
143 def from_FractionField(K1, a, K0):
144 """Convert a rational function to ``dtype``. """
145 if K1.domain == K0:
146 return K1.ring.from_list([a])
148 q, r = K0.numer(a).div(K0.denom(a))
150 if r.is_zero:
151 return K1.from_PolynomialRing(q, K0.field.ring.to_domain())
152 else:
153 return None
155 def from_GlobalPolynomialRing(K1, a, K0):
156 """Convert from old poly ring to ``dtype``. """
157 if K1.symbols == K0.gens:
158 ad = a.to_dict()
159 if K1.domain != K0.domain:
160 ad = {m: K1.domain.convert(c) for m, c in ad.items()}
161 return K1(ad)
162 elif a.is_ground and K0.domain == K1:
163 return K1.convert_from(a.to_list()[0], K0.domain)
165 def get_field(self):
166 """Returns a field associated with `self`. """
167 return self.ring.to_field().to_domain()
169 def is_positive(self, a):
170 """Returns True if `LC(a)` is positive. """
171 return self.domain.is_positive(a.LC)
173 def is_negative(self, a):
174 """Returns True if `LC(a)` is negative. """
175 return self.domain.is_negative(a.LC)
177 def is_nonpositive(self, a):
178 """Returns True if `LC(a)` is non-positive. """
179 return self.domain.is_nonpositive(a.LC)
181 def is_nonnegative(self, a):
182 """Returns True if `LC(a)` is non-negative. """
183 return self.domain.is_nonnegative(a.LC)
185 def gcdex(self, a, b):
186 """Extended GCD of `a` and `b`. """
187 return a.gcdex(b)
189 def gcd(self, a, b):
190 """Returns GCD of `a` and `b`. """
191 return a.gcd(b)
193 def lcm(self, a, b):
194 """Returns LCM of `a` and `b`. """
195 return a.lcm(b)
197 def factorial(self, a):
198 """Returns factorial of `a`. """
199 return self.dtype(self.domain.factorial(a))