malachite_nz/integer_vector/arithmetic/add_mul.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_vector::IntegerVector;
11use crate::natural::Natural;
12use malachite_base::num::arithmetic::traits::{AddMul, AddMulAssign};
13use malachite_base::num::basic::traits::{One, Zero};
14
15fn assert_same_dimension(v: &IntegerVector, w: &IntegerVector) {
16 assert_eq!(
17 v.elements.len(),
18 w.elements.len(),
19 "cannot add-multiply vectors of different dimensions"
20 );
21}
22
23impl AddMul<Self, Integer> for IntegerVector {
24 type Output = Self;
25
26 /// Adds the product of an [`IntegerVector`] and an [`Integer`] to an [`IntegerVector`], taking
27 /// all three by value.
28 ///
29 /// The operation is taken element by element, so the result has the same dimension as the
30 /// vectors. Like FLINT's, this special-cases multiplication by 0, 1, and $-1$.
31 ///
32 /// $$
33 /// f(v, w, c) = v + cw = (v_0 + cw_0, v_1 + cw_1, \ldots, v_{n-1} + cw_{n-1}).
34 /// $$
35 ///
36 /// # Worst-case complexity
37 /// $T(n, m) = O(m + n \log n \log\log n)$
38 ///
39 /// $M(n) = O(n \log n)$
40 ///
41 /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits of the elements
42 /// of `w` and of `c`, and $m$ is the total number of bits of the elements of `self`.
43 ///
44 /// # Panics
45 /// Panics if `self` and `w` have different dimensions.
46 ///
47 /// # Examples
48 /// See [here](super::add_mul#add_mul).
49 ///
50 /// This is equivalent to `_fmpz_vec_scalar_addmul_fmpz` from `fmpz_vec/scalar.c`, FLINT 3.6.0.
51 #[inline]
52 fn add_mul(mut self, w: Self, c: Integer) -> Self {
53 self.add_mul_assign(w, &c);
54 self
55 }
56}
57
58impl<'b> AddMul<Self, &'b Integer> for IntegerVector {
59 type Output = Self;
60
61 /// Adds the product of an [`IntegerVector`] and an [`Integer`] to an [`IntegerVector`], taking
62 /// the first vector by value, the second vector by value, and the scalar by reference.
63 ///
64 /// See the documentation for the [`AddMul`] implementation that takes all three by value for
65 /// details.
66 ///
67 /// # Worst-case complexity
68 /// $T(n, m) = O(m + n \log n \log\log n)$
69 ///
70 /// $M(n) = O(n \log n)$
71 ///
72 /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits of the elements
73 /// of `w` and of `c`, and $m$ is the total number of bits of the elements of `self`.
74 ///
75 /// # Panics
76 /// Panics if `self` and `w` have different dimensions.
77 ///
78 /// # Examples
79 /// See [here](super::add_mul#add_mul).
80 ///
81 /// This is equivalent to `_fmpz_vec_scalar_addmul_fmpz` from `fmpz_vec/scalar.c`, FLINT 3.6.0.
82 #[inline]
83 fn add_mul(mut self, w: Self, c: &'b Integer) -> Self {
84 self.add_mul_assign(w, c);
85 self
86 }
87}
88
89impl<'a> AddMul<&'a Self, Integer> for IntegerVector {
90 type Output = Self;
91
92 /// Adds the product of an [`IntegerVector`] and an [`Integer`] to an [`IntegerVector`], taking
93 /// the first vector by value, the second vector by reference, and the scalar by value.
94 ///
95 /// See the documentation for the [`AddMul`] implementation that takes all three by value for
96 /// details.
97 ///
98 /// # Worst-case complexity
99 /// $T(n, m) = O(m + n \log n \log\log n)$
100 ///
101 /// $M(n) = O(n \log n)$
102 ///
103 /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits of the elements
104 /// of `w` and of `c`, and $m$ is the total number of bits of the elements of `self`.
105 ///
106 /// # Panics
107 /// Panics if `self` and `w` have different dimensions.
108 ///
109 /// # Examples
110 /// See [here](super::add_mul#add_mul).
111 ///
112 /// This is equivalent to `_fmpz_vec_scalar_addmul_fmpz` from `fmpz_vec/scalar.c`, FLINT 3.6.0.
113 #[inline]
114 fn add_mul(mut self, w: &'a Self, c: Integer) -> Self {
115 self.add_mul_assign(w, &c);
116 self
117 }
118}
119
120impl<'a, 'b> AddMul<&'a Self, &'b Integer> for IntegerVector {
121 type Output = Self;
122
123 /// Adds the product of an [`IntegerVector`] and an [`Integer`] to an [`IntegerVector`], taking
124 /// the first vector by value, the second vector by reference, and the scalar by reference.
125 ///
126 /// See the documentation for the [`AddMul`] implementation that takes all three by value for
127 /// details.
128 ///
129 /// # Worst-case complexity
130 /// $T(n, m) = O(m + n \log n \log\log n)$
131 ///
132 /// $M(n) = O(n \log n)$
133 ///
134 /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits of the elements
135 /// of `w` and of `c`, and $m$ is the total number of bits of the elements of `self`.
136 ///
137 /// # Panics
138 /// Panics if `self` and `w` have different dimensions.
139 ///
140 /// # Examples
141 /// See [here](super::add_mul#add_mul).
142 ///
143 /// This is equivalent to `_fmpz_vec_scalar_addmul_fmpz` from `fmpz_vec/scalar.c`, FLINT 3.6.0.
144 #[inline]
145 fn add_mul(mut self, w: &'a Self, c: &'b Integer) -> Self {
146 self.add_mul_assign(w, c);
147 self
148 }
149}
150
151impl AddMul<&IntegerVector, &Integer> for &IntegerVector {
152 type Output = IntegerVector;
153
154 /// Adds the product of an [`IntegerVector`] and an [`Integer`] to an [`IntegerVector`], taking
155 /// all three by reference.
156 ///
157 /// See the documentation for the [`AddMul`] implementation that takes all three by value for
158 /// details.
159 ///
160 /// # Worst-case complexity
161 /// $T(n, m) = O(m + n \log n \log\log n)$
162 ///
163 /// $M(n, m) = O(m + n \log n)$
164 ///
165 /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits of the elements
166 /// of `w` and of `c`, and $m$ is the total number of bits of the elements of `self`.
167 ///
168 /// # Panics
169 /// Panics if `self` and `w` have different dimensions.
170 ///
171 /// # Examples
172 /// See [here](super::add_mul#add_mul).
173 ///
174 /// This is equivalent to `_fmpz_vec_scalar_addmul_fmpz` from `fmpz_vec/scalar.c`, FLINT 3.6.0.
175 fn add_mul(self, w: &IntegerVector, c: &Integer) -> IntegerVector {
176 assert_same_dimension(self, w);
177 match *c {
178 integer_zero!() => self.clone(),
179 integer_one!() => self + w,
180 integer_negative_one!() => self - w,
181 _ => IntegerVector {
182 elements: self
183 .elements
184 .iter()
185 .zip(&w.elements)
186 .map(|(x, y)| x.add_mul(y, c))
187 .collect(),
188 },
189 }
190 }
191}
192
193impl AddMulAssign<Self, Integer> for IntegerVector {
194 /// Adds the product of an [`IntegerVector`] and an [`Integer`] to an [`IntegerVector`] in
195 /// place, taking the vector and the scalar on the right-hand side by value.
196 ///
197 /// The operation is taken element by element. Like FLINT's, this special-cases multiplication
198 /// by 0, 1, and $-1$.
199 ///
200 /// $$
201 /// v \gets v + cw.
202 /// $$
203 ///
204 /// # Worst-case complexity
205 /// $T(n, m) = O(m + n \log n \log\log n)$
206 ///
207 /// $M(n) = O(n \log n)$
208 ///
209 /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits of the elements
210 /// of `w` and of `c`, and $m$ is the total number of bits of the elements of `self`.
211 ///
212 /// # Panics
213 /// Panics if `self` and `w` have different dimensions.
214 ///
215 /// # Examples
216 /// See [here](super::add_mul#add_mul_assign).
217 ///
218 /// This is equivalent to `_fmpz_vec_scalar_addmul_fmpz` from `fmpz_vec/scalar.c`, FLINT 3.6.0.
219 #[inline]
220 fn add_mul_assign(&mut self, w: Self, c: Integer) {
221 self.add_mul_assign(w, &c);
222 }
223}
224
225impl<'b> AddMulAssign<Self, &'b Integer> for IntegerVector {
226 /// Adds the product of an [`IntegerVector`] and an [`Integer`] to an [`IntegerVector`] in
227 /// place, taking the vector on the right-hand side by value and the scalar by reference.
228 ///
229 /// See the documentation for the [`AddMulAssign`] implementation that takes both by value for
230 /// details.
231 ///
232 /// # Worst-case complexity
233 /// $T(n, m) = O(m + n \log n \log\log n)$
234 ///
235 /// $M(n) = O(n \log n)$
236 ///
237 /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits of the elements
238 /// of `w` and of `c`, and $m$ is the total number of bits of the elements of `self`.
239 ///
240 /// # Panics
241 /// Panics if `self` and `w` have different dimensions.
242 ///
243 /// # Examples
244 /// See [here](super::add_mul#add_mul_assign).
245 ///
246 /// This is equivalent to `_fmpz_vec_scalar_addmul_fmpz` from `fmpz_vec/scalar.c`, FLINT 3.6.0.
247 fn add_mul_assign(&mut self, w: Self, c: &'b Integer) {
248 assert_same_dimension(self, &w);
249 match *c {
250 integer_zero!() => {}
251 integer_one!() => *self += w,
252 integer_negative_one!() => *self -= w,
253 _ => {
254 for (x, y) in self.elements.iter_mut().zip(w.elements) {
255 x.add_mul_assign(y, c);
256 }
257 }
258 }
259 }
260}
261
262impl<'a> AddMulAssign<&'a Self, Integer> for IntegerVector {
263 /// Adds the product of an [`IntegerVector`] and an [`Integer`] to an [`IntegerVector`] in
264 /// place, taking the vector on the right-hand side by reference and the scalar by value.
265 ///
266 /// See the documentation for the [`AddMulAssign`] implementation that takes both by value for
267 /// details.
268 ///
269 /// # Worst-case complexity
270 /// $T(n, m) = O(m + n \log n \log\log n)$
271 ///
272 /// $M(n) = O(n \log n)$
273 ///
274 /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits of the elements
275 /// of `w` and of `c`, and $m$ is the total number of bits of the elements of `self`.
276 ///
277 /// # Panics
278 /// Panics if `self` and `w` have different dimensions.
279 ///
280 /// # Examples
281 /// See [here](super::add_mul#add_mul_assign).
282 ///
283 /// This is equivalent to `_fmpz_vec_scalar_addmul_fmpz` from `fmpz_vec/scalar.c`, FLINT 3.6.0.
284 #[inline]
285 fn add_mul_assign(&mut self, w: &'a Self, c: Integer) {
286 self.add_mul_assign(w, &c);
287 }
288}
289
290impl<'a, 'b> AddMulAssign<&'a Self, &'b Integer> for IntegerVector {
291 /// Adds the product of an [`IntegerVector`] and an [`Integer`] to an [`IntegerVector`] in
292 /// place, taking the vector and the scalar on the right-hand side by reference.
293 ///
294 /// See the documentation for the [`AddMulAssign`] implementation that takes both by value for
295 /// details.
296 ///
297 /// # Worst-case complexity
298 /// $T(n, m) = O(m + n \log n \log\log n)$
299 ///
300 /// $M(n) = O(n \log n)$
301 ///
302 /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits of the elements
303 /// of `w` and of `c`, and $m$ is the total number of bits of the elements of `self`.
304 ///
305 /// # Panics
306 /// Panics if `self` and `w` have different dimensions.
307 ///
308 /// # Examples
309 /// See [here](super::add_mul#add_mul_assign).
310 ///
311 /// This is equivalent to `_fmpz_vec_scalar_addmul_fmpz` from `fmpz_vec/scalar.c`, FLINT 3.6.0.
312 fn add_mul_assign(&mut self, w: &'a Self, c: &'b Integer) {
313 assert_same_dimension(self, w);
314 match *c {
315 integer_zero!() => {}
316 integer_one!() => *self += w,
317 integer_negative_one!() => *self -= w,
318 _ => {
319 for (x, y) in self.elements.iter_mut().zip(&w.elements) {
320 x.add_mul_assign(y, c);
321 }
322 }
323 }
324 }
325}