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