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}