2 Multivariate polynomial extenders. 5 from __future__
import division
15 _MIXIN_MSG =
"%s is mix-in" 20 OrderProvider provides order and related operations. 24 Do not instantiate OrderProvider. 25 This initializer should be called from descendant: 26 OrderProvider.__init__(self, order) 28 if type(self)
is OrderProvider:
29 raise NotImplementedError(_MIXIN_MSG % self.__class__.__name__)
35 Provide nest/unnest pair to convert a multivar polynomial to a 36 univar polynomial of polynomial coefficient and opposite 41 Return the position of the leading variable (the leading term 42 among all total degree one terms). 44 The leading term varies with term orders, so does the result. 45 The term order can be specified via the attribute 'order'. 47 if hasattr(self,
'order'):
52 if order.cmp(pivot, vindex) < 0:
53 pivot, pvar = vindex, var
58 def nest(self, outer, coeffring):
60 Nest the polynomial by extracting outer variable at the given 65 itercoeff =
lambda coeff: [(i[0], c)
for (i, c)
in coeff]
66 poly = uniutil.polynomial
67 polyring = poly_ring.PolynomialRing.getInstance(coeffring)
69 itercoeff =
lambda coeff: coeff
73 raise TypeError(
"number of variable is not multiple")
74 for index, coeff
in self.combine_similar_terms(outer):
75 combined[index] = poly(itercoeff(coeff), coeffring=coeffring)
76 return uniutil.polynomial(combined, coeffring=polyring)
78 def unnest(self, q, outer, coeffring):
80 Unnest the nested polynomial q by inserting outer variable at 85 for inner_d, inner_c
in cpoly:
86 if isinstance(inner_d, (int, long)):
89 inner_d = list(inner_d)
90 inner_d.insert(outer, d)
91 q_coeff[tuple(inner_d)] = inner_c
92 return self.__class__(q_coeff, coeffring=coeffring)
97 Provides interfaces for ring.CommutativeRingElement. 101 Do not instantiate RingElementProvider. 102 This initializer should be called from descendant: 103 RingElementProvider.__init__(self) 105 if type(self)
is RingElementProvider:
106 raise NotImplementedError(_MIXIN_MSG % self.__class__.__name__)
107 ring.CommutativeRingElement.__init__(self)
113 Return an object of a subclass of Ring, to which the element 118 for c
in self.itercoefficients():
119 cring = ring.getRing(c)
120 if not myring
or myring != cring
and myring.issubring(cring):
122 elif not cring.issubring(myring):
123 myring = myring.getCommonSuperring(cring)
125 myring = rational.theIntegerRing
131 Return the coefficient ring. 143 PseudoDivisionProvider provides pseudo divisions for multivariate 144 polynomials. It is assumed that the coefficient ring of the 145 polynomials is a domain. 147 The class should be used with NestProvider, RingElementProvider. 151 self.pseudo_divmod(other) -> (Q, R) 153 Q, R are polynomials such that 154 d**(deg(self) - deg(other) + 1) * self == other * Q + R, 155 w.r.t. a fixed variable, where d is the leading coefficient of 158 The leading coefficient varies with term orders, so does the 159 result. The term order can be specified via the attribute 162 var = self.leading_variable()
163 coeffring = self.getCoefficientRing()
165 s = self.nest(var, coeffring)
166 o = other.nest(var, coeffring)
167 q, r = s.pseudo_divmod(o)
168 qpoly = self.unnest(q, var, coeffring)
169 rpoly = self.unnest(r, var, coeffring)
174 self.pseudo_floordiv(other) -> Q 176 Q is a polynomial such that 177 d**(deg(self) - deg(other) + 1) * self == other * Q + R, 178 where d is the leading coefficient of other and R is a 181 The leading coefficient varies with term orders, so does the 182 result. The term order can be specified via the attribute 185 var = self.leading_variable()
186 coeffring = self.getCoefficientRing()
188 s = self.nest(var, coeffring)
189 o = other.nest(var, coeffring)
190 q = s.pseudo_floordiv(o)
191 return self.unnest(q, var, coeffring)
195 self.pseudo_mod(other) -> R 197 R is a polynomial such that 198 d**(deg(self) - deg(other) + 1) * self == other * Q + R, 199 where d is the leading coefficient of other and Q a 202 The leading coefficient varies with term orders, so does the 203 result. The term order can be specified via the attribute 206 var = self.leading_variable()
207 coeffring = self.getCoefficientRing()
209 s = self.nest(var, coeffring)
210 o = other.nest(var, coeffring)
212 return self.unnest(r, var, coeffring)
218 The result is a rational function. 224 Return quotient of exact division. 226 coeffring = self.getCoefficientRing()
227 if other
in coeffring:
232 if keep_ring
and ratio
not in coeffring:
234 new_coeffring = ratio.getRing()
235 new_coeffs.append((i, ratio))
237 return self.__class__(new_coeffs, coeffring=coeffring)
239 return self.__class__(new_coeffs, coeffring=new_coeffring)
241 var = self.leading_variable()
242 coeffring = self.getCoefficientRing()
243 s = self.nest(var, coeffring)
244 o = other.nest(var, coeffring)
245 q = s.exact_division(o)
246 return self.unnest(q, var, coeffring)
251 Provides greatest common divisor for multivariate polynomial. 253 The class should be used with NestProvider, RingElementProvider. 258 The nested polynomials' gcd is used. 260 var = self.leading_variable()
261 coeffring = self.getCoefficientRing()
262 s = self.nest(var, coeffring)
263 o = other.nest(var, coeffring)
264 if hasattr(s,
"gcd"):
266 elif hasattr(s,
"subresultant_gcd"):
267 g = s.subresultant_gcd(o)
269 raise TypeError(
"no gcd method available")
270 return self.unnest(g, var, coeffring)
276 RingElementProvider):
278 General polynomial with commutative ring coefficients. 282 Initialize the polynomial. 285 - coefficients: initializer for polynomial coefficients 287 Keyword arguments should include: 289 - number_of_variables: the number of variables 291 if "number_of_variables" not in kwds:
292 coefficients = dict(coefficients)
293 for i
in coefficients.iterkeys():
294 kwds[
"number_of_variables"] = len(i)
296 multivar.BasicPolynomial.__init__(self, coefficients, **kwds)
297 NestProvider.__init__(self)
298 PseudoDivisionProvider.__init__(self)
299 RingElementProvider.__init__(self)
301 if "coeffring" in kwds:
302 coeffring = kwds[
"coeffring"]
304 coeffring = uniutil.init_coefficient_ring(self.
_coefficients)
305 if coeffring
is not None:
308 raise TypeError(
"argument `coeffring' is required")
310 order = kwds[
"order"]
312 order = termorder.lexicographic_order
313 OrderProvider.__init__(self, order)
317 Return an object of a subclass of Ring, to which the element 325 Return an object of a subclass of Ring, to which the all 332 return "%s(%s)" % (self.__class__.__name__, self.
_coefficients)
336 return multivar.BasicPolynomial.__add__(self, other)
337 except (AttributeError, TypeError):
340 return multivar.BasicPolynomial.__add__(self, other * one)
342 return NotImplemented
347 return other * one + self
349 return NotImplemented
353 return multivar.BasicPolynomial.__sub__(self, other)
354 except (AttributeError, TypeError):
357 return multivar.BasicPolynomial.__sub__(self, other * one)
359 return NotImplemented
364 return other * one - self
366 return NotImplemented
372 Polynomial with domain coefficients. 376 Initialize the polynomial. 378 - coefficients: initializer for polynomial coefficients 381 RingPolynomial.__init__(self, coefficients, **kwds)
383 raise TypeError(
"coefficient ring has to be a domain")
384 PseudoDivisionProvider.__init__(self)
390 Polynomial with unique factorization domain coefficients. 394 Initialize the polynomial. 396 - coefficients: initializer for polynomial coefficients 397 - coeffring: unique factorization domain 399 DomainPolynomial.__init__(self, coefficients, **kwds)
401 raise TypeError(
"coefficient ring has to be a UFD")
402 GcdProvider.__init__(self)
406 Return resultant of two polynomials of the same ring, with 407 respect to the variable specified by its position var. 410 return self.
nest(var, cring).
resultant(other.nest(var, cring))
415 The class of multivariate polynomial ring. 416 There's no need to specify the variable names. 421 def __init__(self, coeffring, number_of_variables):
423 raise TypeError(
"%s should not be passed as ring" % coeffring.__class__)
424 ring.CommutativeRing.__init__(self)
436 Return the coefficient ring. 442 getQuotientField returns the quotient field of the ring 443 if coefficient ring has its quotient field. Otherwise, 444 an exception will be raised. 448 return ratfunc.RationalFunctionField(coefficientField, variables)
453 if (isinstance(other, PolynomialRingAnonymousVariables)
and 461 Return 'PolynomialRingAnonymousVariables(Ring, #vars)' 479 `in' operator is provided for checking the element be in the 484 elem_ring = ring.getRing(element)
485 if elem_ring
is not None and elem_ring.issubring(self):
491 reports whether another ring contains this polynomial ring. 493 if isinstance(other, poly_ring.PolynomialRing):
497 elif isinstance(other, poly_ring.RationalFunctionField):
502 return other.issuperring(self)
509 reports whether this polynomial ring contains another ring. 513 if isinstance(other, poly_ring.PolynomialRing):
517 return other.issubring(self)
524 Return common superring of two rings. 528 elif other.issuperring(self):
530 elif (
not isinstance(other, PolynomialRingAnonymousVariables)
and 534 if hasattr(other,
"getCommonSuperring"):
535 return other.getCommonSuperring(self)
539 raise TypeError(
"no common super ring")
543 Return an element of the polynomial ring made from seed 544 overriding ring.createElement. 551 raise NotImplementedError(
"unclear which type of polynomial be chosen")
555 if self.
_one is None:
559 one = property(_getOne,
None,
None,
"multiplicative unit")
563 if self.
_zero is None:
567 zero = property(_getZero,
None,
None,
"additive unit")
571 Return the greatest common divisor of given polynomials. 572 The polynomials must be in the polynomial ring. 573 If the coefficient ring is a field, the result is monic. 575 if hasattr(a,
"gcd"):
577 elif hasattr(a,
"subresultant_gcd"):
578 return a.subresultant_gcd(b)
579 raise NotImplementedError(
"no gcd")
583 Return the tuple (u, v, d): d is the greatest common divisor 584 of given polynomials, and they satisfy d = u*a + v*b. The 585 polynomials must be in the polynomial ring. If the 586 coefficient ring is a field, the result is monic. 588 if hasattr(a,
"extgcd"):
590 raise NotImplementedError(
"no extgcd")
595 Return an instance of the class with specified coefficient ring 596 and number of variables. 598 if (coeffring, number_of_variables)
not in cls.
_instances:
599 cls.
_instances[coeffring, number_of_variables] = cls(coeffring, number_of_variables)
600 return cls.
_instances[coeffring, number_of_variables]
605 Multivariate polynomial ideal. 609 Initialize a polynomial ideal. 611 ring.Ideal.__init__(self, generators, aring)
615 Return whether elem is in the ideal or not. 617 if not elem.getRing().issubring(self.
ring):
620 return elem == self.
ring.zero
621 return not self.
reduce(elem)
625 Report whether the ideal is zero ideal or not. Of course, 626 False is for zero ideal. 634 return "%s(%r, %r)" % (self.__class__.__name__, self.
generators, self.
ring)
640 return "(%s)%s" % (
", ".join([str(g)
for g
in self.
generators]), self.
ring)
645 special_ring_table = {}
647 def polynomial(coefficients, coeffring, number_of_variables=None):
650 - coefficients has to be a initializer for dict, whose keys are 651 variable indices and values are coefficients at the indices. 652 - coeffring has to be an object inheriting ring.Ring. 653 - number_of_variables has to be the number of variables. 655 One can override the way to choose a polynomial type from a 656 coefficient ring, by setting: 657 special_ring_table[coeffring_type] = polynomial_type 658 before the function call. 660 if type(coeffring)
in special_ring_table:
661 poly_type = special_ring_table[type(coeffring)]
662 elif coeffring.isufd():
663 poly_type = UniqueFactorizationDomainPolynomial
664 elif coeffring.isdomain():
665 poly_type = DomainPolynomial
668 if number_of_variables
is None:
669 coefficients = dict(coefficients)
670 for k
in coefficients:
671 number_of_variables = len(k)
673 return poly_type(coefficients, coeffring=coeffring, number_of_variables=number_of_variables)
677 MultiVariableSparsePolynomial(coefficient, variable [,coeffring]) 679 - coefficient has to be a dictionary of form {(i1,...,ik): c} 680 - variable has to be a list of character strings. 681 - coeffring has to be, if specified, an object inheriting ring.Ring. 683 This function is provided for backward compatible way of defining 684 multivariate polynomial. The variable names are ignored, but 685 their number is used. 687 if not isinstance(variable, list)
or not isinstance(coefficient, dict):
688 raise ValueError(
"You must input MultiVariableSparsePolynomial(dict, list) but (%s, %s)." % (coefficient.__class__, variable.__class__))
689 if coeffring
is None:
690 coeffring = uniutil.init_coefficient_ring(coefficient)
691 return polynomial(coefficient, coeffring=coeffring, number_of_variables=len(variable))
695 From space separated names of indeterminates, prepare variables 696 representing the indeterminates. The result will be stored in ctx 699 The variables should be prepared at once, otherwise wrong aliases 700 of variables may confuse you in later calculation. 702 If an optional coeffring is not given, indeterminates will be 703 initialized as integer coefficient polynomials. 706 >>> prepare_indeterminates("X Y Z", globals()) 708 UniqueFactorizationDomainPolynomial({(0, 1, 0): 1}) 711 split_names = names.split()
712 number_of_variables = len(split_names)
713 if coeffring
is None:
714 coeffring = uniutil.init_coefficient_ring({1:1})
715 for i, name
in enumerate(split_names):
716 e_i = tuple([0] * i + [1] + [0] * (number_of_variables - i - 1))
717 ctx[name] =
polynomial({e_i: 1}, coeffring, number_of_variables)