Skip to main content

malachite_nz/integer_polynomial/arithmetic/
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::integer::Integer;
10use crate::integer_polynomial::IntegerPolynomial;
11use crate::integer_polynomial::arithmetic::sub::{rsub_assign_ref, sub_assign_ref, sub_assign_val};
12use malachite_base::polynomial::{Polynomial, SubTruncated, SubTruncatedAssign};
13
14// The first `len` elements of `xs`, or all of them if there are fewer.
15fn prefix(xs: &[Integer], len: u64) -> &[Integer] {
16    &xs[..usize::try_from(len).map_or(xs.len(), |len| len.min(xs.len()))]
17}
18
19impl SubTruncated<Self> for IntegerPolynomial {
20    type Output = Self;
21
22    /// Subtracts one [`IntegerPolynomial`] from another, keeping only the coefficients of $x^i$ for
23    /// $i$ less than `len`, taking both by value.
24    ///
25    /// $$
26    /// f(p, q, n) = (p - q) \bmod x^n.
27    /// $$
28    ///
29    /// The polynomials need not already be truncated: this is the difference of their images modulo
30    /// $x^n$, so only the first `len` coefficients of each are read. The difference is trimmed, so
31    /// when coefficients cancel at the top of the kept range, the degree is lower still.
32    ///
33    /// # Worst-case complexity
34    /// $T(n) = O(n)$
35    ///
36    /// $M(n) = O(n)$
37    ///
38    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
39    /// first `len` coefficients of both polynomials.
40    ///
41    /// # Examples
42    /// ```
43    /// use core::str::FromStr;
44    /// use malachite_base::polynomial::SubTruncated;
45    /// use malachite_nz::integer_polynomial::IntegerPolynomial;
46    ///
47    /// assert_eq!(
48    ///     IntegerPolynomial::from_str("x^3+2*x^2-x+5")
49    ///         .unwrap()
50    ///         .sub_truncated(IntegerPolynomial::from_str("4*x^2+x-2").unwrap(), 3)
51    ///         .to_string(),
52    ///     "-2*x^2-2*x+7"
53    /// );
54    /// // The quadratic and linear coefficients cancel.
55    /// assert_eq!(
56    ///     IntegerPolynomial::from_str("x^3+2*x^2-x+5")
57    ///         .unwrap()
58    ///         .sub_truncated(IntegerPolynomial::from_str("2*x^2-x+3").unwrap(), 3)
59    ///         .to_string(),
60    ///     "2"
61    /// );
62    /// ```
63    ///
64    /// This is equivalent to `fmpz_poly_sub_series` from `fmpz_poly/sub_series.c`, FLINT 3.6.0.
65    fn sub_truncated(mut self, mut other: Self, len: u64) -> Self {
66        self.truncate_assign(len);
67        other.truncate_assign(len);
68        sub_assign_val(&mut self.coefficients, other.coefficients);
69        self.trim();
70        self
71    }
72}
73
74impl SubTruncated<&Self> for IntegerPolynomial {
75    type Output = Self;
76
77    /// Subtracts one [`IntegerPolynomial`] from another, keeping only the coefficients of $x^i$ for
78    /// $i$ less than `len`, taking the first by value and the second by reference.
79    ///
80    /// $$
81    /// f(p, q, n) = (p - q) \bmod x^n.
82    /// $$
83    ///
84    /// The polynomials need not already be truncated: this is the difference of their images modulo
85    /// $x^n$, so only the first `len` coefficients of each are read. The difference is trimmed, so
86    /// when coefficients cancel at the top of the kept range, the degree is lower still.
87    ///
88    /// # Worst-case complexity
89    /// $T(n) = O(n)$
90    ///
91    /// $M(n) = O(n)$
92    ///
93    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
94    /// first `len` coefficients of both polynomials.
95    ///
96    /// # Examples
97    /// ```
98    /// use core::str::FromStr;
99    /// use malachite_base::polynomial::SubTruncated;
100    /// use malachite_nz::integer_polynomial::IntegerPolynomial;
101    ///
102    /// assert_eq!(
103    ///     IntegerPolynomial::from_str("x^3+2*x^2-x+5")
104    ///         .unwrap()
105    ///         .sub_truncated(&IntegerPolynomial::from_str("4*x^2+x-2").unwrap(), 3)
106    ///         .to_string(),
107    ///     "-2*x^2-2*x+7"
108    /// );
109    /// // The quadratic and linear coefficients cancel.
110    /// assert_eq!(
111    ///     IntegerPolynomial::from_str("x^3+2*x^2-x+5")
112    ///         .unwrap()
113    ///         .sub_truncated(&IntegerPolynomial::from_str("2*x^2-x+3").unwrap(), 3)
114    ///         .to_string(),
115    ///     "2"
116    /// );
117    /// ```
118    ///
119    /// This is equivalent to `fmpz_poly_sub_series` from `fmpz_poly/sub_series.c`, FLINT 3.6.0.
120    fn sub_truncated(mut self, other: &Self, len: u64) -> Self {
121        self.truncate_assign(len);
122        sub_assign_ref(&mut self.coefficients, prefix(&other.coefficients, len));
123        self.trim();
124        self
125    }
126}
127
128impl SubTruncated<IntegerPolynomial> for &IntegerPolynomial {
129    type Output = IntegerPolynomial;
130
131    /// Subtracts one [`IntegerPolynomial`] from another, keeping only the coefficients of $x^i$ for
132    /// $i$ less than `len`, taking the first by reference and the second by value.
133    ///
134    /// $$
135    /// f(p, q, n) = (p - q) \bmod x^n.
136    /// $$
137    ///
138    /// The polynomials need not already be truncated: this is the difference of their images modulo
139    /// $x^n$, so only the first `len` coefficients of each are read. The difference is trimmed, so
140    /// when coefficients cancel at the top of the kept range, the degree is lower still.
141    ///
142    /// # Worst-case complexity
143    /// $T(n) = O(n)$
144    ///
145    /// $M(n) = O(n)$
146    ///
147    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
148    /// first `len` coefficients of both polynomials.
149    ///
150    /// # Examples
151    /// ```
152    /// use core::str::FromStr;
153    /// use malachite_base::polynomial::SubTruncated;
154    /// use malachite_nz::integer_polynomial::IntegerPolynomial;
155    ///
156    /// assert_eq!(
157    ///     (&IntegerPolynomial::from_str("x^3+2*x^2-x+5").unwrap())
158    ///         .sub_truncated(IntegerPolynomial::from_str("4*x^2+x-2").unwrap(), 3)
159    ///         .to_string(),
160    ///     "-2*x^2-2*x+7"
161    /// );
162    /// // The quadratic and linear coefficients cancel.
163    /// assert_eq!(
164    ///     (&IntegerPolynomial::from_str("x^3+2*x^2-x+5").unwrap())
165    ///         .sub_truncated(IntegerPolynomial::from_str("2*x^2-x+3").unwrap(), 3)
166    ///         .to_string(),
167    ///     "2"
168    /// );
169    /// ```
170    ///
171    /// This is equivalent to `fmpz_poly_sub_series` from `fmpz_poly/sub_series.c`, FLINT 3.6.0.
172    fn sub_truncated(self, mut other: IntegerPolynomial, len: u64) -> IntegerPolynomial {
173        other.truncate_assign(len);
174        rsub_assign_ref(&mut other.coefficients, prefix(&self.coefficients, len));
175        other.trim();
176        other
177    }
178}
179
180impl SubTruncated<&IntegerPolynomial> for &IntegerPolynomial {
181    type Output = IntegerPolynomial;
182
183    /// Subtracts one [`IntegerPolynomial`] from another, keeping only the coefficients of $x^i$ for
184    /// $i$ less than `len`, taking both by reference.
185    ///
186    /// $$
187    /// f(p, q, n) = (p - q) \bmod x^n.
188    /// $$
189    ///
190    /// The polynomials need not already be truncated: this is the difference of their images modulo
191    /// $x^n$, so only the first `len` coefficients of each are read. The difference is trimmed, so
192    /// when coefficients cancel at the top of the kept range, the degree is lower still.
193    ///
194    /// # Worst-case complexity
195    /// $T(n) = O(n)$
196    ///
197    /// $M(n) = O(n)$
198    ///
199    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
200    /// first `len` coefficients of both polynomials.
201    ///
202    /// # Examples
203    /// ```
204    /// use core::str::FromStr;
205    /// use malachite_base::polynomial::SubTruncated;
206    /// use malachite_nz::integer_polynomial::IntegerPolynomial;
207    ///
208    /// assert_eq!(
209    ///     (&IntegerPolynomial::from_str("x^3+2*x^2-x+5").unwrap())
210    ///         .sub_truncated(&IntegerPolynomial::from_str("4*x^2+x-2").unwrap(), 3)
211    ///         .to_string(),
212    ///     "-2*x^2-2*x+7"
213    /// );
214    /// // The quadratic and linear coefficients cancel.
215    /// assert_eq!(
216    ///     (&IntegerPolynomial::from_str("x^3+2*x^2-x+5").unwrap())
217    ///         .sub_truncated(&IntegerPolynomial::from_str("2*x^2-x+3").unwrap(), 3)
218    ///         .to_string(),
219    ///     "2"
220    /// );
221    /// ```
222    ///
223    /// This is equivalent to `fmpz_poly_sub_series` from `fmpz_poly/sub_series.c`, FLINT 3.6.0.
224    fn sub_truncated(self, other: &IntegerPolynomial, len: u64) -> IntegerPolynomial {
225        let mut coefficients = prefix(&self.coefficients, len).to_vec();
226        sub_assign_ref(&mut coefficients, prefix(&other.coefficients, len));
227        IntegerPolynomial::from_coefficients_asc(coefficients)
228    }
229}
230
231impl SubTruncatedAssign<Self> for IntegerPolynomial {
232    /// Subtracts an [`IntegerPolynomial`] from an [`IntegerPolynomial`] in place, keeping only the
233    /// coefficients of $x^i$ for $i$ less than `len`, taking the second polynomial by value.
234    ///
235    /// $$
236    /// p \gets (p - q) \bmod x^n.
237    /// $$
238    ///
239    /// The polynomials need not already be truncated: this is the difference of their images modulo
240    /// $x^n$, so only the first `len` coefficients of each are read. The difference is trimmed, so
241    /// when coefficients cancel at the top of the kept range, the degree is lower still.
242    ///
243    /// # Worst-case complexity
244    /// $T(n) = O(n)$
245    ///
246    /// $M(n) = O(n)$
247    ///
248    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
249    /// first `len` coefficients of both polynomials.
250    ///
251    /// # Examples
252    /// ```
253    /// use core::str::FromStr;
254    /// use malachite_base::polynomial::SubTruncatedAssign;
255    /// use malachite_nz::integer_polynomial::IntegerPolynomial;
256    ///
257    /// let mut p = IntegerPolynomial::from_str("x^3+2*x^2-x+5").unwrap();
258    /// p.sub_truncated_assign(IntegerPolynomial::from_str("4*x^2+x-2").unwrap(), 3);
259    /// assert_eq!(p.to_string(), "-2*x^2-2*x+7");
260    ///
261    /// // The quadratic and linear coefficients cancel.
262    /// let mut p = IntegerPolynomial::from_str("x^3+2*x^2-x+5").unwrap();
263    /// p.sub_truncated_assign(IntegerPolynomial::from_str("2*x^2-x+3").unwrap(), 3);
264    /// assert_eq!(p.to_string(), "2");
265    /// ```
266    ///
267    /// This is equivalent to `fmpz_poly_sub_series` from `fmpz_poly/sub_series.c`, FLINT 3.6.0.
268    fn sub_truncated_assign(&mut self, mut other: Self, len: u64) {
269        self.truncate_assign(len);
270        other.truncate_assign(len);
271        sub_assign_val(&mut self.coefficients, other.coefficients);
272        self.trim();
273    }
274}
275
276impl SubTruncatedAssign<&Self> for IntegerPolynomial {
277    /// Subtracts an [`IntegerPolynomial`] from an [`IntegerPolynomial`] in place, keeping only the
278    /// coefficients of $x^i$ for $i$ less than `len`, taking the second polynomial by reference.
279    ///
280    /// $$
281    /// p \gets (p - q) \bmod x^n.
282    /// $$
283    ///
284    /// The polynomials need not already be truncated: this is the difference of their images modulo
285    /// $x^n$, so only the first `len` coefficients of each are read. The difference is trimmed, so
286    /// when coefficients cancel 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 total number of bits of the
294    /// first `len` coefficients of both polynomials.
295    ///
296    /// # Examples
297    /// ```
298    /// use core::str::FromStr;
299    /// use malachite_base::polynomial::SubTruncatedAssign;
300    /// use malachite_nz::integer_polynomial::IntegerPolynomial;
301    ///
302    /// let mut p = IntegerPolynomial::from_str("x^3+2*x^2-x+5").unwrap();
303    /// p.sub_truncated_assign(&IntegerPolynomial::from_str("4*x^2+x-2").unwrap(), 3);
304    /// assert_eq!(p.to_string(), "-2*x^2-2*x+7");
305    ///
306    /// // The quadratic and linear coefficients cancel.
307    /// let mut p = IntegerPolynomial::from_str("x^3+2*x^2-x+5").unwrap();
308    /// p.sub_truncated_assign(&IntegerPolynomial::from_str("2*x^2-x+3").unwrap(), 3);
309    /// assert_eq!(p.to_string(), "2");
310    /// ```
311    ///
312    /// This is equivalent to `fmpz_poly_sub_series` from `fmpz_poly/sub_series.c`, FLINT 3.6.0.
313    fn sub_truncated_assign(&mut self, other: &Self, len: u64) {
314        self.truncate_assign(len);
315        sub_assign_ref(&mut self.coefficients, prefix(&other.coefficients, len));
316        self.trim();
317    }
318}