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}