Skip to main content

malachite_nz/integer_polynomial/arithmetic/
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::integer::Integer;
10use crate::integer_polynomial::IntegerPolynomial;
11use alloc::vec::Vec;
12use core::cmp::min;
13use core::mem::swap;
14use core::ops::{Sub, SubAssign};
15use malachite_base::num::arithmetic::traits::NegAssign;
16
17// Subtracts `ys` from `xs`, negating the coefficients of `ys` past the end of `xs`.
18pub(crate) fn sub_assign_ref(xs: &mut Vec<Integer>, ys: &[Integer]) {
19    let common = min(xs.len(), ys.len());
20    for (x, y) in xs.iter_mut().zip(&ys[..common]) {
21        *x -= y;
22    }
23    if ys.len() > common {
24        xs.extend(ys[common..].iter().map(|y| -y));
25    }
26}
27
28// Subtracts `ys` from `xs`, reusing whichever of the two is longer: when `ys` is, it is negated in
29// place and `xs` is added to it.
30pub(crate) fn sub_assign_val(xs: &mut Vec<Integer>, mut ys: Vec<Integer>) {
31    if ys.len() > xs.len() {
32        for y in &mut ys {
33            y.neg_assign();
34        }
35        swap(xs, &mut ys);
36        for (x, y) in xs.iter_mut().zip(ys) {
37            *x += y;
38        }
39    } else {
40        for (x, y) in xs.iter_mut().zip(ys) {
41            *x -= y;
42        }
43    }
44}
45
46// Replaces `ys` with `xs - ys`, reusing the storage of `ys`.
47pub(crate) fn rsub_assign_ref(ys: &mut Vec<Integer>, xs: &[Integer]) {
48    for y in ys.iter_mut() {
49        y.neg_assign();
50    }
51    let common = min(xs.len(), ys.len());
52    for (y, x) in ys.iter_mut().zip(&xs[..common]) {
53        *y += x;
54    }
55    if xs.len() > common {
56        ys.extend_from_slice(&xs[common..]);
57    }
58}
59
60impl Sub<Self> for IntegerPolynomial {
61    type Output = Self;
62
63    /// Subtracts two [`IntegerPolynomial`]s, taking both by value.
64    ///
65    /// $$
66    /// f(p, q) = p - q.
67    /// $$
68    ///
69    /// When the two polynomials have the same degree, their leading coefficients can cancel, and
70    /// then the degree of the difference is lower.
71    ///
72    /// # Worst-case complexity
73    /// $T(n) = O(n)$
74    ///
75    /// $M(n) = O(n)$
76    ///
77    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
78    /// coefficients of both polynomials.
79    ///
80    /// # Examples
81    /// ```
82    /// use core::str::FromStr;
83    /// use malachite_nz::integer_polynomial::IntegerPolynomial;
84    ///
85    /// assert_eq!(
86    ///     (IntegerPolynomial::from_str("x^2+x").unwrap()
87    ///         - IntegerPolynomial::from_str("x^2-1").unwrap())
88    ///     .to_string(),
89    ///     "x+1"
90    /// );
91    /// // A longer subtrahend is negated.
92    /// assert_eq!(
93    ///     (IntegerPolynomial::from_str("3*x+1").unwrap()
94    ///         - IntegerPolynomial::from_str("x^2").unwrap())
95    ///     .to_string(),
96    ///     "-x^2+3*x+1"
97    /// );
98    /// ```
99    ///
100    /// This is equivalent to `fmpz_poly_sub` from `fmpz_poly/sub.c`, FLINT 3.6.0.
101    fn sub(mut self, other: Self) -> Self {
102        sub_assign_val(&mut self.coefficients, other.coefficients);
103        self.trim();
104        self
105    }
106}
107
108impl Sub<&Self> for IntegerPolynomial {
109    type Output = Self;
110
111    /// Subtracts two [`IntegerPolynomial`]s, taking the first by value and the second by reference.
112    ///
113    /// $$
114    /// f(p, q) = p - q.
115    /// $$
116    ///
117    /// When the two polynomials have the same degree, their leading coefficients can cancel, and
118    /// then the degree of the difference is lower.
119    ///
120    /// # Worst-case complexity
121    /// $T(n) = O(n)$
122    ///
123    /// $M(n) = O(n)$
124    ///
125    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
126    /// coefficients of both polynomials.
127    ///
128    /// # Examples
129    /// ```
130    /// use core::str::FromStr;
131    /// use malachite_nz::integer_polynomial::IntegerPolynomial;
132    ///
133    /// assert_eq!(
134    ///     (IntegerPolynomial::from_str("x^2+x").unwrap()
135    ///         - &IntegerPolynomial::from_str("x^2-1").unwrap())
136    ///         .to_string(),
137    ///     "x+1"
138    /// );
139    /// // A longer subtrahend is negated.
140    /// assert_eq!(
141    ///     (IntegerPolynomial::from_str("3*x+1").unwrap()
142    ///         - &IntegerPolynomial::from_str("x^2").unwrap())
143    ///         .to_string(),
144    ///     "-x^2+3*x+1"
145    /// );
146    /// ```
147    ///
148    /// This is equivalent to `fmpz_poly_sub` from `fmpz_poly/sub.c`, FLINT 3.6.0.
149    fn sub(mut self, other: &Self) -> Self {
150        sub_assign_ref(&mut self.coefficients, &other.coefficients);
151        self.trim();
152        self
153    }
154}
155
156impl Sub<IntegerPolynomial> for &IntegerPolynomial {
157    type Output = IntegerPolynomial;
158
159    /// Subtracts two [`IntegerPolynomial`]s, taking the first by reference and the second by value.
160    ///
161    /// $$
162    /// f(p, q) = p - q.
163    /// $$
164    ///
165    /// When the two polynomials have the same degree, their leading coefficients can cancel, and
166    /// then the degree of the difference is lower.
167    ///
168    /// # Worst-case complexity
169    /// $T(n) = O(n)$
170    ///
171    /// $M(n) = O(n)$
172    ///
173    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
174    /// coefficients of both polynomials.
175    ///
176    /// # Examples
177    /// ```
178    /// use core::str::FromStr;
179    /// use malachite_nz::integer_polynomial::IntegerPolynomial;
180    ///
181    /// assert_eq!(
182    ///     (&IntegerPolynomial::from_str("x^2+x").unwrap()
183    ///         - IntegerPolynomial::from_str("x^2-1").unwrap())
184    ///     .to_string(),
185    ///     "x+1"
186    /// );
187    /// // A longer subtrahend is negated.
188    /// assert_eq!(
189    ///     (&IntegerPolynomial::from_str("3*x+1").unwrap()
190    ///         - IntegerPolynomial::from_str("x^2").unwrap())
191    ///     .to_string(),
192    ///     "-x^2+3*x+1"
193    /// );
194    /// ```
195    ///
196    /// This is equivalent to `fmpz_poly_sub` from `fmpz_poly/sub.c`, FLINT 3.6.0.
197    fn sub(self, other: IntegerPolynomial) -> IntegerPolynomial {
198        let mut other = other;
199        rsub_assign_ref(&mut other.coefficients, &self.coefficients);
200        other.trim();
201        other
202    }
203}
204
205impl Sub<&IntegerPolynomial> for &IntegerPolynomial {
206    type Output = IntegerPolynomial;
207
208    /// Subtracts two [`IntegerPolynomial`]s, taking both by reference.
209    ///
210    /// $$
211    /// f(p, q) = p - q.
212    /// $$
213    ///
214    /// When the two polynomials have the same degree, their leading coefficients can cancel, and
215    /// then the degree of the difference is lower.
216    ///
217    /// # Worst-case complexity
218    /// $T(n) = O(n)$
219    ///
220    /// $M(n) = O(n)$
221    ///
222    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
223    /// coefficients of both polynomials.
224    ///
225    /// # Examples
226    /// ```
227    /// use core::str::FromStr;
228    /// use malachite_nz::integer_polynomial::IntegerPolynomial;
229    ///
230    /// assert_eq!(
231    ///     (&IntegerPolynomial::from_str("x^2+x").unwrap()
232    ///         - &IntegerPolynomial::from_str("x^2-1").unwrap())
233    ///         .to_string(),
234    ///     "x+1"
235    /// );
236    /// // A longer subtrahend is negated.
237    /// assert_eq!(
238    ///     (&IntegerPolynomial::from_str("3*x+1").unwrap()
239    ///         - &IntegerPolynomial::from_str("x^2").unwrap())
240    ///         .to_string(),
241    ///     "-x^2+3*x+1"
242    /// );
243    /// ```
244    ///
245    /// This is equivalent to `fmpz_poly_sub` from `fmpz_poly/sub.c`, FLINT 3.6.0.
246    fn sub(self, other: &IntegerPolynomial) -> IntegerPolynomial {
247        let mut difference = IntegerPolynomial {
248            coefficients: self.coefficients.clone(),
249        };
250        sub_assign_ref(&mut difference.coefficients, &other.coefficients);
251        difference.trim();
252        difference
253    }
254}
255
256impl SubAssign<Self> for IntegerPolynomial {
257    /// Subtracts another [`IntegerPolynomial`] from an [`IntegerPolynomial`] in place, taking the
258    /// right-hand side by value.
259    ///
260    /// $$
261    /// p \gets p - q.
262    /// $$
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 total number of bits of the
270    /// coefficients of both polynomials.
271    ///
272    /// # Examples
273    /// ```
274    /// use core::str::FromStr;
275    /// use malachite_nz::integer_polynomial::IntegerPolynomial;
276    ///
277    /// let mut p = IntegerPolynomial::from_str("x^2+x").unwrap();
278    /// p -= IntegerPolynomial::from_str("x^2-1").unwrap();
279    /// assert_eq!(p.to_string(), "x+1");
280    /// ```
281    fn sub_assign(&mut self, other: Self) {
282        sub_assign_val(&mut self.coefficients, other.coefficients);
283        self.trim();
284    }
285}
286
287impl SubAssign<&Self> for IntegerPolynomial {
288    /// Subtracts another [`IntegerPolynomial`] from an [`IntegerPolynomial`] in place, taking the
289    /// right-hand side by reference.
290    ///
291    /// $$
292    /// p \gets p - q.
293    /// $$
294    ///
295    /// # Worst-case complexity
296    /// $T(n) = O(n)$
297    ///
298    /// $M(n) = O(n)$
299    ///
300    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
301    /// coefficients of both polynomials.
302    ///
303    /// # Examples
304    /// ```
305    /// use core::str::FromStr;
306    /// use malachite_nz::integer_polynomial::IntegerPolynomial;
307    ///
308    /// let mut p = IntegerPolynomial::from_str("x^2+x").unwrap();
309    /// p -= &IntegerPolynomial::from_str("x^2-1").unwrap();
310    /// assert_eq!(p.to_string(), "x+1");
311    /// ```
312    fn sub_assign(&mut self, other: &Self) {
313        sub_assign_ref(&mut self.coefficients, &other.coefficients);
314        self.trim();
315    }
316}