mathhook_core/core/polynomial/
poly.rs1mod arithmetic;
25mod conversion;
26mod display;
27mod division;
28
29use super::traits::Ring;
30use num_rational::Ratio;
31
32#[derive(Debug, Clone, PartialEq, Eq)]
47pub struct Poly<T: Ring> {
48 coeffs: Vec<T>,
49}
50
51pub type IntPoly = Poly<i64>;
53
54pub type RationalPoly = Poly<Ratio<i64>>;
56
57impl<T: Ring> Poly<T> {
58 #[inline(always)]
71 pub fn from_coeffs(mut coeffs: Vec<T>) -> Self {
72 while coeffs.last().is_some_and(|c| c.is_zero()) {
73 coeffs.pop();
74 }
75 Self { coeffs }
76 }
77
78 #[inline(always)]
80 pub fn zero() -> Self {
81 Self { coeffs: Vec::new() }
82 }
83
84 #[inline(always)]
86 pub fn constant(c: T) -> Self {
87 if c.is_zero() {
88 Self::zero()
89 } else {
90 Self { coeffs: vec![c] }
91 }
92 }
93
94 #[inline(always)]
96 pub fn is_zero(&self) -> bool {
97 self.coeffs.is_empty()
98 }
99
100 #[inline(always)]
102 pub fn is_constant(&self) -> bool {
103 self.coeffs.len() <= 1
104 }
105
106 #[inline(always)]
108 pub fn degree(&self) -> Option<usize> {
109 if self.coeffs.is_empty() {
110 None
111 } else {
112 Some(self.coeffs.len() - 1)
113 }
114 }
115
116 #[inline(always)]
118 pub fn leading_coeff(&self) -> T {
119 self.coeffs.last().cloned().unwrap_or_else(T::zero)
120 }
121
122 #[inline(always)]
124 pub fn coeff(&self, i: usize) -> T {
125 self.coeffs.get(i).cloned().unwrap_or_else(T::zero)
126 }
127
128 #[inline(always)]
130 pub fn coefficients(&self) -> &[T] {
131 &self.coeffs
132 }
133}
134
135impl IntPoly {
136 #[inline(always)]
138 pub fn monomial(n: usize) -> Self {
139 let mut coeffs = vec![0; n + 1];
140 coeffs[n] = 1;
141 Self { coeffs }
142 }
143
144 #[inline(always)]
146 pub fn term(coeff: i64, power: usize) -> Self {
147 if coeff == 0 {
148 Self::zero()
149 } else {
150 let mut coeffs = vec![0; power + 1];
151 coeffs[power] = coeff;
152 Self { coeffs }
153 }
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160
161 #[test]
162 fn test_construction() {
163 let p = IntPoly::from_coeffs(vec![1, 2, 3]);
164 assert_eq!(p.degree(), Some(2));
165 assert_eq!(p.leading_coeff(), 3);
166 assert_eq!(p.coeff(0), 1);
167 assert_eq!(p.coeff(1), 2);
168 assert_eq!(p.coeff(2), 3);
169 assert_eq!(p.coeff(3), 0);
170 }
171
172 #[test]
173 fn test_zero_polynomial() {
174 let z = IntPoly::zero();
175 assert!(z.is_zero());
176 assert_eq!(z.degree(), None);
177 assert_eq!(z.leading_coeff(), 0);
178 }
179
180 #[test]
181 fn test_trailing_zeros_removed() {
182 let p = IntPoly::from_coeffs(vec![1, 2, 0, 0, 0]);
183 assert_eq!(p.degree(), Some(1));
184 assert_eq!(p.coefficients(), &[1, 2]);
185 }
186
187 #[test]
188 fn test_constant_polynomial() {
189 let p = IntPoly::constant(5);
190 assert!(p.is_constant());
191 assert_eq!(p.degree(), Some(0));
192 assert_eq!(p.coeff(0), 5);
193
194 let z = IntPoly::constant(0);
195 assert!(z.is_zero());
196 assert_eq!(z.degree(), None);
197 }
198
199 #[test]
200 fn test_rational_poly_construction() {
201 let p =
202 RationalPoly::from_coeffs(vec![Ratio::new(1, 2), Ratio::new(3, 4), Ratio::new(5, 6)]);
203 assert_eq!(p.degree(), Some(2));
204 assert_eq!(p.leading_coeff(), Ratio::new(5, 6));
205 assert_eq!(p.coeff(0), Ratio::new(1, 2));
206 }
207
208 #[test]
209 fn test_rational_poly_zero() {
210 let z = RationalPoly::zero();
211 assert!(z.is_zero());
212 assert_eq!(z.degree(), None);
213 assert_eq!(z.leading_coeff(), Ratio::new(0, 1));
214 }
215}