-
Notifications
You must be signed in to change notification settings - Fork 24
/
Copy pathpolynomial.py
116 lines (95 loc) · 3.79 KB
/
polynomial.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
class Polynomial(list):
'''
Polynomial class, essentially a list of coefficients with
a nice string representation, and correctly behaving addition,
multiplication, etc.
'''
def __init__(self, *coeffs):
from collections.abc import Sequence
if isinstance(coeffs[0], Sequence):
coeffs = coeffs[0]
list.__init__(self, coeffs)
self.degree = self.find_degree()
def find_degree(self):
'''
Find the degree of the polynomial.
This is not necessarily the length of the polynomial
as a list, since there may be redundant 0 terms at the end
'''
for i, coefficient in enumerate(self):
if coefficient != 0:
degree = i
return degree
def display_monomial(self, degree, coefficient):
'''
Correctly give a string representation of the given monomial
'''
if degree == 0:
return str(coefficient)
if degree == 1 and coefficient == 1:
return self.symbol
elif degree == 1 and coefficient != 1:
return "{}{}".format(coefficient, "x")
elif coefficient == 1:
return "{}^{}".format("x", degree)
else:
return "{}{}^{}".format(coefficient, "x", degree)
def __str__(self):
monos = [self.display_monomial(k, coeff) for k, coeff in enumerate(self) if coeff != 0]
return " + ".join(monos)
def __call__(self, point):
'''
Evaluates the polynomial at the specified input
'''
return sum([co*point**i for i, co in enumerate(self)])
def match_length(self, p):
'''
Adding polynomials requires them to be same length
This method returns the same polynomial with additional zeros added to the end
to match the length of the polynomial p
'''
added_zeros = [0 for i in range(len(p) - len(self))]
return Polynomial(list(self) + added_zeros)
def isnumber(self, p):
from numbers import Number
return isinstance(p, Number)
def __add__(self, p):
from numbers import Number
# First, if we add a number rather than another polynomial,
# we just return a polynomial whose constant (0th) term has
# p added
if self.isnumber(p):
return self + Polynomial(p)
polys = [self, p]
polys.sort(key=len)
matched_length = polys[0].match_length(polys[1])
return Polynomial([co[0] + co[1] for co in zip(polys[1], matched_length)])
def __neg__(self):
return Polynomial([-a for a in self])
def __sub__(self, p):
return self + (-p)
def same_sum_pairs(self, i, j):
'''
Generates tuples containing pairs of powers
having the same sum, upto required degree
'''
from itertools import product
for k in range(i + j - 1): # need to -1 here because polynomial degree = highest power =
yield (pair for pair in product(range(i), range(j)) if pair[0] + pair[1] == k)
def __mul__(self,p):
# Multiplication by a number just multiplies each
# term by the number
if self.isnumber(p):
return self * Polynomial(p)
deg1, deg2 = len(self), len(p)
terms = [[self[i]*p[j] for i, j in degree_pairs] # list comprehensions within list comprehensions
for degree_pairs in self.same_sum_pairs(deg1, deg2)] # never go deeper!
return Polynomial([sum(term) for term in terms])
def __radd__(self, p):
return self + p
def __rmul__(self, p):
return self * p
def derivative(self):
coefficients = [i*coef for i, coef in enumerate(self)]
return Polynomial(coefficients[1:])
D = lambda p: p.derivative()