Skip to main content

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}