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}