Skip to main content

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