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

1"""Implementation of :class:`PolynomialRing` class. """ 

2 

3 

4from sympy.polys.domains.ring import Ring 

5from sympy.polys.domains.compositedomain import CompositeDomain 

6 

7from sympy.polys.polyerrors import CoercionFailed, GeneratorsError 

8from sympy.utilities import public 

9 

10@public 

11class PolynomialRing(Ring, CompositeDomain): 

12 """A class for representing multivariate polynomial rings. """ 

13 

14 is_PolynomialRing = is_Poly = True 

15 

16 has_assoc_Ring = True 

17 has_assoc_Field = True 

18 

19 def __init__(self, domain_or_ring, symbols=None, order=None): 

20 from sympy.polys.rings import PolyRing 

21 

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) 

26 

27 self.ring = ring 

28 self.dtype = ring.dtype 

29 

30 self.gens = ring.gens 

31 self.ngens = ring.ngens 

32 self.symbols = ring.symbols 

33 self.domain = ring.domain 

34 

35 

36 if symbols: 

37 if ring.domain.is_Field and ring.domain.is_Exact and len(symbols)==1: 

38 self.is_PID = True 

39 

40 # TODO: remove this 

41 self.dom = self.domain 

42 

43 def new(self, element): 

44 return self.ring.ring_new(element) 

45 

46 @property 

47 def zero(self): 

48 return self.ring.zero 

49 

50 @property 

51 def one(self): 

52 return self.ring.one 

53 

54 @property 

55 def order(self): 

56 return self.ring.order 

57 

58 def __str__(self): 

59 return str(self.domain) + '[' + ','.join(map(str, self.symbols)) + ']' 

60 

61 def __hash__(self): 

62 return hash((self.__class__.__name__, self.dtype.ring, self.domain, self.symbols)) 

63 

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) 

69 

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)) 

76 

77 def canonical_unit(self, a): 

78 u = self.domain.canonical_unit(a.LC) 

79 return self.ring.ground_new(u) 

80 

81 def to_sympy(self, a): 

82 """Convert `a` to a SymPy object. """ 

83 return a.as_expr() 

84 

85 def from_sympy(self, a): 

86 """Convert SymPy's expression to `dtype`. """ 

87 return self.ring.from_expr(a) 

88 

89 def from_ZZ(K1, a, K0): 

90 """Convert a Python `int` object to `dtype`. """ 

91 return K1(K1.domain.convert(a, K0)) 

92 

93 def from_ZZ_python(K1, a, K0): 

94 """Convert a Python `int` object to `dtype`. """ 

95 return K1(K1.domain.convert(a, K0)) 

96 

97 def from_QQ(K1, a, K0): 

98 """Convert a Python `Fraction` object to `dtype`. """ 

99 return K1(K1.domain.convert(a, K0)) 

100 

101 def from_QQ_python(K1, a, K0): 

102 """Convert a Python `Fraction` object to `dtype`. """ 

103 return K1(K1.domain.convert(a, K0)) 

104 

105 def from_ZZ_gmpy(K1, a, K0): 

106 """Convert a GMPY `mpz` object to `dtype`. """ 

107 return K1(K1.domain.convert(a, K0)) 

108 

109 def from_QQ_gmpy(K1, a, K0): 

110 """Convert a GMPY `mpq` object to `dtype`. """ 

111 return K1(K1.domain.convert(a, K0)) 

112 

113 def from_GaussianIntegerRing(K1, a, K0): 

114 """Convert a `GaussianInteger` object to `dtype`. """ 

115 return K1(K1.domain.convert(a, K0)) 

116 

117 def from_GaussianRationalField(K1, a, K0): 

118 """Convert a `GaussianRational` object to `dtype`. """ 

119 return K1(K1.domain.convert(a, K0)) 

120 

121 def from_RealField(K1, a, K0): 

122 """Convert a mpmath `mpf` object to `dtype`. """ 

123 return K1(K1.domain.convert(a, K0)) 

124 

125 def from_ComplexField(K1, a, K0): 

126 """Convert a mpmath `mpf` object to `dtype`. """ 

127 return K1(K1.domain.convert(a, K0)) 

128 

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) 

135 

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 

142 

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]) 

147 

148 q, r = K0.numer(a).div(K0.denom(a)) 

149 

150 if r.is_zero: 

151 return K1.from_PolynomialRing(q, K0.field.ring.to_domain()) 

152 else: 

153 return None 

154 

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) 

164 

165 def get_field(self): 

166 """Returns a field associated with `self`. """ 

167 return self.ring.to_field().to_domain() 

168 

169 def is_positive(self, a): 

170 """Returns True if `LC(a)` is positive. """ 

171 return self.domain.is_positive(a.LC) 

172 

173 def is_negative(self, a): 

174 """Returns True if `LC(a)` is negative. """ 

175 return self.domain.is_negative(a.LC) 

176 

177 def is_nonpositive(self, a): 

178 """Returns True if `LC(a)` is non-positive. """ 

179 return self.domain.is_nonpositive(a.LC) 

180 

181 def is_nonnegative(self, a): 

182 """Returns True if `LC(a)` is non-negative. """ 

183 return self.domain.is_nonnegative(a.LC) 

184 

185 def gcdex(self, a, b): 

186 """Extended GCD of `a` and `b`. """ 

187 return a.gcdex(b) 

188 

189 def gcd(self, a, b): 

190 """Returns GCD of `a` and `b`. """ 

191 return a.gcd(b) 

192 

193 def lcm(self, a, b): 

194 """Returns LCM of `a` and `b`. """ 

195 return a.lcm(b) 

196 

197 def factorial(self, a): 

198 """Returns factorial of `a`. """ 

199 return self.dtype(self.domain.factorial(a))