2017-05-14 18:09:52 +02:00
|
|
|
# Polynomial class on Z or Z_p
|
2017-05-14 17:03:14 +02:00
|
|
|
|
|
|
|
from collections import defaultdict
|
|
|
|
|
|
|
|
class Poly:
|
|
|
|
'Polynomial class.'
|
|
|
|
def __init__(self, coeffs = None):
|
2017-05-14 19:12:37 +02:00
|
|
|
self.coeffs = defaultdict(int, isinstance(coeffs, int) and {0:coeffs} or coeffs or {})
|
|
|
|
self.deg = int(len(self.coeffs) and max(self.coeffs.keys()))
|
2017-05-14 18:09:52 +02:00
|
|
|
|
2017-05-14 18:45:18 +02:00
|
|
|
def __call__(self, val):
|
|
|
|
'Evaluate polynomial for a given value.'
|
|
|
|
res = 0
|
|
|
|
for i in xrange(self.deg, -1, -1):
|
|
|
|
res = res * val + self.coeffs[i]
|
|
|
|
return res
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
def term(coeff, expt):
|
2017-05-14 19:12:37 +02:00
|
|
|
if coeff == 1 and expt == 0:
|
|
|
|
return '1'
|
2017-05-15 10:26:12 +02:00
|
|
|
return ' * '.join(([] if coeff == 1 else [str(coeff)]) + \
|
|
|
|
([] if expt == 0 else ['X'] if expt == 1 else ['X ** %d' % expt]))
|
2017-05-14 18:45:18 +02:00
|
|
|
|
|
|
|
return ' + '.join(term(self.coeffs[i], i) for i in self.coeffs if self.coeffs[i] != 0)
|
2017-05-14 19:12:37 +02:00
|
|
|
def __repr__(self):
|
|
|
|
return str(self)
|
2017-05-14 18:45:18 +02:00
|
|
|
|
2017-05-14 18:09:52 +02:00
|
|
|
# arithmetic
|
2017-05-15 10:14:40 +02:00
|
|
|
def __neg__(self):
|
|
|
|
return Poly({(i, -self.coeffs[i]) for i in self.coeffs})
|
2017-05-14 18:09:52 +02:00
|
|
|
def __add__(self, other):
|
|
|
|
if not isinstance(other, Poly):
|
|
|
|
other = Poly(other)
|
|
|
|
res = Poly()
|
|
|
|
res.deg = max(self.deg, other.deg)
|
|
|
|
for i in xrange(res.deg+1):
|
|
|
|
res.coeffs[i] = self.coeffs[i] + other.coeffs[i]
|
|
|
|
return res
|
|
|
|
def __radd__(self, other):
|
|
|
|
if not isinstance(other, Poly):
|
|
|
|
other = Poly(other)
|
|
|
|
return other.__add__(self)
|
|
|
|
def __sub__(self, other):
|
|
|
|
if not isinstance(other, Poly):
|
|
|
|
other = Poly(other)
|
2017-05-15 10:14:40 +02:00
|
|
|
return self.__add__(other.__neg__())
|
2017-05-14 18:09:52 +02:00
|
|
|
def __rsub__(self, other):
|
|
|
|
if not isinstance(other, Poly):
|
|
|
|
other = Poly(other)
|
2017-05-15 10:14:40 +02:00
|
|
|
return other.__add__(self.__neg__())
|
2017-05-14 18:09:52 +02:00
|
|
|
|
|
|
|
def __mul__(self, other):
|
|
|
|
if not isinstance(other, Poly):
|
|
|
|
other = Poly(other)
|
|
|
|
res = Poly()
|
2017-05-14 18:45:18 +02:00
|
|
|
res.deg = self.deg + other.deg # consider case where other is 0
|
2017-05-14 18:09:52 +02:00
|
|
|
for i in xrange(res.deg+1):
|
|
|
|
for j in xrange(i+1):
|
|
|
|
res.coeffs[i] += self.coeffs[j] * other.coeffs[i - j]
|
|
|
|
return res
|
|
|
|
def __rmul__(self, other):
|
|
|
|
if not isinstance(other, Poly):
|
|
|
|
other = Poly(other)
|
|
|
|
return other.__mul__(self)
|
2017-05-14 19:12:37 +02:00
|
|
|
|
|
|
|
def __pow__(self, other):
|
|
|
|
if not isinstance(other, int) or other < 0:
|
|
|
|
raise ValueError("Exponent %d is not a natural number" % other)
|
|
|
|
res = Poly(1)
|
|
|
|
while other:
|
|
|
|
res *= self
|
|
|
|
other -= 1
|
|
|
|
return res
|
2017-05-14 17:03:14 +02:00
|
|
|
|
2017-05-14 18:45:18 +02:00
|
|
|
X = Poly({1:1})
|
|
|
|
|
|
|
|
def derivative(p):
|
|
|
|
'Return derivative of polynomial.'
|
|
|
|
return Poly({(i - 1, i * p.coeffs[i]) for i in p.coeffs if i != 0})
|