Skip to main content

sirius/solver/poly/
coef.rs

1//! Coefficient, the constant part of a [`Poly`](super::Poly) term.
2
3use std::cmp::{Ord, PartialOrd};
4use std::fmt;
5use std::ops::Neg;
6
7/// Coefficient, represented by `i128`. The constant part of a [`Poly`](super::Poly) term.
8/// All arithmetic is checked and panics on overflow.
9#[derive(Clone, Copy, PartialOrd, Ord, Hash, PartialEq, Eq)]
10pub struct Coef(i128);
11
12impl Coef {
13    pub fn new<T: Into<i128>>(v: T) -> Self {
14        Self(v.into())
15    }
16
17    pub fn from_size(v: usize) -> Self {
18        Self(v as i128)
19    }
20
21    pub fn get(&self) -> i128 {
22        self.0
23    }
24
25    pub fn vec(arr: &[i128]) -> Vec<Self> {
26        arr.iter().map(|a| Coef::new(*a)).collect()
27    }
28
29    pub fn is_zero(&self) -> bool {
30        self.0 == 0
31    }
32
33    pub fn is_positive(&self) -> bool {
34        self.0 > 0
35    }
36
37    pub fn gcd(&self, other: &Self) -> Self {
38        let (mut a, mut b) = (self.0, other.0);
39        while b != 0 {
40            (a, b) = (b, a % b);
41        }
42        Self(a)
43    }
44
45    pub fn lcm(&self, other: &Self) -> Self {
46        self * other / self.gcd(other)
47    }
48
49    pub fn abs(&self) -> Self {
50        Coef(self.0.checked_abs().unwrap())
51    }
52
53    pub fn divrem(&self, other: Coef) -> (Self, Self) {
54        (
55            Coef(self.0.checked_div(other.0).unwrap()),
56            Coef(self.0.checked_rem(other.0).unwrap()),
57        )
58    }
59
60    fn add_impl(&self, b: &Self) -> Coef {
61        Coef(self.0.checked_add(b.0).unwrap())
62    }
63
64    fn sub_impl(&self, b: &Self) -> Coef {
65        Coef(self.0.checked_sub(b.0).unwrap())
66    }
67
68    fn mul_impl(&self, b: &Self) -> Coef {
69        Coef(self.0.checked_mul(b.0).unwrap())
70    }
71
72    fn div_impl(&self, b: &Self) -> Coef {
73        Coef(self.0.checked_div(b.0).unwrap())
74    }
75}
76
77impl fmt::Debug for Coef {
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        write!(f, "{}", self.0)
80    }
81}
82
83impl<T: Into<i128>> From<T> for Coef {
84    fn from(val: T) -> Self {
85        Coef::new(val)
86    }
87}
88
89impl Neg for Coef {
90    type Output = Coef;
91
92    fn neg(self) -> Coef {
93        Coef(self.0.checked_neg().unwrap())
94    }
95}
96
97macro_rules! impl_binop {
98    ($T:ident, $Trait:ident, $method:ident, $impl_fn:ident) => {
99        impl std::ops::$Trait<&$T> for &$T {
100            type Output = $T;
101            fn $method(self, rhs: &$T) -> $T {
102                self.$impl_fn(rhs)
103            }
104        }
105        impl std::ops::$Trait<$T> for &$T {
106            type Output = $T;
107            fn $method(self, rhs: $T) -> $T {
108                self.$impl_fn(&rhs)
109            }
110        }
111        impl std::ops::$Trait<&$T> for $T {
112            type Output = $T;
113            fn $method(self, rhs: &$T) -> $T {
114                self.$impl_fn(rhs)
115            }
116        }
117        impl std::ops::$Trait<$T> for $T {
118            type Output = $T;
119            fn $method(self, rhs: $T) -> $T {
120                self.$impl_fn(&rhs)
121            }
122        }
123    };
124}
125
126impl_binop!(Coef, Add, add, add_impl);
127impl_binop!(Coef, Sub, sub, sub_impl);
128impl_binop!(Coef, Mul, mul, mul_impl);
129impl_binop!(Coef, Div, div, div_impl);
130
131#[cfg(test)]
132mod tests {
133    use super::Coef;
134    #[test]
135    fn gcd() {
136        let a = Coef(156);
137        let b = Coef(36);
138        assert_eq!(a.gcd(&b), Coef(12));
139    }
140}