Coverage for src\pqlattice\polynomial\_poly.py: 76%
59 statements
« prev ^ index » next coverage.py v7.11.0, created at 2026-01-10 12:32 +0100
« prev ^ index » next coverage.py v7.11.0, created at 2026-01-10 12:32 +0100
1import numpy as np
2from numpy.typing import ArrayLike
4from .._utils import as_integer
5from ..typing import Vector, validate_aliases
8@validate_aliases
9def make_poly(data: ArrayLike) -> Vector:
10 """_summary_
12 Parameters
13 ----------
14 data : Iterable[int | float]
15 _description_
17 Returns
18 -------
19 Vector
20 _description_
22 Raises
23 ------
24 ValueError
25 _description_
26 """
27 arr = as_integer(data)
29 if arr.ndim != 1:
30 raise ValueError(f"Expected 1D iterable, got {arr.ndim}D")
32 return arr
35@validate_aliases
36def is_zero_poly(p: Vector) -> bool:
37 """_summary_
39 Parameters
40 ----------
41 p : Vector
42 _description_
44 Returns
45 -------
46 bool
47 _description_
49 Raises
50 ------
51 ValueError
52 _description_
53 """
54 if len(p) == 0:
55 raise ValueError("Empty coefficient array is not a proper polynomial")
57 return np.count_nonzero(p) == 0
60@validate_aliases
61def deg(p: Vector) -> int:
62 """_summary_
64 Parameters
65 ----------
66 p : Vector
67 _description_
69 Returns
70 -------
71 int
72 _description_
74 Raises
75 ------
76 ValueError
77 _description_
78 """
79 if len(p) == 0:
80 raise ValueError("Empty coefficient array is not a proper polynomial")
81 nonzeros = np.nonzero(p)[0]
82 if len(nonzeros) == 0:
83 return -1
84 # raise ValueError("Degree of zero polynomial is undefined")
85 else:
86 return nonzeros[-1]
89@validate_aliases
90def pad(p: Vector, max_deg: int) -> Vector:
91 """_summary_
93 Parameters
94 ----------
95 p : Vector
96 _description_
97 max_deg : int
98 _description_
100 Returns
101 -------
102 Vector
103 _description_
105 Raises
106 ------
107 ValueError
108 _description_
109 """
110 if is_zero_poly(p):
111 return zero_poly(max_deg)
113 d = deg(p)
114 if max_deg < d:
115 raise ValueError("max_deg has to be greater or equal to the degree of a given polynomial p")
117 return as_integer(np.pad(trim(p), (0, max_deg - d)))
120@validate_aliases
121def trim(p: Vector) -> Vector:
122 """_summary_
124 Parameters
125 ----------
126 p : Vector
127 _description_
129 Returns
130 -------
131 Vector
132 _description_
133 """
134 if is_zero_poly(p):
135 return as_integer([0])
137 return p[: deg(p) + 1].copy()
140@validate_aliases
141def add(p: Vector, q: Vector) -> Vector:
142 """_summary_
144 Parameters
145 ----------
146 p : Vector
147 _description_
148 q : Vector
149 _description_
151 Returns
152 -------
153 Vector
154 _description_
155 """
156 max_deg = max(deg(p), deg(q), 0)
157 return trim(pad(p, max_deg) + pad(q, max_deg))
160@validate_aliases
161def sub(p: Vector, q: Vector) -> Vector:
162 """_summary_
164 Parameters
165 ----------
166 p : Vector
167 _description_
168 q : Vector
169 _description_
171 Returns
172 -------
173 Vector
174 _description_
175 """
176 max_deg = max(deg(p), deg(q), 0)
177 return trim(pad(p, max_deg) - pad(q, max_deg))
180@validate_aliases
181def mul(p: Vector, q: Vector) -> Vector:
182 """_summary_
184 Parameters
185 ----------
186 p : Vector
187 _description_
188 q : Vector
189 _description_
191 Returns
192 -------
193 Vector
194 _description_
195 """
196 return trim(np.polymul(p[::-1], q[::-1])[::-1])
199@validate_aliases
200def monomial(coeff: int, degree: int) -> Vector:
201 """_summary_
203 Parameters
204 ----------
205 coeff : int
206 _description_
207 degree : int
208 _description_
210 Returns
211 -------
212 Vector
213 _description_
215 Raises
216 ------
217 ValueError
218 _description_
219 """
220 if degree < 0:
221 raise ValueError("degree has to be non negative")
223 p = as_integer([0] * (degree + 1))
224 p[degree] = coeff
225 return p
228@validate_aliases
229def zero_poly(max_deg: int = 0) -> Vector:
230 """_summary_
232 Parameters
233 ----------
234 max_deg : int, optional
235 _description_, by default 0
237 Returns
238 -------
239 Vector
240 _description_
242 Raises
243 ------
244 ValueError
245 _description_
246 """
247 if max_deg < 0:
248 raise ValueError("degree has to be non negative")
250 return as_integer([0] * (max_deg + 1))