Skip to main content

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