Skip to main content

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}