1use num_traits::{One, Pow, Zero};
4use std::collections::BTreeMap;
5use std::fmt::Display;
6use std::iter::{Product, Sum};
7use std::ops::{Add, AddAssign, Mul, Neg};
8
9use derivative::Derivative;
10
11use super::rig::*;
12
13pub trait CommAlg: CommRing + Module<Ring = Self::R> {
15 type R: CommRing;
17
18 fn from_scalar(r: Self::R) -> Self {
24 Self::one() * r
25 }
26}
27
28#[derive(Clone, PartialEq, Eq, Derivative)]
41#[derivative(Default(bound = ""))]
42pub struct Polynomial<Var, Coef, Exp>(Combination<Monomial<Var, Exp>, Coef>);
43
44impl<Var, Coef, Exp> Polynomial<Var, Coef, Exp>
45where
46 Var: Ord,
47 Exp: Ord,
48{
49 pub fn generator(var: Var) -> Self
51 where
52 Coef: One,
53 Exp: One,
54 {
55 Polynomial::from_monomial(Monomial::generator(var))
56 }
57
58 pub fn from_monomial(m: Monomial<Var, Exp>) -> Self
60 where
61 Coef: One,
62 {
63 Polynomial(Combination::generator(m))
64 }
65
66 pub fn monomials(&self) -> impl ExactSizeIterator<Item = &Monomial<Var, Exp>> {
68 self.0.variables()
69 }
70
71 pub fn extend_scalars<NewCoef, F>(self, f: F) -> Polynomial<Var, NewCoef, Exp>
78 where
79 F: FnMut(Coef) -> NewCoef,
80 {
81 Polynomial(self.0.extend_scalars(f))
82 }
83
84 pub fn eval<A, F>(&self, f: F) -> A
86 where
87 A: Clone + Mul<Coef, Output = A> + Pow<Exp, Output = A> + Sum + Product,
88 F: Clone + FnMut(&Var) -> A,
89 Coef: Clone,
90 Exp: Clone,
91 {
92 self.0.eval_with_order(self.monomials().map(|m| m.eval(f.clone())))
93 }
94
95 pub fn eval_pairs<A>(&self, pairs: impl IntoIterator<Item = (Var, A)>) -> A
101 where
102 A: Clone + Mul<Coef, Output = A> + Pow<Exp, Output = A> + Sum + Product,
103 Coef: Clone,
104 Exp: Clone,
105 {
106 let map: BTreeMap<Var, A> = pairs.into_iter().collect();
107 self.eval(|var| map.get(var).cloned().unwrap())
108 }
109
110 pub fn map_variables<NewVar, F>(&self, mut f: F) -> Polynomial<NewVar, Coef, Exp>
119 where
120 Coef: Clone + Add<Output = Coef>,
121 Exp: Clone + Add<Output = Exp>,
122 NewVar: Clone + Ord,
123 F: FnMut(&Var) -> NewVar,
124 {
125 (&self.0)
126 .into_iter()
127 .map(|(coef, m)| (coef.clone(), m.map_variables(|var| f(var))))
128 .collect()
129 }
130
131 pub fn normalize(self) -> Self
138 where
139 Coef: Zero,
140 Exp: Zero,
141 {
142 self.0
143 .into_iter()
144 .filter_map(|(coef, m)| {
145 if coef.is_zero() {
146 None
147 } else {
148 Some((coef, m.normalize()))
149 }
150 })
151 .collect()
152 }
153}
154
155impl<Var, Coef, Exp> FromIterator<(Coef, Monomial<Var, Exp>)> for Polynomial<Var, Coef, Exp>
156where
157 Var: Ord,
158 Coef: Add<Output = Coef>,
159 Exp: Ord,
160{
161 fn from_iter<T: IntoIterator<Item = (Coef, Monomial<Var, Exp>)>>(iter: T) -> Self {
162 Polynomial(iter.into_iter().collect())
163 }
164}
165
166impl<Var, Coef, Exp> Display for Polynomial<Var, Coef, Exp>
167where
168 Var: Display,
169 Coef: Display + PartialEq + One,
170 Exp: Display + PartialEq + One,
171{
172 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
173 self.0.fmt(f)
174 }
175}
176
177impl<Var, Coef, Exp> AddAssign<(Coef, Monomial<Var, Exp>)> for Polynomial<Var, Coef, Exp>
181where
182 Var: Ord,
183 Coef: Add<Output = Coef>,
184 Exp: Ord,
185{
186 fn add_assign(&mut self, rhs: (Coef, Monomial<Var, Exp>)) {
187 self.0 += rhs;
188 }
189}
190
191impl<Var, Coef, Exp> Add for Polynomial<Var, Coef, Exp>
192where
193 Var: Ord,
194 Coef: Add<Output = Coef>,
195 Exp: Ord,
196{
197 type Output = Self;
198
199 fn add(self, rhs: Self) -> Self::Output {
200 Polynomial(self.0 + rhs.0)
201 }
202}
203
204impl<Var, Coef, Exp> Zero for Polynomial<Var, Coef, Exp>
205where
206 Var: Ord,
207 Coef: Add<Output = Coef> + Zero,
208 Exp: Ord,
209{
210 fn zero() -> Self {
211 Polynomial(Combination::default())
212 }
213
214 fn is_zero(&self) -> bool {
215 self.0.is_zero()
216 }
217}
218
219impl<Var, Coef, Exp> AdditiveMonoid for Polynomial<Var, Coef, Exp>
220where
221 Var: Ord,
222 Coef: AdditiveMonoid,
223 Exp: Ord,
224{
225}
226
227impl<Var, Coef, Exp> Mul<Coef> for Polynomial<Var, Coef, Exp>
228where
229 Var: Ord,
230 Coef: Clone + Default + Mul<Output = Coef>,
231 Exp: Ord,
232{
233 type Output = Self;
234
235 fn mul(self, a: Coef) -> Self::Output {
236 Polynomial(self.0 * a)
237 }
238}
239
240impl<Var, Coef, Exp> RigModule for Polynomial<Var, Coef, Exp>
241where
242 Var: Ord,
243 Coef: Clone + Default + CommRig,
244 Exp: Ord,
245{
246 type Rig = Coef;
247}
248
249impl<Var, Coef, Exp> Neg for Polynomial<Var, Coef, Exp>
250where
251 Var: Ord,
252 Coef: Default + Neg<Output = Coef>,
253 Exp: Ord,
254{
255 type Output = Self;
256
257 fn neg(self) -> Self::Output {
258 Polynomial(self.0.neg())
259 }
260}
261
262impl<Var, Coef, Exp> AbGroup for Polynomial<Var, Coef, Exp>
263where
264 Var: Ord,
265 Coef: Default + AbGroup,
266 Exp: Ord,
267{
268}
269
270impl<Var, Coef, Exp> Module for Polynomial<Var, Coef, Exp>
271where
272 Var: Ord,
273 Coef: Clone + Default + CommRing,
274 Exp: Ord,
275{
276 type Ring = Coef;
277}
278
279impl<Var, Coef, Exp> Mul for Polynomial<Var, Coef, Exp>
281where
282 Var: Clone + Ord,
283 Coef: Clone + Add<Output = Coef> + Mul<Output = Coef>,
284 Exp: Clone + Ord + Add<Output = Exp>,
285{
286 type Output = Self;
287
288 fn mul(self, rhs: Self) -> Self::Output {
289 let mut result = Polynomial::default();
292 let (outer, inner) = (self.0, rhs.0);
293 let mut outer_iter = outer.into_iter();
294 while let Some((a, m)) = outer_iter.next() {
295 if outer_iter.len() == 0 {
296 let mut inner_iter = inner.into_iter();
297 while let Some((b, n)) = inner_iter.next() {
298 if inner_iter.len() == 0 {
299 result += (a * b, m * n);
300 break;
301 } else {
302 result += (a.clone() * b, m.clone() * n);
303 }
304 }
305 break;
306 } else {
307 for (b, n) in &inner {
308 result += (a.clone() * b.clone(), m.clone() * n.clone());
309 }
310 }
311 }
312 result
313 }
314}
315
316impl<Var, Coef, Exp> One for Polynomial<Var, Coef, Exp>
317where
318 Var: Clone + Ord,
319 Coef: Clone + Add<Output = Coef> + One,
320 Exp: Clone + Ord + Add<Output = Exp>,
321{
322 fn one() -> Self {
323 Polynomial::from_monomial(Default::default())
324 }
325}
326
327impl<Var, Coef, Exp> Monoid for Polynomial<Var, Coef, Exp>
328where
329 Var: Clone + Ord,
330 Coef: Clone + Rig,
331 Exp: Clone + Ord + AdditiveMonoid,
332{
333}
334
335impl<Var, Coef, Exp> Rig for Polynomial<Var, Coef, Exp>
336where
337 Var: Clone + Ord,
338 Coef: Clone + Rig,
339 Exp: Clone + Ord + AdditiveMonoid,
340{
341}
342
343impl<Var, Coef, Exp> Ring for Polynomial<Var, Coef, Exp>
344where
345 Var: Clone + Ord,
346 Coef: Clone + Default + Ring,
347 Exp: Clone + Ord + AdditiveMonoid,
348{
349}
350
351impl<Var, Coef, Exp> CommMonoid for Polynomial<Var, Coef, Exp>
352where
353 Var: Clone + Ord,
354 Coef: Clone + CommRig,
355 Exp: Clone + Ord + AdditiveMonoid,
356{
357}
358
359impl<Var, Coef, Exp> CommRig for Polynomial<Var, Coef, Exp>
360where
361 Var: Clone + Ord,
362 Coef: Clone + CommRig,
363 Exp: Clone + Ord + AdditiveMonoid,
364{
365}
366
367impl<Var, Coef, Exp> CommRing for Polynomial<Var, Coef, Exp>
368where
369 Var: Clone + Ord,
370 Coef: Clone + Default + CommRing,
371 Exp: Clone + Ord + AdditiveMonoid,
372{
373}
374
375impl<Var, Coef, Exp> CommAlg for Polynomial<Var, Coef, Exp>
376where
377 Var: Clone + Ord,
378 Coef: Clone + Default + CommRing,
379 Exp: Clone + Ord + AdditiveMonoid,
380{
381 type R = Coef;
382
383 fn from_scalar(r: Self::R) -> Self {
384 [(r, Monomial::one())].into_iter().collect()
385 }
386}
387
388#[cfg(test)]
389mod tests {
390 use super::*;
391
392 #[test]
393 fn polynomials() {
394 let x = || Polynomial::<_, i32, u32>::generator('x');
395 let y = || Polynomial::<_, i32, u32>::generator('y');
396 assert_eq!(x().to_string(), "x");
397
398 let p = Polynomial::<char, i32, u32>::from_scalar(-5);
399 assert_eq!(p.eval_pairs::<i32>([]), -5);
400
401 let p = x() * y() * x() * 2 + y() * x() * y() * 3;
402 assert_eq!(p.to_string(), "3 x y^2 + 2 x^2 y");
403 assert_eq!(p.map_variables(|_| 'x').to_string(), "5 x^3");
404 assert_eq!(p.eval_pairs([('x', 1), ('y', 1)]), 5);
405 assert_eq!(p.eval_pairs([('x', 1), ('y', 2)]), 16);
406 assert_eq!(p.eval_pairs([('y', 1), ('x', 2)]), 14);
407
408 let p = (x() + y()) * (x() + y());
409 assert_eq!(p.to_string(), "2 x y + x^2 + y^2");
410
411 let p = (x() + y()) * (x() + y().neg());
412 assert_eq!(p.normalize().to_string(), "x^2 + (-1) y^2");
413 }
414}