1use num_traits::{One, Pow, Zero};
18use std::collections::BTreeMap;
19use std::fmt::Display;
20use std::iter::{Product, Sum};
21use std::ops::{Add, AddAssign, Mul, MulAssign, Neg};
22
23use derivative::Derivative;
24use duplicate::duplicate_item;
25
26pub trait AdditiveMonoid: Add<Output = Self> + Zero {}
28
29#[duplicate_item(T; [f32]; [f64]; [i32]; [i64]; [u32]; [u64]; [usize])]
30impl AdditiveMonoid for T {}
31
32pub trait AbGroup: AdditiveMonoid + Neg<Output = Self> {}
39
40#[duplicate_item(T; [f32]; [f64]; [i32]; [i64])]
41impl AbGroup for T {}
42
43pub trait Monoid: Mul<Output = Self> + One {}
45
46#[duplicate_item(T; [f32]; [f64]; [i32]; [i64]; [u32]; [u64]; [usize])]
47impl Monoid for T {}
48
49pub trait CommMonoid: Monoid {}
51
52#[duplicate_item(T; [f32]; [f64]; [i32]; [i64]; [u32]; [u64]; [usize])]
53impl CommMonoid for T {}
54
55pub trait Rig: Monoid + AdditiveMonoid {}
57
58#[duplicate_item(T; [f32]; [f64]; [i32]; [i64]; [u32]; [u64]; [usize])]
59impl Rig for T {}
60
61pub trait CommRig: Rig + CommMonoid {}
63
64#[duplicate_item(T; [f32]; [f64]; [i32]; [i64]; [u32]; [u64]; [usize])]
65impl CommRig for T {}
66
67pub trait Ring: Rig + AbGroup {}
69
70#[duplicate_item(T; [f32]; [f64]; [i32]; [i64])]
71impl Ring for T {}
72
73pub trait CommRing: Ring + CommRig {}
75
76#[duplicate_item(T; [f32]; [f64]; [i32]; [i64])]
77impl CommRing for T {}
78
79pub trait RigModule: AdditiveMonoid + Mul<Self::Rig, Output = Self> {
81 type Rig: CommRig;
83}
84
85pub trait Module: RigModule<Rig = Self::Ring> + AbGroup {
87 type Ring: CommRing;
89}
90
91#[derive(Clone, PartialEq, Eq, Derivative)]
106#[derivative(Default(bound = ""))]
107pub struct Combination<Var, Coef>(BTreeMap<Var, Coef>);
108
109impl<Var, Coef> Combination<Var, Coef>
110where
111 Var: Ord,
112{
113 pub fn generator(var: Var) -> Self
115 where
116 Coef: One,
117 {
118 Combination([(var, Coef::one())].into_iter().collect())
119 }
120
121 pub fn variables(&self) -> impl ExactSizeIterator<Item = &Var> {
123 self.0.keys()
124 }
125
126 pub fn extend_scalars<NewCoef, F>(self, mut f: F) -> Combination<Var, NewCoef>
134 where
135 F: FnMut(Coef) -> NewCoef,
136 {
137 Combination(self.0.into_iter().map(|(var, coef)| (var, f(coef))).collect())
138 }
139
140 pub fn eval<A, F>(&self, mut f: F) -> A
142 where
143 A: Mul<Coef, Output = A> + Sum,
144 F: FnMut(&Var) -> A,
145 Coef: Clone,
146 {
147 self.0.iter().map(|(var, coef)| f(var) * coef.clone()).sum()
148 }
149
150 pub fn eval_with_order<A>(&self, values: impl IntoIterator<Item = A>) -> A
157 where
158 A: Mul<Coef, Output = A> + Sum,
159 Coef: Clone,
160 {
161 let mut iter = values.into_iter();
162 let value = self.eval(|_| iter.next().expect("Should have enough values"));
163 assert!(iter.next().is_none(), "Too many values");
164 value
165 }
166}
167
168impl<Var, Coef> FromIterator<(Coef, Var)> for Combination<Var, Coef>
170where
171 Var: Ord,
172 Coef: Add<Output = Coef>,
173{
174 fn from_iter<T: IntoIterator<Item = (Coef, Var)>>(iter: T) -> Self {
175 let mut combination = Combination::zero();
176 for rhs in iter {
177 combination += rhs;
178 }
179 combination
180 }
181}
182
183impl<Var, Coef> IntoIterator for Combination<Var, Coef> {
185 type Item = (Coef, Var);
186
187 type IntoIter = std::iter::Map<
188 std::collections::btree_map::IntoIter<Var, Coef>,
189 fn((Var, Coef)) -> (Coef, Var),
190 >;
191
192 fn into_iter(self) -> Self::IntoIter {
193 self.0.into_iter().map(|(var, coef)| (coef, var))
194 }
195}
196
197impl<'a, Var, Coef> IntoIterator for &'a Combination<Var, Coef> {
198 type Item = (&'a Coef, &'a Var);
199
200 type IntoIter = std::iter::Map<
201 std::collections::btree_map::Iter<'a, Var, Coef>,
202 fn((&'a Var, &'a Coef)) -> (&'a Coef, &'a Var),
203 >;
204
205 fn into_iter(self) -> Self::IntoIter {
206 self.0.iter().map(|(var, coef)| (coef, var))
207 }
208}
209
210impl<Var, Coef> Display for Combination<Var, Coef>
215where
216 Var: Display,
217 Coef: Display + PartialEq + One,
218{
219 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
220 let mut pairs = self.0.iter();
221 let fmt_scalar_mul = |f: &mut std::fmt::Formatter<'_>, coef: &Coef, var: &Var| {
222 if !coef.is_one() {
223 let coef = coef.to_string();
224 if coef.chars().all(|c| c.is_alphabetic())
225 || coef.chars().all(|c| c.is_ascii_digit() || c == '.')
226 {
227 write!(f, "{} ", coef)?;
228 } else {
229 write!(f, "({}) ", coef)?;
230 }
231 }
232 write!(f, "{}", var)
233 };
234 if let Some((var, coef)) = pairs.next() {
235 fmt_scalar_mul(f, coef, var)?;
236 } else {
237 write!(f, "0")?;
238 }
239 for (var, coef) in pairs {
240 write!(f, " + ")?;
241 fmt_scalar_mul(f, coef, var)?;
242 }
243 Ok(())
244 }
245}
246
247impl<Var, Coef> AddAssign<(Coef, Var)> for Combination<Var, Coef>
248where
249 Var: Ord,
250 Coef: Add<Output = Coef>,
251{
252 fn add_assign(&mut self, rhs: (Coef, Var)) {
253 let rhs = (rhs.1, rhs.0);
254 _add_assign(&mut self.0, rhs);
255 }
256}
257
258impl<Var, Coef> AddAssign for Combination<Var, Coef>
259where
260 Var: Ord,
261 Coef: Add<Output = Coef>,
262{
263 fn add_assign(&mut self, rhs: Self) {
264 for rhs in rhs.0 {
265 _add_assign(&mut self.0, rhs);
266 }
267 }
268}
269
270fn _add_assign<K, V>(lhs: &mut BTreeMap<K, V>, rhs: (K, V))
271where
272 K: Ord,
273 V: Add<Output = V>,
274{
275 let (k, b) = rhs;
276 if let Some(a) = lhs.remove(&k) {
277 lhs.insert(k, a + b);
278 } else {
279 lhs.insert(k, b);
280 }
281}
282
283impl<Var, Coef> Add for Combination<Var, Coef>
284where
285 Var: Ord,
286 Coef: Add<Output = Coef>,
287{
288 type Output = Self;
289
290 fn add(mut self, rhs: Self) -> Self {
291 self += rhs;
292 self
293 }
294}
295
296impl<Var, Coef> Zero for Combination<Var, Coef>
297where
298 Var: Ord,
299 Coef: Add<Output = Coef>,
300{
301 fn zero() -> Self {
302 Combination(Default::default())
303 }
304
305 fn is_zero(&self) -> bool {
306 self.0.is_empty()
307 }
308}
309
310impl<Var, Coef> AdditiveMonoid for Combination<Var, Coef>
311where
312 Var: Ord,
313 Coef: AdditiveMonoid,
314{
315}
316
317impl<Var, Coef> Mul<Coef> for Combination<Var, Coef>
318where
319 Var: Ord,
320 Coef: Clone + Default + Mul<Output = Coef>,
321{
322 type Output = Self;
323
324 fn mul(mut self, a: Coef) -> Self {
325 for coef in self.0.values_mut() {
326 *coef = std::mem::take(coef) * a.clone();
327 }
328 self
329 }
330}
331
332impl<Var, Coef> RigModule for Combination<Var, Coef>
333where
334 Var: Ord,
335 Coef: Clone + Default + CommRig,
336{
337 type Rig = Coef;
338}
339
340impl<Var, Coef> Neg for Combination<Var, Coef>
341where
342 Var: Ord,
343 Coef: Default + Neg<Output = Coef>,
344{
345 type Output = Self;
346
347 fn neg(mut self) -> Self {
348 for coef in self.0.values_mut() {
349 *coef = std::mem::take(coef).neg();
350 }
351 self
352 }
353}
354
355impl<Var, Coef> AbGroup for Combination<Var, Coef>
356where
357 Var: Ord,
358 Coef: Default + AbGroup,
359{
360}
361
362impl<Var, Coef> Module for Combination<Var, Coef>
363where
364 Var: Ord,
365 Coef: Clone + Default + CommRing,
366{
367 type Ring = Coef;
368}
369
370#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Derivative)]
389#[derivative(Default(bound = ""))]
390pub struct Monomial<Var, Exp>(BTreeMap<Var, Exp>);
391
392impl<Var, Exp> Monomial<Var, Exp>
393where
394 Var: Ord,
395{
396 pub fn generator(var: Var) -> Self
398 where
399 Exp: One,
400 {
401 Monomial([(var, Exp::one())].into_iter().collect())
402 }
403
404 pub fn variables(&self) -> impl ExactSizeIterator<Item = &Var> {
406 self.0.keys()
407 }
408
409 pub fn eval<A, F>(&self, mut f: F) -> A
411 where
412 A: Pow<Exp, Output = A> + Product,
413 F: FnMut(&Var) -> A,
414 Exp: Clone,
415 {
416 self.0.iter().map(|(var, exp)| f(var).pow(exp.clone())).product()
417 }
418
419 pub fn eval_with_order<A>(&self, values: impl IntoIterator<Item = A>) -> A
426 where
427 A: Pow<Exp, Output = A> + Product,
428 Exp: Clone,
429 {
430 let mut iter = values.into_iter();
431 let value = self.eval(|_| iter.next().expect("Should have enough values"));
432 assert!(iter.next().is_none(), "Too many values");
433 value
434 }
435
436 pub fn map_variables<NewVar, F>(&self, mut f: F) -> Monomial<NewVar, Exp>
443 where
444 Exp: Clone + Add<Output = Exp>,
445 NewVar: Ord,
446 F: FnMut(&Var) -> NewVar,
447 {
448 self.0.iter().map(|(var, exp)| (f(var), exp.clone())).collect()
449 }
450}
451
452impl<Var, Exp> FromIterator<(Var, Exp)> for Monomial<Var, Exp>
454where
455 Var: Ord,
456 Exp: Add<Output = Exp>,
457{
458 fn from_iter<T: IntoIterator<Item = (Var, Exp)>>(iter: T) -> Self {
459 let mut monomial = Monomial::one();
460 for rhs in iter {
461 monomial *= rhs;
462 }
463 monomial
464 }
465}
466
467impl<Var, Exp> Display for Monomial<Var, Exp>
469where
470 Var: Display,
471 Exp: Display + PartialEq + One,
472{
473 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
474 let mut pairs = self.0.iter();
475 let fmt_power = |f: &mut std::fmt::Formatter<'_>, var: &Var, exp: &Exp| {
476 write!(f, "{}", var)?;
477 if !exp.is_one() {
478 let exp = exp.to_string();
479 if exp.len() == 1 {
480 write!(f, "^{}", exp)?;
481 } else {
482 write!(f, "^{{{}}}", exp)?;
483 }
484 }
485 Ok(())
486 };
487 if let Some((var, exp)) = pairs.next() {
488 fmt_power(f, var, exp)?;
489 } else {
490 write!(f, "1")?;
491 }
492 for (var, exp) in pairs {
493 write!(f, " ")?;
494 fmt_power(f, var, exp)?;
495 }
496 Ok(())
497 }
498}
499
500impl<Var, Exp> MulAssign<(Var, Exp)> for Monomial<Var, Exp>
501where
502 Var: Ord,
503 Exp: Add<Output = Exp>,
504{
505 fn mul_assign(&mut self, rhs: (Var, Exp)) {
506 _add_assign(&mut self.0, rhs);
507 }
508}
509
510impl<Var, Exp> MulAssign for Monomial<Var, Exp>
511where
512 Var: Ord,
513 Exp: Add<Output = Exp>,
514{
515 fn mul_assign(&mut self, rhs: Self) {
516 for rhs in rhs.0 {
517 *self *= rhs;
518 }
519 }
520}
521
522impl<Var, Exp> Mul for Monomial<Var, Exp>
523where
524 Var: Ord,
525 Exp: Add<Output = Exp>,
526{
527 type Output = Self;
528
529 fn mul(mut self, rhs: Self) -> Self {
530 self *= rhs;
531 self
532 }
533}
534
535impl<Var, Exp> One for Monomial<Var, Exp>
536where
537 Var: Ord,
538 Exp: Add<Output = Exp>,
539{
540 fn one() -> Self {
541 Monomial(Default::default())
542 }
543
544 fn is_one(&self) -> bool {
545 self.0.is_empty()
546 }
547}
548
549impl<Var, Exp> Monoid for Monomial<Var, Exp>
550where
551 Var: Ord,
552 Exp: AdditiveMonoid,
553{
554}
555
556impl<Var, Exp> CommMonoid for Monomial<Var, Exp>
557where
558 Var: Ord,
559 Exp: AdditiveMonoid,
560{
561}
562
563impl<Var, Exp> Pow<Exp> for Monomial<Var, Exp>
564where
565 Var: Ord,
566 Exp: Clone + Default + Mul<Output = Exp>,
567{
568 type Output = Self;
569
570 fn pow(mut self, a: Exp) -> Self::Output {
571 for exp in self.0.values_mut() {
572 *exp = std::mem::take(exp) * a.clone();
573 }
574 self
575 }
576}
577
578#[cfg(test)]
579mod tests {
580 use super::*;
581
582 #[test]
583 fn combinations() {
584 let x = || Combination::generator('x');
585 let y = || Combination::generator('y');
586 assert_eq!(x().to_string(), "x");
587 assert_eq!((x() + y() + y() + x()).to_string(), "2 x + 2 y");
588
589 let combination = x() * 2u32 + y() * 3u32;
590 assert_eq!(combination.to_string(), "2 x + 3 y");
591 assert_eq!(combination.eval_with_order([5, 1]), 13);
592 let vars: Vec<_> = combination.variables().cloned().collect();
593 assert_eq!(vars, vec!['x', 'y']);
594
595 assert_eq!(Combination::<char, u32>::zero().to_string(), "0");
596
597 let x = Combination::generator('x');
598 assert_eq!((x.clone() * -1i32).to_string(), "(-1) x");
599 assert_eq!(x.neg().to_string(), "(-1) x");
600 }
601
602 #[test]
603 fn monomials() {
604 let x = || Monomial::<_, u32>::generator('x');
605 let y = || Monomial::<_, u32>::generator('y');
606 assert_eq!(x().to_string(), "x");
607 assert_eq!((x() * y() * y() * x()).to_string(), "x^2 y^2");
608
609 let monomial: Monomial<_, u32> = [('x', 1), ('y', 2)].into_iter().collect();
610 assert_eq!(monomial.to_string(), "x y^2");
611 assert_eq!(monomial.eval_with_order([10, 5]), 250);
612 let vars: Vec<_> = monomial.variables().cloned().collect();
613 assert_eq!(vars, vec!['x', 'y']);
614 assert_eq!(monomial.map_variables(|_| 'x').to_string(), "x^3");
615
616 assert_eq!(Monomial::<char, u32>::one().to_string(), "1");
617 }
618}