Skip to main content

malachite_base/unsigned_polynomial/arithmetic/
mod_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::{ModSubTruncated, ModSubTruncatedAssign, Polynomial};
11use crate::unsigned_polynomial::UnsignedPolynomial;
12use crate::unsigned_polynomial::arithmetic::mod_add::assert_reduced;
13use crate::unsigned_polynomial::arithmetic::mod_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> ModSubTruncated<Self, T> for UnsignedPolynomial<T> {
23    type Output = Self;
24
25    /// Subtracts one [`UnsignedPolynomial`] from another modulo `m`, keeping only the coefficients
26    /// of $x^i$ for $i$ less than `len`, taking both by value. The coefficients of both must
27    /// already be reduced modulo `m`.
28    ///
29    /// $$
30    /// f(p, q, n, m) = ((p - q) \bmod x^n) \bmod m.
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 `m`. The difference is trimmed, so when
36    /// coefficients cancel modulo `m` 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.
45    ///
46    /// # Panics
47    /// Panics if `m` is 0, or if any coefficient of `self` or `other` is greater than or equal to
48    /// `m`.
49    ///
50    /// # Examples
51    /// ```
52    /// use core::str::FromStr;
53    /// use malachite_base::polynomial::ModSubTruncated;
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_sub_truncated(UnsignedPolynomial::from_str("4*x^2+6*x+2").unwrap(), 3, 7)
61    ///         .to_string(),
62    ///     "5*x^2+2*x+3"
63    /// );
64    /// assert_eq!(
65    ///     UnsignedPolynomial::<u8>::from_str("x^3+2*x^2+x+5")
66    ///         .unwrap()
67    ///         .mod_sub_truncated(UnsignedPolynomial::from_str("4*x^2+6*x+2").unwrap(), 1, 7)
68    ///         .to_string(),
69    ///     "3"
70    /// );
71    /// ```
72    ///
73    /// This is equivalent to `nmod_poly_sub_series` from `nmod_poly/sub_series.c`, FLINT 3.6.0.
74    fn mod_sub_truncated(mut self, mut other: Self, len: u64, m: T) -> Self {
75        assert_reduced(&self, &other, m);
76        self.truncate_assign(len);
77        other.truncate_assign(len);
78        sub_assign_val(&mut self.coefficients, other.coefficients, m);
79        self.trim();
80        self
81    }
82}
83
84impl<T: PrimitiveUnsigned> ModSubTruncated<&Self, T> for UnsignedPolynomial<T> {
85    type Output = Self;
86
87    /// Subtracts one [`UnsignedPolynomial`] from another modulo `m`, keeping only the coefficients
88    /// of $x^i$ for $i$ less than `len`, taking the first by value and the second by reference. The
89    /// coefficients of both must already be reduced modulo `m`.
90    ///
91    /// $$
92    /// f(p, q, n, m) = ((p - q) \bmod x^n) \bmod m.
93    /// $$
94    ///
95    /// The polynomials need not already be truncated: this is the difference of their images modulo
96    /// $x^n$, so only the first `len` coefficients of each are read. Where the second polynomial
97    /// has more of those, they are negated modulo `m`. The difference is trimmed, so when
98    /// coefficients cancel modulo `m` at the top of the kept range, the degree is lower still.
99    ///
100    /// # Worst-case complexity
101    /// $T(n) = O(n)$
102    ///
103    /// $M(n) = O(n)$
104    ///
105    /// where $T$ is time, $M$ is additional memory, and $n$ is the number of coefficients of the
106    /// longer polynomial.
107    ///
108    /// # Panics
109    /// Panics if `m` is 0, or if any coefficient of `self` or `other` is greater than or equal to
110    /// `m`.
111    ///
112    /// # Examples
113    /// ```
114    /// use core::str::FromStr;
115    /// use malachite_base::polynomial::ModSubTruncated;
116    /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
117    ///
118    /// // The quadratic and linear coefficients wrap around.
119    /// assert_eq!(
120    ///     UnsignedPolynomial::<u8>::from_str("x^3+2*x^2+x+5")
121    ///         .unwrap()
122    ///         .mod_sub_truncated(&UnsignedPolynomial::from_str("4*x^2+6*x+2").unwrap(), 3, 7)
123    ///         .to_string(),
124    ///     "5*x^2+2*x+3"
125    /// );
126    /// assert_eq!(
127    ///     UnsignedPolynomial::<u8>::from_str("x^3+2*x^2+x+5")
128    ///         .unwrap()
129    ///         .mod_sub_truncated(&UnsignedPolynomial::from_str("4*x^2+6*x+2").unwrap(), 1, 7)
130    ///         .to_string(),
131    ///     "3"
132    /// );
133    /// ```
134    ///
135    /// This is equivalent to `nmod_poly_sub_series` from `nmod_poly/sub_series.c`, FLINT 3.6.0.
136    fn mod_sub_truncated(mut self, other: &Self, len: u64, m: T) -> Self {
137        assert_reduced(&self, other, m);
138        self.truncate_assign(len);
139        sub_assign_ref(&mut self.coefficients, prefix(&other.coefficients, len), m);
140        self.trim();
141        self
142    }
143}
144
145impl<T: PrimitiveUnsigned> ModSubTruncated<UnsignedPolynomial<T>, T> for &UnsignedPolynomial<T> {
146    type Output = UnsignedPolynomial<T>;
147
148    /// Subtracts one [`UnsignedPolynomial`] from another modulo `m`, keeping only the coefficients
149    /// of $x^i$ for $i$ less than `len`, taking the first by reference and the second by value. The
150    /// coefficients of both must already be reduced modulo `m`.
151    ///
152    /// $$
153    /// f(p, q, n, m) = ((p - q) \bmod x^n) \bmod m.
154    /// $$
155    ///
156    /// The polynomials need not already be truncated: this is the difference of their images modulo
157    /// $x^n$, so only the first `len` coefficients of each are read. Where the second polynomial
158    /// has more of those, they are negated modulo `m`. The difference is trimmed, so when
159    /// coefficients cancel modulo `m` at the top of the kept range, the degree is lower still.
160    ///
161    /// # Worst-case complexity
162    /// $T(n) = O(n)$
163    ///
164    /// $M(n) = O(n)$
165    ///
166    /// where $T$ is time, $M$ is additional memory, and $n$ is the number of coefficients of the
167    /// longer polynomial.
168    ///
169    /// # Panics
170    /// Panics if `m` is 0, or if any coefficient of `self` or `other` is greater than or equal to
171    /// `m`.
172    ///
173    /// # Examples
174    /// ```
175    /// use core::str::FromStr;
176    /// use malachite_base::polynomial::ModSubTruncated;
177    /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
178    ///
179    /// // The quadratic and linear coefficients wrap around.
180    /// assert_eq!(
181    ///     (&UnsignedPolynomial::<u8>::from_str("x^3+2*x^2+x+5").unwrap())
182    ///         .mod_sub_truncated(UnsignedPolynomial::from_str("4*x^2+6*x+2").unwrap(), 3, 7)
183    ///         .to_string(),
184    ///     "5*x^2+2*x+3"
185    /// );
186    /// assert_eq!(
187    ///     (&UnsignedPolynomial::<u8>::from_str("x^3+2*x^2+x+5").unwrap())
188    ///         .mod_sub_truncated(UnsignedPolynomial::from_str("4*x^2+6*x+2").unwrap(), 1, 7)
189    ///         .to_string(),
190    ///     "3"
191    /// );
192    /// ```
193    ///
194    /// This is equivalent to `nmod_poly_sub_series` from `nmod_poly/sub_series.c`, FLINT 3.6.0.
195    fn mod_sub_truncated(
196        self,
197        mut other: UnsignedPolynomial<T>,
198        len: u64,
199        m: T,
200    ) -> UnsignedPolynomial<T> {
201        assert_reduced(self, &other, m);
202        other.truncate_assign(len);
203        rsub_assign_ref(&mut other.coefficients, prefix(&self.coefficients, len), m);
204        other.trim();
205        other
206    }
207}
208
209impl<T: PrimitiveUnsigned> ModSubTruncated<&UnsignedPolynomial<T>, T> for &UnsignedPolynomial<T> {
210    type Output = UnsignedPolynomial<T>;
211
212    /// Subtracts one [`UnsignedPolynomial`] from another modulo `m`, keeping only the coefficients
213    /// of $x^i$ for $i$ less than `len`, taking both by reference. The coefficients of both must
214    /// already be reduced modulo `m`.
215    ///
216    /// $$
217    /// f(p, q, n, m) = ((p - q) \bmod x^n) \bmod m.
218    /// $$
219    ///
220    /// The polynomials need not already be truncated: this is the difference of their images modulo
221    /// $x^n$, so only the first `len` coefficients of each are read. Where the second polynomial
222    /// has more of those, they are negated modulo `m`. The difference is trimmed, so when
223    /// coefficients cancel modulo `m` at the top of the kept range, the degree is lower still.
224    ///
225    /// # Worst-case complexity
226    /// $T(n) = O(n)$
227    ///
228    /// $M(n) = O(n)$
229    ///
230    /// where $T$ is time, $M$ is additional memory, and $n$ is the number of coefficients of the
231    /// longer polynomial.
232    ///
233    /// # Panics
234    /// Panics if `m` is 0, or if any coefficient of `self` or `other` is greater than or equal to
235    /// `m`.
236    ///
237    /// # Examples
238    /// ```
239    /// use core::str::FromStr;
240    /// use malachite_base::polynomial::ModSubTruncated;
241    /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
242    ///
243    /// // The quadratic and linear coefficients wrap around.
244    /// assert_eq!(
245    ///     (&UnsignedPolynomial::<u8>::from_str("x^3+2*x^2+x+5").unwrap())
246    ///         .mod_sub_truncated(&UnsignedPolynomial::from_str("4*x^2+6*x+2").unwrap(), 3, 7)
247    ///         .to_string(),
248    ///     "5*x^2+2*x+3"
249    /// );
250    /// assert_eq!(
251    ///     (&UnsignedPolynomial::<u8>::from_str("x^3+2*x^2+x+5").unwrap())
252    ///         .mod_sub_truncated(&UnsignedPolynomial::from_str("4*x^2+6*x+2").unwrap(), 1, 7)
253    ///         .to_string(),
254    ///     "3"
255    /// );
256    /// ```
257    ///
258    /// This is equivalent to `nmod_poly_sub_series` from `nmod_poly/sub_series.c`, FLINT 3.6.0.
259    fn mod_sub_truncated(
260        self,
261        other: &UnsignedPolynomial<T>,
262        len: u64,
263        m: T,
264    ) -> UnsignedPolynomial<T> {
265        assert_reduced(self, other, m);
266        let mut coefficients = prefix(&self.coefficients, len).to_vec();
267        sub_assign_ref(&mut coefficients, prefix(&other.coefficients, len), m);
268        let mut result = UnsignedPolynomial { coefficients };
269        result.trim();
270        result
271    }
272}
273
274impl<T: PrimitiveUnsigned> ModSubTruncatedAssign<Self, T> for UnsignedPolynomial<T> {
275    /// Subtracts an [`UnsignedPolynomial`] from an [`UnsignedPolynomial`] modulo `m` in place,
276    /// keeping only the coefficients of $x^i$ for $i$ less than `len`, taking the second polynomial
277    /// by value. The coefficients of both must already be reduced modulo `m`.
278    ///
279    /// $$
280    /// p \gets ((p - q) \bmod x^n) \bmod m.
281    /// $$
282    ///
283    /// The polynomials need not already be truncated: this is the difference of their images modulo
284    /// $x^n$, so only the first `len` coefficients of each are read. Where the second polynomial
285    /// has more of those, they are negated modulo `m`. The difference is trimmed, so when
286    /// coefficients cancel modulo `m` at the top of the kept range, the degree is lower still.
287    ///
288    /// # Worst-case complexity
289    /// $T(n) = O(n)$
290    ///
291    /// $M(n) = O(n)$
292    ///
293    /// where $T$ is time, $M$ is additional memory, and $n$ is the number of coefficients of the
294    /// longer polynomial.
295    ///
296    /// # Panics
297    /// Panics if `m` is 0, or if any coefficient of `self` or `other` is greater than or equal to
298    /// `m`.
299    ///
300    /// # Examples
301    /// ```
302    /// use core::str::FromStr;
303    /// use malachite_base::polynomial::ModSubTruncatedAssign;
304    /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
305    ///
306    /// // The quadratic and linear coefficients wrap around.
307    /// let mut p = UnsignedPolynomial::<u8>::from_str("x^3+2*x^2+x+5").unwrap();
308    /// p.mod_sub_truncated_assign(UnsignedPolynomial::from_str("4*x^2+6*x+2").unwrap(), 3, 7);
309    /// assert_eq!(p.to_string(), "5*x^2+2*x+3");
310    ///
311    /// let mut p = UnsignedPolynomial::<u8>::from_str("x^3+2*x^2+x+5").unwrap();
312    /// p.mod_sub_truncated_assign(UnsignedPolynomial::from_str("4*x^2+6*x+2").unwrap(), 1, 7);
313    /// assert_eq!(p.to_string(), "3");
314    /// ```
315    ///
316    /// This is equivalent to `nmod_poly_sub_series` from `nmod_poly/sub_series.c`, FLINT 3.6.0.
317    fn mod_sub_truncated_assign(&mut self, mut other: Self, len: u64, m: T) {
318        assert_reduced(self, &other, m);
319        self.truncate_assign(len);
320        other.truncate_assign(len);
321        sub_assign_val(&mut self.coefficients, other.coefficients, m);
322        self.trim();
323    }
324}
325
326impl<T: PrimitiveUnsigned> ModSubTruncatedAssign<&Self, T> for UnsignedPolynomial<T> {
327    /// Subtracts an [`UnsignedPolynomial`] from an [`UnsignedPolynomial`] modulo `m` in place,
328    /// keeping only the coefficients of $x^i$ for $i$ less than `len`, taking the second polynomial
329    /// by reference. The coefficients of both must already be reduced modulo `m`.
330    ///
331    /// $$
332    /// p \gets ((p - q) \bmod x^n) \bmod m.
333    /// $$
334    ///
335    /// The polynomials need not already be truncated: this is the difference of their images modulo
336    /// $x^n$, so only the first `len` coefficients of each are read. Where the second polynomial
337    /// has more of those, they are negated modulo `m`. The difference is trimmed, so when
338    /// coefficients cancel modulo `m` at the top of the kept range, the degree is lower still.
339    ///
340    /// # Worst-case complexity
341    /// $T(n) = O(n)$
342    ///
343    /// $M(n) = O(n)$
344    ///
345    /// where $T$ is time, $M$ is additional memory, and $n$ is the number of coefficients of the
346    /// longer polynomial.
347    ///
348    /// # Panics
349    /// Panics if `m` is 0, or if any coefficient of `self` or `other` is greater than or equal to
350    /// `m`.
351    ///
352    /// # Examples
353    /// ```
354    /// use core::str::FromStr;
355    /// use malachite_base::polynomial::ModSubTruncatedAssign;
356    /// use malachite_base::unsigned_polynomial::UnsignedPolynomial;
357    ///
358    /// // The quadratic and linear coefficients wrap around.
359    /// let mut p = UnsignedPolynomial::<u8>::from_str("x^3+2*x^2+x+5").unwrap();
360    /// p.mod_sub_truncated_assign(&UnsignedPolynomial::from_str("4*x^2+6*x+2").unwrap(), 3, 7);
361    /// assert_eq!(p.to_string(), "5*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_sub_truncated_assign(&UnsignedPolynomial::from_str("4*x^2+6*x+2").unwrap(), 1, 7);
365    /// assert_eq!(p.to_string(), "3");
366    /// ```
367    ///
368    /// This is equivalent to `nmod_poly_sub_series` from `nmod_poly/sub_series.c`, FLINT 3.6.0.
369    fn mod_sub_truncated_assign(&mut self, other: &Self, len: u64, m: T) {
370        assert_reduced(self, other, m);
371        self.truncate_assign(len);
372        sub_assign_ref(&mut self.coefficients, prefix(&other.coefficients, len), m);
373        self.trim();
374    }
375}