polynomial.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. try:
  2. from itertools import zip_longest
  3. except ImportError:
  4. from itertools import izip_longest as zip_longest
  5. import fractions
  6. from .numbertype import *
  7. # strip all copies of elt from the end of the list
  8. def strip(L, elt):
  9. if len(L) == 0: return L
  10. i = len(L) - 1
  11. while i >= 0 and L[i] == elt:
  12. i -= 1
  13. return L[:i+1]
  14. # create a polynomial with coefficients in a field; coefficients are in
  15. # increasing order of monomial degree so that, for example, [1,2,3]
  16. # corresponds to 1 + 2x + 3x^2
  17. @memoize
  18. def polynomialsOver(field=fractions.Fraction):
  19. class Polynomial(DomainElement):
  20. operatorPrecedence = 2
  21. @classmethod
  22. def factory(cls, L):
  23. return Polynomial([cls.field(x) for x in L])
  24. def __init__(self, c):
  25. if type(c) is Polynomial:
  26. self.coefficients = c.coefficients
  27. elif isinstance(c, field):
  28. self.coefficients = [c]
  29. elif not hasattr(c, '__iter__') and not hasattr(c, 'iter'):
  30. self.coefficients = [field(c)]
  31. else:
  32. self.coefficients = c
  33. self.coefficients = strip(self.coefficients, field(0))
  34. def isZero(self): return self.coefficients == []
  35. def __repr__(self):
  36. if self.isZero():
  37. return '0'
  38. return ' + '.join(['%s x^%d' % (a,i) if i > 0 else '%s'%a
  39. for i,a in enumerate(self.coefficients)])
  40. def __abs__(self): return len(self.coefficients) # the valuation only gives 0 to the zero polynomial, i.e. 1+degree
  41. def __len__(self): return len(self.coefficients)
  42. def __sub__(self, other): return self + (-other)
  43. def __iter__(self): return iter(self.coefficients)
  44. def __neg__(self): return Polynomial([-a for a in self])
  45. def iter(self): return self.__iter__()
  46. def leadingCoefficient(self): return self.coefficients[-1]
  47. def degree(self): return abs(self) - 1
  48. @typecheck
  49. def __eq__(self, other):
  50. return self.degree() == other.degree() and all([x==y for (x,y) in zip(self, other)])
  51. @typecheck
  52. def __ne__(self, other):
  53. return self.degree() != other.degree() or any([x!=y for (x,y) in zip(self, other)])
  54. @typecheck
  55. def __add__(self, other):
  56. newCoefficients = [sum(x) for x in zip_longest(self, other, fillvalue=self.field(0))]
  57. return Polynomial(newCoefficients)
  58. @typecheck
  59. def __mul__(self, other):
  60. if self.isZero() or other.isZero():
  61. return Zero()
  62. newCoeffs = [self.field(0) for _ in range(len(self) + len(other) - 1)]
  63. for i,a in enumerate(self):
  64. for j,b in enumerate(other):
  65. newCoeffs[i+j] += a*b
  66. return Polynomial(newCoeffs)
  67. @typecheck
  68. def __divmod__(self, divisor):
  69. quotient, remainder = Zero(), self
  70. divisorDeg = divisor.degree()
  71. divisorLC = divisor.leadingCoefficient()
  72. while remainder.degree() >= divisorDeg:
  73. monomialExponent = remainder.degree() - divisorDeg
  74. monomialZeros = [self.field(0) for _ in range(monomialExponent)]
  75. monomialDivisor = Polynomial(monomialZeros + [remainder.leadingCoefficient() / divisorLC])
  76. quotient += monomialDivisor
  77. remainder -= monomialDivisor * divisor
  78. return quotient, remainder
  79. @typecheck
  80. def __truediv__(self, divisor):
  81. if divisor.isZero():
  82. raise ZeroDivisionError
  83. return divmod(self, divisor)[0]
  84. @typecheck
  85. def __mod__(self, divisor):
  86. if divisor.isZero():
  87. raise ZeroDivisionError
  88. return divmod(self, divisor)[1]
  89. def __call__(self, x):
  90. if type(x) is int:
  91. x = self.field(x)
  92. assert type(x) is self.field
  93. if self.isZero():
  94. return self.field(0)
  95. y = self.leadingCoefficient()
  96. for coeff in self.coefficients[-2::-1]:
  97. y = y * x + coeff
  98. return y
  99. def Zero():
  100. return Polynomial([])
  101. Polynomial.field = field
  102. Polynomial.__name__ = '(%s)[x]' % field.__name__
  103. Polynomial.englishName = 'Polynomials in one variable over %s' % field.__name__
  104. return Polynomial