mathhook_core/core/polynomial/poly/
arithmetic.rs1use super::Poly;
2use crate::core::polynomial::traits::Ring;
3use std::ops::{Add, Mul, Neg, Sub};
4
5impl<T: Ring> Poly<T> {
6 #[inline]
8 pub fn add(&self, other: &Self) -> Self {
9 let max_len = self.coeffs.len().max(other.coeffs.len());
10 let mut result = Vec::with_capacity(max_len);
11
12 for i in 0..max_len {
13 let a = self.coeff(i);
14 let b = other.coeff(i);
15 result.push(a.wrapping_add(&b));
16 }
17
18 Self::from_coeffs(result)
19 }
20
21 #[inline]
23 pub fn sub(&self, other: &Self) -> Self {
24 let max_len = self.coeffs.len().max(other.coeffs.len());
25 let mut result = Vec::with_capacity(max_len);
26
27 for i in 0..max_len {
28 let a = self.coeff(i);
29 let b = other.coeff(i);
30 result.push(a.wrapping_sub(&b));
31 }
32
33 Self::from_coeffs(result)
34 }
35
36 #[inline]
40 pub fn mul(&self, other: &Self) -> Self {
41 if self.is_zero() || other.is_zero() {
42 return Self::zero();
43 }
44
45 let result_len = self.coeffs.len() + other.coeffs.len() - 1;
46 let mut result = Vec::with_capacity(result_len);
47 for _ in 0..result_len {
48 result.push(T::zero());
49 }
50
51 for (i, a) in self.coeffs.iter().enumerate() {
52 if a.is_zero() {
53 continue;
54 }
55 for (j, b) in other.coeffs.iter().enumerate() {
56 let prod = a.wrapping_mul(b);
57 result[i + j] = result[i + j].wrapping_add(&prod);
58 }
59 }
60
61 Self::from_coeffs(result)
62 }
63
64 #[inline]
66 pub fn scale(&self, c: &T) -> Self {
67 if c.is_zero() {
68 return Self::zero();
69 }
70 if c.is_one() {
71 return self.clone();
72 }
73
74 let coeffs: Vec<T> = self.coeffs.iter().map(|x| x.wrapping_mul(c)).collect();
75 Self::from_coeffs(coeffs)
76 }
77
78 #[inline]
80 pub fn negate(&self) -> Self {
81 let coeffs: Vec<T> = self.coeffs.iter().map(|x| -x.clone()).collect();
82 Self { coeffs }
83 }
84
85 #[inline]
87 pub fn derivative(&self) -> Self {
88 if self.coeffs.len() <= 1 {
89 return Self::zero();
90 }
91
92 let coeffs: Vec<T> = self.coeffs[1..]
93 .iter()
94 .enumerate()
95 .map(|(i, c)| {
96 let multiplier = T::zero().wrapping_add(&T::one());
97 let mut result = multiplier.clone();
98 for _ in 0..i {
99 result = result.wrapping_add(&multiplier);
100 }
101 c.wrapping_mul(&result)
102 })
103 .collect();
104
105 Self::from_coeffs(coeffs)
106 }
107
108 #[inline]
112 pub fn evaluate(&self, x: &T) -> T {
113 if self.coeffs.is_empty() {
114 return T::zero();
115 }
116
117 let mut result = T::zero();
118 for coeff in self.coeffs.iter().rev() {
119 result = result.wrapping_mul(x).wrapping_add(coeff);
120 }
121 result
122 }
123}
124
125impl<T: Ring> Add for Poly<T> {
126 type Output = Self;
127
128 #[inline]
129 fn add(self, other: Self) -> Self {
130 Poly::add(&self, &other)
131 }
132}
133
134impl<T: Ring> Add for &Poly<T> {
135 type Output = Poly<T>;
136
137 #[inline]
138 fn add(self, other: Self) -> Poly<T> {
139 Poly::add(self, other)
140 }
141}
142
143impl<T: Ring> Sub for Poly<T> {
144 type Output = Self;
145
146 #[inline]
147 fn sub(self, other: Self) -> Self {
148 Poly::sub(&self, &other)
149 }
150}
151
152impl<T: Ring> Sub for &Poly<T> {
153 type Output = Poly<T>;
154
155 #[inline]
156 fn sub(self, other: Self) -> Poly<T> {
157 Poly::sub(self, other)
158 }
159}
160
161impl<T: Ring> Mul for Poly<T> {
162 type Output = Self;
163
164 #[inline]
165 fn mul(self, other: Self) -> Self {
166 Poly::mul(&self, &other)
167 }
168}
169
170impl<T: Ring> Mul for &Poly<T> {
171 type Output = Poly<T>;
172
173 #[inline]
174 fn mul(self, other: Self) -> Poly<T> {
175 Poly::mul(self, other)
176 }
177}
178
179impl<T: Ring> Neg for Poly<T> {
180 type Output = Self;
181
182 #[inline]
183 fn neg(self) -> Self {
184 self.negate()
185 }
186}
187
188impl<T: Ring> Neg for &Poly<T> {
189 type Output = Poly<T>;
190
191 #[inline]
192 fn neg(self) -> Poly<T> {
193 self.negate()
194 }
195}
196
197impl super::IntPoly {
198 #[inline]
200 pub fn evaluate_i64(&self, x: i64) -> i64 {
201 if self.coeffs.is_empty() {
202 return 0;
203 }
204
205 let mut result = 0i64;
206 for &coeff in self.coeffs.iter().rev() {
207 result = result.wrapping_mul(x).wrapping_add(coeff);
208 }
209 result
210 }
211
212 #[inline]
214 pub fn scale_i64(&self, c: i64) -> Self {
215 if c == 0 {
216 return Self::zero();
217 }
218 if c == 1 {
219 return self.clone();
220 }
221
222 let coeffs: Vec<i64> = self.coeffs.iter().map(|&x| x.wrapping_mul(c)).collect();
223 Self::from_coeffs(coeffs)
224 }
225
226 #[inline]
228 pub fn derivative_i64(&self) -> Self {
229 if self.coeffs.len() <= 1 {
230 return Self::zero();
231 }
232
233 let coeffs: Vec<i64> = self.coeffs[1..]
234 .iter()
235 .enumerate()
236 .map(|(i, &c)| c.wrapping_mul((i + 1) as i64))
237 .collect();
238
239 Self::from_coeffs(coeffs)
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use crate::core::polynomial::poly::IntPoly;
246
247 #[test]
248 fn test_addition() {
249 let p1 = IntPoly::from_coeffs(vec![1, 2, 3]);
250 let p2 = IntPoly::from_coeffs(vec![4, 5]);
251 let sum = &p1 + &p2;
252 assert_eq!(sum.coefficients(), &[5, 7, 3]);
253 }
254
255 #[test]
256 fn test_subtraction() {
257 let p1 = IntPoly::from_coeffs(vec![5, 7, 3]);
258 let p2 = IntPoly::from_coeffs(vec![4, 5]);
259 let diff = &p1 - &p2;
260 assert_eq!(diff.coefficients(), &[1, 2, 3]);
261 }
262
263 #[test]
264 fn test_multiplication() {
265 let p = IntPoly::from_coeffs(vec![1, 1]);
266 let product = &p * &p;
267 assert_eq!(product.coefficients(), &[1, 2, 1]);
268
269 let p1 = IntPoly::from_coeffs(vec![1, 1]);
270 let p2 = IntPoly::from_coeffs(vec![1, -1]);
271 let product = &p1 * &p2;
272 assert_eq!(product.coefficients(), &[1, 0, -1]);
273 }
274
275 #[test]
276 fn test_evaluation() {
277 let p = IntPoly::from_coeffs(vec![1, 2, 3]);
278 assert_eq!(p.evaluate_i64(2), 17);
279 assert_eq!(p.evaluate_i64(0), 1);
280 assert_eq!(p.evaluate_i64(1), 6);
281 }
282
283 #[test]
284 fn test_derivative() {
285 let p = IntPoly::from_coeffs(vec![1, 2, 3, 4]);
286 let dp = p.derivative_i64();
287 assert_eq!(dp.coefficients(), &[2, 6, 12]);
288 }
289
290 #[test]
291 fn test_negation() {
292 let p = IntPoly::from_coeffs(vec![1, -2, 3]);
293 let neg = -&p;
294 assert_eq!(neg.coefficients(), &[-1, 2, -3]);
295 }
296
297 #[test]
298 fn test_scalar_multiplication() {
299 let p = IntPoly::from_coeffs(vec![1, 2, 3]);
300 let scaled = p.scale_i64(3);
301 assert_eq!(scaled.coefficients(), &[3, 6, 9]);
302 }
303}