-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpolygen.py
More file actions
77 lines (68 loc) · 3.03 KB
/
Copy pathpolygen.py
File metadata and controls
77 lines (68 loc) · 3.03 KB
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
import numpy as np
from numpy.polynomial import Polynomial
from dist import Dist, ConstDist
class Poly:
def __init__(self, degree, dist):
self.degree = degree
if isinstance(dist, list):
if len(dist) != degree + 1:
raise ValueError("If a list of distributions is given, it must have length degree+1")
self.dists = dist
elif isinstance(dist, Dist):
self.dists = [dist] * (degree + 1)
else:
raise ValueError("dist must be a Dist instance or list of Dist instances")
def sample_coeffs(self):
"""Return an array of sampled coefficients (real or complex)."""
coeffs = np.array([d.sample()[0] for d in self.dists])
if np.iscomplexobj(coeffs):
coeffs = coeffs.astype(np.complex128)
else:
coeffs = coeffs.astype(np.float64)
return coeffs
def sample(self):
"""Sample a random polynomial with coefficients from the specified distributions."""
coeffs = self.sample_coeffs()
return Polynomial(coeffs)
def __add__(self, other):
if not isinstance(other, Poly):
raise TypeError("Polynomial addition only supported between Poly objects.")
deg = max(self.degree, other.degree)
new_dists = []
for i in range(deg + 1):
a = self.dists[i] if i <= self.degree else ConstDist(0)
b = other.dists[i] if i <= other.degree else ConstDist(0)
new_dists.append(a + b)
return Poly(deg, new_dists)
def __sub__(self, other):
if not isinstance(other, Poly):
raise TypeError("Polynomial subtraction only supported between Poly objects.")
deg = max(self.degree, other.degree)
new_dists = []
for i in range(deg + 1):
a = self.dists[i] if i <= self.degree else ConstDist(0)
b = other.dists[i] if i <= other.degree else ConstDist(0)
new_dists.append(a - b)
return Poly(deg, new_dists)
def __mul__(self, other):
if not isinstance(other, Poly):
raise TypeError("Polynomial multiplication only supported between Poly objects.")
deg = self.degree + other.degree
new_dists = [ConstDist(0)] * (deg + 1)
for i in range(self.degree + 1):
for j in range(other.degree + 1):
new_dists[i + j] = new_dists[i + j] + (self.dists[i] * other.dists[j])
return Poly(deg, new_dists)
def compose(self, other):
"""Composition P(Q(x)) as a random polynomial."""
if not isinstance(other, Poly):
raise TypeError("Polynomial composition only supported between Poly objects.")
# Initialize as zero polynomial
result = Poly(0, ConstDist(0))
base = Poly(0, ConstDist(1)) # Q(x)^0
for coeff in self.dists:
result = result + (Poly(other.degree * base.degree, [coeff]) * base)
base = base * other
return result
def __repr__(self):
return f"Poly(degree={self.degree}, dists={self.dists})"