Skip to main content

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