malachite_base/unsigned_polynomial/arithmetic/mod_add.rs
1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::num::arithmetic::traits::{ModAdd, ModAddAssign, ModIsReduced};
10use crate::num::basic::unsigneds::PrimitiveUnsigned;
11use crate::unsigned_polynomial::UnsignedPolynomial;
12use alloc::vec::Vec;
13use core::cmp::min;
14use core::mem::swap;
15
16pub(crate) fn assert_reduced<T: PrimitiveUnsigned>(
17 p: &UnsignedPolynomial<T>,
18 q: &UnsignedPolynomial<T>,
19 m: T,
20) {
21 assert!(
22 p.mod_is_reduced(&m),
23 "self must be reduced mod m, but {p} has a coefficient >= {m}"
24 );
25 assert!(
26 q.mod_is_reduced(&m),
27 "other must be reduced mod m, but {q} has a coefficient >= {m}"
28 );
29}
30
31// Adds `ys` into `xs` modulo m, copying the coefficients of `ys` past the end of `xs`. The caller
32// trims, since leading coefficients can cancel.
33pub(crate) fn add_assign_ref<T: PrimitiveUnsigned>(xs: &mut Vec<T>, ys: &[T], m: T) {
34 let common = min(xs.len(), ys.len());
35 for (x, &y) in xs.iter_mut().zip(&ys[..common]) {
36 *x = x.mod_add(y, m);
37 }
38 if ys.len() > common {
39 xs.extend_from_slice(&ys[common..]);
40 }
41}
42
43// Adds `ys` into `xs` modulo m, reusing whichever of the two is longer. The caller trims.
44pub(crate) fn add_assign_val<T: PrimitiveUnsigned>(xs: &mut Vec<T>, mut ys: Vec<T>, m: T) {
45 if ys.len() > xs.len() {
46 swap(xs, &mut ys);
47 }
48 for (x, y) in xs.iter_mut().zip(ys) {
49 *x = x.mod_add(y, m);
50 }
51}
52
53fn mod_add_owned_owned<T: PrimitiveUnsigned>(
54 mut p: UnsignedPolynomial<T>,
55 q: UnsignedPolynomial<T>,
56 m: T,
57) -> UnsignedPolynomial<T> {
58 assert_reduced(&p, &q, m);
59 add_assign_val(&mut p.coefficients, q.coefficients, m);
60 p.trim();
61 p
62}
63
64fn mod_add_owned_ref<T: PrimitiveUnsigned>(
65 mut p: UnsignedPolynomial<T>,
66 q: &UnsignedPolynomial<T>,
67 m: T,
68) -> UnsignedPolynomial<T> {
69 assert_reduced(&p, q, m);
70 add_assign_ref(&mut p.coefficients, &q.coefficients, m);
71 p.trim();
72 p
73}
74
75fn mod_add_ref_owned<T: PrimitiveUnsigned>(
76 p: &UnsignedPolynomial<T>,
77 mut q: UnsignedPolynomial<T>,
78 m: T,
79) -> UnsignedPolynomial<T> {
80 assert_reduced(p, &q, m);
81 add_assign_ref(&mut q.coefficients, &p.coefficients, m);
82 q.trim();
83 q
84}
85
86fn mod_add_ref_ref<T: PrimitiveUnsigned>(
87 p: &UnsignedPolynomial<T>,
88 q: &UnsignedPolynomial<T>,
89 m: T,
90) -> UnsignedPolynomial<T> {
91 assert_reduced(p, q, m);
92 let mut coefficients = p.coefficients.clone();
93 add_assign_ref(&mut coefficients, &q.coefficients, m);
94 let mut result = UnsignedPolynomial { coefficients };
95 result.trim();
96 result
97}
98
99fn mod_add_assign_owned<T: PrimitiveUnsigned>(
100 p: &mut UnsignedPolynomial<T>,
101 q: UnsignedPolynomial<T>,
102 m: T,
103) {
104 assert_reduced(p, &q, m);
105 add_assign_val(&mut p.coefficients, q.coefficients, m);
106 p.trim();
107}
108
109fn mod_add_assign_ref<T: PrimitiveUnsigned>(
110 p: &mut UnsignedPolynomial<T>,
111 q: &UnsignedPolynomial<T>,
112 m: T,
113) {
114 assert_reduced(p, q, m);
115 add_assign_ref(&mut p.coefficients, &q.coefficients, m);
116 p.trim();
117}
118
119impl<T: PrimitiveUnsigned> ModAdd<Self, T> for UnsignedPolynomial<T> {
120 type Output = Self;
121
122 /// Adds two [`UnsignedPolynomial`]s modulo `m`, taking both by value. The coefficients of both
123 /// must already be reduced modulo `m`.
124 ///
125 /// $$
126 /// f(p, q, m) = p + q \bmod m.
127 /// $$
128 ///
129 /// Coefficients past the end of the shorter polynomial are taken to be zero. When the two
130 /// polynomials have the same degree, their leading coefficients can cancel modulo `m`, and then
131 /// the degree of the sum is lower.
132 ///
133 /// # Worst-case complexity
134 /// $T(n) = O(n)$
135 ///
136 /// $M(n) = O(1)$
137 ///
138 /// where $T$ is time, $M$ is additional memory, and $n$ is the number of coefficients of the
139 /// longer polynomial.
140 ///
141 /// # Panics
142 /// Panics if `m` is 0, or if any coefficient of `self` or `other` is greater than or equal to
143 /// `m`.
144 ///
145 /// # Examples
146 /// ```
147 /// use core::str::FromStr;
148 /// use malachite_base::num::arithmetic::traits::ModAdd;
149 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
150 ///
151 /// // The leading coefficients cancel, and so do the linear ones.
152 /// assert_eq!(
153 /// UnsignedPolynomial::<u8>::from_str("5*x^2+x+3")
154 /// .unwrap()
155 /// .mod_add(UnsignedPolynomial::from_str("2*x^2+6*x+1").unwrap(), 7)
156 /// .to_string(),
157 /// "4"
158 /// );
159 /// // Wrapping around makes the constant term 2.
160 /// assert_eq!(
161 /// UnsignedPolynomial::<u8>::from_str("x+3")
162 /// .unwrap()
163 /// .mod_add(UnsignedPolynomial::from_str("x^2+6").unwrap(), 7)
164 /// .to_string(),
165 /// "x^2+x+2"
166 /// );
167 /// ```
168 ///
169 /// This is equivalent to `nmod_poly_add` from `nmod_poly/add.c`, FLINT 3.6.0.
170 #[inline]
171 fn mod_add(self, other: Self, m: T) -> Self {
172 mod_add_owned_owned(self, other, m)
173 }
174}
175
176impl<T: PrimitiveUnsigned> ModAdd<&Self, T> for UnsignedPolynomial<T> {
177 type Output = Self;
178
179 /// Adds two [`UnsignedPolynomial`]s modulo `m`, taking the first by value and the second by
180 /// reference. The coefficients of both must already be reduced modulo `m`.
181 ///
182 /// $$
183 /// f(p, q, m) = p + q \bmod m.
184 /// $$
185 ///
186 /// Coefficients past the end of the shorter polynomial are taken to be zero. When the two
187 /// polynomials have the same degree, their leading coefficients can cancel modulo `m`, and then
188 /// the degree of the sum is lower.
189 ///
190 /// # Worst-case complexity
191 /// $T(n) = O(n)$
192 ///
193 /// $M(n) = O(n)$
194 ///
195 /// where $T$ is time, $M$ is additional memory, and $n$ is the number of coefficients of the
196 /// longer polynomial.
197 ///
198 /// # Panics
199 /// Panics if `m` is 0, or if any coefficient of `self` or `other` is greater than or equal to
200 /// `m`.
201 ///
202 /// # Examples
203 /// ```
204 /// use core::str::FromStr;
205 /// use malachite_base::num::arithmetic::traits::ModAdd;
206 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
207 ///
208 /// // The leading coefficients cancel, and so do the linear ones.
209 /// assert_eq!(
210 /// UnsignedPolynomial::<u8>::from_str("5*x^2+x+3")
211 /// .unwrap()
212 /// .mod_add(&UnsignedPolynomial::from_str("2*x^2+6*x+1").unwrap(), 7)
213 /// .to_string(),
214 /// "4"
215 /// );
216 /// // Wrapping around makes the constant term 2.
217 /// assert_eq!(
218 /// UnsignedPolynomial::<u8>::from_str("x+3")
219 /// .unwrap()
220 /// .mod_add(&UnsignedPolynomial::from_str("x^2+6").unwrap(), 7)
221 /// .to_string(),
222 /// "x^2+x+2"
223 /// );
224 /// ```
225 ///
226 /// This is equivalent to `nmod_poly_add` from `nmod_poly/add.c`, FLINT 3.6.0.
227 #[inline]
228 fn mod_add(self, other: &Self, m: T) -> Self {
229 mod_add_owned_ref(self, other, m)
230 }
231}
232
233impl<T: PrimitiveUnsigned> ModAdd<UnsignedPolynomial<T>, T> for &UnsignedPolynomial<T> {
234 type Output = UnsignedPolynomial<T>;
235
236 /// Adds two [`UnsignedPolynomial`]s modulo `m`, taking the first by reference and the second by
237 /// value. The coefficients of both must already be reduced modulo `m`.
238 ///
239 /// $$
240 /// f(p, q, m) = p + q \bmod m.
241 /// $$
242 ///
243 /// Coefficients past the end of the shorter polynomial are taken to be zero. When the two
244 /// polynomials have the same degree, their leading coefficients can cancel modulo `m`, and then
245 /// the degree of the sum is lower.
246 ///
247 /// # Worst-case complexity
248 /// $T(n) = O(n)$
249 ///
250 /// $M(n) = O(n)$
251 ///
252 /// where $T$ is time, $M$ is additional memory, and $n$ is the number of coefficients of the
253 /// longer polynomial.
254 ///
255 /// # Panics
256 /// Panics if `m` is 0, or if any coefficient of `self` or `other` is greater than or equal to
257 /// `m`.
258 ///
259 /// # Examples
260 /// ```
261 /// use core::str::FromStr;
262 /// use malachite_base::num::arithmetic::traits::ModAdd;
263 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
264 ///
265 /// // The leading coefficients cancel, and so do the linear ones.
266 /// assert_eq!(
267 /// (&UnsignedPolynomial::<u8>::from_str("5*x^2+x+3").unwrap())
268 /// .mod_add(UnsignedPolynomial::from_str("2*x^2+6*x+1").unwrap(), 7)
269 /// .to_string(),
270 /// "4"
271 /// );
272 /// // Wrapping around makes the constant term 2.
273 /// assert_eq!(
274 /// (&UnsignedPolynomial::<u8>::from_str("x+3").unwrap())
275 /// .mod_add(UnsignedPolynomial::from_str("x^2+6").unwrap(), 7)
276 /// .to_string(),
277 /// "x^2+x+2"
278 /// );
279 /// ```
280 ///
281 /// This is equivalent to `nmod_poly_add` from `nmod_poly/add.c`, FLINT 3.6.0.
282 #[inline]
283 fn mod_add(self, other: UnsignedPolynomial<T>, m: T) -> UnsignedPolynomial<T> {
284 mod_add_ref_owned(self, other, m)
285 }
286}
287
288impl<T: PrimitiveUnsigned> ModAdd<&UnsignedPolynomial<T>, T> for &UnsignedPolynomial<T> {
289 type Output = UnsignedPolynomial<T>;
290
291 /// Adds two [`UnsignedPolynomial`]s modulo `m`, taking both by reference. The coefficients of
292 /// both must already be reduced modulo `m`.
293 ///
294 /// $$
295 /// f(p, q, m) = p + q \bmod m.
296 /// $$
297 ///
298 /// Coefficients past the end of the shorter polynomial are taken to be zero. When the two
299 /// polynomials have the same degree, their leading coefficients can cancel modulo `m`, and then
300 /// the degree of the sum is lower.
301 ///
302 /// # Worst-case complexity
303 /// $T(n) = O(n)$
304 ///
305 /// $M(n) = O(n)$
306 ///
307 /// where $T$ is time, $M$ is additional memory, and $n$ is the number of coefficients of the
308 /// longer polynomial.
309 ///
310 /// # Panics
311 /// Panics if `m` is 0, or if any coefficient of `self` or `other` is greater than or equal to
312 /// `m`.
313 ///
314 /// # Examples
315 /// ```
316 /// use core::str::FromStr;
317 /// use malachite_base::num::arithmetic::traits::ModAdd;
318 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
319 ///
320 /// // The leading coefficients cancel, and so do the linear ones.
321 /// assert_eq!(
322 /// (&UnsignedPolynomial::<u8>::from_str("5*x^2+x+3").unwrap())
323 /// .mod_add(&UnsignedPolynomial::from_str("2*x^2+6*x+1").unwrap(), 7)
324 /// .to_string(),
325 /// "4"
326 /// );
327 /// // Wrapping around makes the constant term 2.
328 /// assert_eq!(
329 /// (&UnsignedPolynomial::<u8>::from_str("x+3").unwrap())
330 /// .mod_add(&UnsignedPolynomial::from_str("x^2+6").unwrap(), 7)
331 /// .to_string(),
332 /// "x^2+x+2"
333 /// );
334 /// ```
335 ///
336 /// This is equivalent to `nmod_poly_add` from `nmod_poly/add.c`, FLINT 3.6.0.
337 #[inline]
338 fn mod_add(self, other: &UnsignedPolynomial<T>, m: T) -> UnsignedPolynomial<T> {
339 mod_add_ref_ref(self, other, m)
340 }
341}
342
343impl<T: PrimitiveUnsigned> ModAddAssign<Self, T> for UnsignedPolynomial<T> {
344 /// Adds an [`UnsignedPolynomial`] to an [`UnsignedPolynomial`] modulo `m`, in place, taking the
345 /// second by value. The coefficients of both must already be reduced modulo `m`.
346 ///
347 /// $$
348 /// p \gets p + q \bmod m.
349 /// $$
350 ///
351 /// Coefficients past the end of the shorter polynomial are taken to be zero. When the two
352 /// polynomials have the same degree, their leading coefficients can cancel modulo `m`, and then
353 /// the degree of the sum is lower.
354 ///
355 /// # Worst-case complexity
356 /// $T(n) = O(n)$
357 ///
358 /// $M(n) = O(1)$
359 ///
360 /// where $T$ is time, $M$ is additional memory, and $n$ is the number of coefficients of the
361 /// longer polynomial.
362 ///
363 /// # Panics
364 /// Panics if `m` is 0, or if any coefficient of `self` or `other` is greater than or equal to
365 /// `m`.
366 ///
367 /// # Examples
368 /// ```
369 /// use core::str::FromStr;
370 /// use malachite_base::num::arithmetic::traits::ModAddAssign;
371 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
372 ///
373 /// // The leading coefficients cancel, and so do the linear ones.
374 /// let mut p = UnsignedPolynomial::<u8>::from_str("5*x^2+x+3").unwrap();
375 /// p.mod_add_assign(UnsignedPolynomial::from_str("2*x^2+6*x+1").unwrap(), 7);
376 /// assert_eq!(p.to_string(), "4");
377 ///
378 /// // Wrapping around makes the constant term 2.
379 /// let mut p = UnsignedPolynomial::<u8>::from_str("x+3").unwrap();
380 /// p.mod_add_assign(UnsignedPolynomial::from_str("x^2+6").unwrap(), 7);
381 /// assert_eq!(p.to_string(), "x^2+x+2");
382 /// ```
383 ///
384 /// This is equivalent to `nmod_poly_add` from `nmod_poly/add.c`, FLINT 3.6.0.
385 #[inline]
386 fn mod_add_assign(&mut self, other: Self, m: T) {
387 mod_add_assign_owned(self, other, m);
388 }
389}
390
391impl<T: PrimitiveUnsigned> ModAddAssign<&Self, T> for UnsignedPolynomial<T> {
392 /// Adds an [`UnsignedPolynomial`] to an [`UnsignedPolynomial`] modulo `m`, in place, taking the
393 /// second by reference. The coefficients of both must already be reduced modulo `m`.
394 ///
395 /// $$
396 /// p \gets p + q \bmod m.
397 /// $$
398 ///
399 /// Coefficients past the end of the shorter polynomial are taken to be zero. When the two
400 /// polynomials have the same degree, their leading coefficients can cancel modulo `m`, and then
401 /// the degree of the sum is lower.
402 ///
403 /// # Worst-case complexity
404 /// $T(n) = O(n)$
405 ///
406 /// $M(n) = O(n)$
407 ///
408 /// where $T$ is time, $M$ is additional memory, and $n$ is the number of coefficients of the
409 /// longer polynomial.
410 ///
411 /// # Panics
412 /// Panics if `m` is 0, or if any coefficient of `self` or `other` is greater than or equal to
413 /// `m`.
414 ///
415 /// # Examples
416 /// ```
417 /// use core::str::FromStr;
418 /// use malachite_base::num::arithmetic::traits::ModAddAssign;
419 /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
420 ///
421 /// // The leading coefficients cancel, and so do the linear ones.
422 /// let mut p = UnsignedPolynomial::<u8>::from_str("5*x^2+x+3").unwrap();
423 /// p.mod_add_assign(&UnsignedPolynomial::from_str("2*x^2+6*x+1").unwrap(), 7);
424 /// assert_eq!(p.to_string(), "4");
425 ///
426 /// // Wrapping around makes the constant term 2.
427 /// let mut p = UnsignedPolynomial::<u8>::from_str("x+3").unwrap();
428 /// p.mod_add_assign(&UnsignedPolynomial::from_str("x^2+6").unwrap(), 7);
429 /// assert_eq!(p.to_string(), "x^2+x+2");
430 /// ```
431 ///
432 /// This is equivalent to `nmod_poly_add` from `nmod_poly/add.c`, FLINT 3.6.0.
433 #[inline]
434 fn mod_add_assign(&mut self, other: &Self, m: T) {
435 mod_add_assign_ref(self, other, m);
436 }
437}