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