| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- try:
- from itertools import zip_longest
- except ImportError:
- from itertools import izip_longest as zip_longest
- import fractions
- from .numbertype import *
- # strip all copies of elt from the end of the list
- def strip(L, elt):
- if len(L) == 0: return L
- i = len(L) - 1
- while i >= 0 and L[i] == elt:
- i -= 1
- return L[:i+1]
- # create a polynomial with coefficients in a field; coefficients are in
- # increasing order of monomial degree so that, for example, [1,2,3]
- # corresponds to 1 + 2x + 3x^2
- @memoize
- def polynomialsOver(field=fractions.Fraction):
- class Polynomial(DomainElement):
- operatorPrecedence = 2
- @classmethod
- def factory(cls, L):
- return Polynomial([cls.field(x) for x in L])
- def __init__(self, c):
- if type(c) is Polynomial:
- self.coefficients = c.coefficients
- elif isinstance(c, field):
- self.coefficients = [c]
- elif not hasattr(c, '__iter__') and not hasattr(c, 'iter'):
- self.coefficients = [field(c)]
- else:
- self.coefficients = c
- self.coefficients = strip(self.coefficients, field(0))
- def isZero(self): return self.coefficients == []
- def __repr__(self):
- if self.isZero():
- return '0'
- return ' + '.join(['%s x^%d' % (a,i) if i > 0 else '%s'%a
- for i,a in enumerate(self.coefficients)])
- def __abs__(self): return len(self.coefficients) # the valuation only gives 0 to the zero polynomial, i.e. 1+degree
- def __len__(self): return len(self.coefficients)
- def __sub__(self, other): return self + (-other)
- def __iter__(self): return iter(self.coefficients)
- def __neg__(self): return Polynomial([-a for a in self])
- def iter(self): return self.__iter__()
- def leadingCoefficient(self): return self.coefficients[-1]
- def degree(self): return abs(self) - 1
- @typecheck
- def __eq__(self, other):
- return self.degree() == other.degree() and all([x==y for (x,y) in zip(self, other)])
- @typecheck
- def __ne__(self, other):
- return self.degree() != other.degree() or any([x!=y for (x,y) in zip(self, other)])
- @typecheck
- def __add__(self, other):
- newCoefficients = [sum(x) for x in zip_longest(self, other, fillvalue=self.field(0))]
- return Polynomial(newCoefficients)
- @typecheck
- def __mul__(self, other):
- if self.isZero() or other.isZero():
- return Zero()
- newCoeffs = [self.field(0) for _ in range(len(self) + len(other) - 1)]
- for i,a in enumerate(self):
- for j,b in enumerate(other):
- newCoeffs[i+j] += a*b
- return Polynomial(newCoeffs)
- @typecheck
- def __divmod__(self, divisor):
- quotient, remainder = Zero(), self
- divisorDeg = divisor.degree()
- divisorLC = divisor.leadingCoefficient()
- while remainder.degree() >= divisorDeg:
- monomialExponent = remainder.degree() - divisorDeg
- monomialZeros = [self.field(0) for _ in range(monomialExponent)]
- monomialDivisor = Polynomial(monomialZeros + [remainder.leadingCoefficient() / divisorLC])
- quotient += monomialDivisor
- remainder -= monomialDivisor * divisor
- return quotient, remainder
- @typecheck
- def __truediv__(self, divisor):
- if divisor.isZero():
- raise ZeroDivisionError
- return divmod(self, divisor)[0]
- @typecheck
- def __mod__(self, divisor):
- if divisor.isZero():
- raise ZeroDivisionError
- return divmod(self, divisor)[1]
- def __call__(self, x):
- if type(x) is int:
- x = self.field(x)
- assert type(x) is self.field
- if self.isZero():
- return self.field(0)
- y = self.leadingCoefficient()
- for coeff in self.coefficients[-2::-1]:
- y = y * x + coeff
- return y
- def Zero():
- return Polynomial([])
- Polynomial.field = field
- Polynomial.__name__ = '(%s)[x]' % field.__name__
- Polynomial.englishName = 'Polynomials in one variable over %s' % field.__name__
- return Polynomial
|