-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpoly.py
161 lines (130 loc) · 4.59 KB
/
poly.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
from lib.type_enforcers import (
enforce_list_types,
enforce_type,
)
import polynomial_algorithms
def enforce_math_type(math):
assert hasattr(math, "add")
assert hasattr(math, "additive_inverse")
assert hasattr(math, "multiply")
assert hasattr(math, "one")
assert hasattr(math, "power")
assert hasattr(math, "type_string")
assert hasattr(math, "value_type")
assert hasattr(math, "zero")
assert callable(math.add)
assert callable(math.additive_inverse)
assert callable(math.multiply)
assert callable(math.power)
enforce_type(math.zero, math.value_type)
enforce_type(math.one, math.value_type)
enforce_type(math.type_string, str)
class SingleVarPoly:
def __init__(self, math, lst, var_name):
enforce_math_type(math)
enforce_list_types(lst, math.value_type)
if len(lst) > 1 and var_name is not None:
enforce_type(var_name, str)
self.lst = lst
self.math = math
self.var_name = var_name
assert hasattr(math, "type_string")
enforce_type(math.type_string, str)
self.type_string = f"SingleVarPoly.{math.type_string}"
self.simplify()
def __add__(self, other):
self.enforce_partner_type(other)
return self.add_with(other)
def __eq__(self, other):
self.enforce_partner_type(other)
return self.lst == other.lst
def __mul__(self, other):
self.enforce_partner_type(other)
return self.multiply_with(other)
def __neg__(self):
return self.additive_inverse()
def __pow__(self, exponent):
return self.raised_to_exponent(exponent)
def __str__(self):
return self.polynomial_string()
def additive_inverse(self):
lst = self.lst
additive_inverse = self.math.additive_inverse
return self.new([additive_inverse(elem) for elem in lst])
def add_with(self, other):
if other.is_zero():
return self
zero = self.math.zero
lst1 = self.lst
lst2 = other.lst
add = self.math.add
lst = polynomial_algorithms.add(lst1, lst2, add=add, zero=zero)
var_name = self.var_name or other.var_name
return SingleVarPoly(self.math, lst, var_name)
def enforce_partner_type(self, other):
assert type(other) == SingleVarPoly
assert type(other.math) == type(self.math)
assert type(self) == type(other)
if self.var_name is not None and other.var_name is not None:
assert self.var_name == other.var_name
def eval(self, x):
add = self.math.add
mul = self.math.multiply
power = self.math.power
zero = self.math.zero
lst = self.lst
return polynomial_algorithms.eval(
lst, x=x, zero=zero, add=add, mul=mul, power=power
)
def is_one(self):
return len(self.lst) == 1 and self.lst[0] == self.math.one
def is_zero(self):
return len(self.lst) == 0
def multiply_with(self, other):
if other.is_zero():
return other
if other.is_one():
return self
zero = self.math.zero
add = self.math.add
mul = self.math.multiply
lst1 = self.lst
lst2 = other.lst
lst = polynomial_algorithms.multiply(lst1, lst2, add=add, mul=mul, zero=zero)
var_name = self.var_name or other.var_name
return SingleVarPoly(self.math, lst, var_name)
def new(self, lst):
return SingleVarPoly(self.math, lst, self.var_name)
def one(self):
return self.new([self.math.one])
def polynomial_string(self):
var_name = self.var_name
zero = self.math.zero
one = self.math.one
lst = self.lst
return polynomial_algorithms.stringify(
lst, var_name=var_name, zero=zero, one=one
)
def raised_to_exponent(self, exponent):
enforce_type(exponent, int)
if exponent < 0:
raise ValueError("we do not support negative exponents")
if exponent == 0:
return self.one()
if exponent == 1:
return self
return self * self.raised_to_exponent(exponent - 1)
def simplify(self):
lst = self.lst
zero = self.math.zero
while lst and lst[-1] == zero:
lst = lst[:-1]
self.lst = lst
@staticmethod
def constant(math, c):
enforce_type(c, math.value_type)
return SingleVarPoly(math, [c], None)
@staticmethod
def degree_one_var(math, var_name):
enforce_type(var_name, str)
return SingleVarPoly(math, [math.zero, math.one], var_name)