malachite_base/unsigned_vector/arithmetic/mod_power_of_2_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::num::arithmetic::traits::{ModPowerOf2Add, ModPowerOf2AddAssign, ModPowerOf2IsReduced};
10use crate::num::basic::unsigneds::PrimitiveUnsigned;
11use crate::unsigned_vector::UnsignedVector;
12
13fn assert_reduced<T: PrimitiveUnsigned>(v: &UnsignedVector<T>, w: &UnsignedVector<T>, pow: u64) {
14 assert!(
15 pow <= T::WIDTH,
16 "pow must be at most T::WIDTH, but it is {pow}"
17 );
18 assert_eq!(
19 v.elements.len(),
20 w.elements.len(),
21 "cannot add vectors of different dimensions"
22 );
23 assert!(
24 v.mod_power_of_2_is_reduced(pow),
25 "self must be reduced mod 2^pow, but {v} has an element >= 2^{pow}"
26 );
27 assert!(
28 w.mod_power_of_2_is_reduced(pow),
29 "other must be reduced mod 2^pow, but {w} has an element >= 2^{pow}"
30 );
31}
32
33impl<T: PrimitiveUnsigned> ModPowerOf2Add<Self> for UnsignedVector<T> {
34 type Output = Self;
35
36 /// Adds two [`UnsignedVector`]s modulo $2^k$, taking both by value. The elements of both must
37 /// already be reduced modulo $2^k$.
38 ///
39 /// The sum is taken element by element, each reduced modulo $2^k$, so the result has the same
40 /// dimension as the summands.
41 ///
42 /// $$
43 /// f(v, w, k) = v + w \bmod 2^k.
44 /// $$
45 ///
46 /// # Worst-case complexity
47 /// $T(n) = O(n)$
48 ///
49 /// $M(n) = O(1)$
50 ///
51 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
52 ///
53 /// # Panics
54 /// Panics if `pow` is greater than `T::WIDTH`, if `self` and `other` have different dimensions,
55 /// or if any element of either is greater than or equal to $2^k$.
56 ///
57 /// # Examples
58 /// ```
59 /// use core::str::FromStr;
60 /// use malachite_base::num::arithmetic::traits::ModPowerOf2Add;
61 /// use malachite_base::unsigned_vector::UnsignedVector;
62 ///
63 /// let v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
64 /// let w = UnsignedVector::<u8>::from_str("(4, 7, 0)").unwrap();
65 /// assert_eq!(v.mod_power_of_2_add(w, 3).to_string(), "(1, 0, 3)");
66 /// ```
67 ///
68 /// This is equivalent to `_nmod_vec_add` from `nmod_vec/add.c`, FLINT 3.6.0, with the modulus
69 /// $2^k$.
70 #[inline]
71 fn mod_power_of_2_add(mut self, other: Self, pow: u64) -> Self {
72 self.mod_power_of_2_add_assign(other, pow);
73 self
74 }
75}
76
77impl<T: PrimitiveUnsigned> ModPowerOf2Add<&Self> for UnsignedVector<T> {
78 type Output = Self;
79
80 /// Adds two [`UnsignedVector`]s modulo $2^k$, taking the first by value and the second by
81 /// reference. The elements of both must already be reduced modulo $2^k$.
82 ///
83 /// The sum is taken element by element, each reduced modulo $2^k$, so the result has the same
84 /// dimension as the summands.
85 ///
86 /// $$
87 /// f(v, w, k) = v + w \bmod 2^k.
88 /// $$
89 ///
90 /// # Worst-case complexity
91 /// $T(n) = O(n)$
92 ///
93 /// $M(n) = O(1)$
94 ///
95 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
96 ///
97 /// # Panics
98 /// Panics if `pow` is greater than `T::WIDTH`, if `self` and `other` have different dimensions,
99 /// or if any element of either is greater than or equal to $2^k$.
100 ///
101 /// # Examples
102 /// ```
103 /// use core::str::FromStr;
104 /// use malachite_base::num::arithmetic::traits::ModPowerOf2Add;
105 /// use malachite_base::unsigned_vector::UnsignedVector;
106 ///
107 /// let v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
108 /// let w = UnsignedVector::<u8>::from_str("(4, 7, 0)").unwrap();
109 /// assert_eq!(v.mod_power_of_2_add(&w, 3).to_string(), "(1, 0, 3)");
110 /// ```
111 ///
112 /// This is equivalent to `_nmod_vec_add` from `nmod_vec/add.c`, FLINT 3.6.0, with the modulus
113 /// $2^k$.
114 #[inline]
115 fn mod_power_of_2_add(mut self, other: &Self, pow: u64) -> Self {
116 self.mod_power_of_2_add_assign(other, pow);
117 self
118 }
119}
120
121impl<T: PrimitiveUnsigned> ModPowerOf2Add<UnsignedVector<T>> for &UnsignedVector<T> {
122 type Output = UnsignedVector<T>;
123
124 /// Adds two [`UnsignedVector`]s modulo $2^k$, taking the first by reference and the second by
125 /// value. The elements of both must already be reduced modulo $2^k$.
126 ///
127 /// The sum is taken element by element, each reduced modulo $2^k$, so the result has the same
128 /// dimension as the summands.
129 ///
130 /// $$
131 /// f(v, w, k) = v + w \bmod 2^k.
132 /// $$
133 ///
134 /// # Worst-case complexity
135 /// $T(n) = O(n)$
136 ///
137 /// $M(n) = O(1)$
138 ///
139 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
140 ///
141 /// # Panics
142 /// Panics if `pow` is greater than `T::WIDTH`, if `self` and `other` have different dimensions,
143 /// or if any element of either is greater than or equal to $2^k$.
144 ///
145 /// # Examples
146 /// ```
147 /// use core::str::FromStr;
148 /// use malachite_base::num::arithmetic::traits::ModPowerOf2Add;
149 /// use malachite_base::unsigned_vector::UnsignedVector;
150 ///
151 /// let v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
152 /// let w = UnsignedVector::<u8>::from_str("(4, 7, 0)").unwrap();
153 /// assert_eq!((&v).mod_power_of_2_add(w, 3).to_string(), "(1, 0, 3)");
154 /// ```
155 ///
156 /// This is equivalent to `_nmod_vec_add` from `nmod_vec/add.c`, FLINT 3.6.0, with the modulus
157 /// $2^k$.
158 #[inline]
159 fn mod_power_of_2_add(self, mut other: UnsignedVector<T>, pow: u64) -> UnsignedVector<T> {
160 other.mod_power_of_2_add_assign(self, pow);
161 other
162 }
163}
164
165impl<T: PrimitiveUnsigned> ModPowerOf2Add<&UnsignedVector<T>> for &UnsignedVector<T> {
166 type Output = UnsignedVector<T>;
167
168 /// Adds two [`UnsignedVector`]s modulo $2^k$, taking both by reference. The elements of both
169 /// must already be reduced modulo $2^k$.
170 ///
171 /// The sum is taken element by element, each reduced modulo $2^k$, so the result has the same
172 /// dimension as the summands.
173 ///
174 /// $$
175 /// f(v, w, k) = v + w \bmod 2^k.
176 /// $$
177 ///
178 /// # Worst-case complexity
179 /// $T(n) = O(n)$
180 ///
181 /// $M(n) = O(n)$
182 ///
183 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
184 ///
185 /// # Panics
186 /// Panics if `pow` is greater than `T::WIDTH`, if `self` and `other` have different dimensions,
187 /// or if any element of either is greater than or equal to $2^k$.
188 ///
189 /// # Examples
190 /// ```
191 /// use core::str::FromStr;
192 /// use malachite_base::num::arithmetic::traits::ModPowerOf2Add;
193 /// use malachite_base::unsigned_vector::UnsignedVector;
194 ///
195 /// let v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
196 /// let w = UnsignedVector::<u8>::from_str("(4, 7, 0)").unwrap();
197 /// assert_eq!((&v).mod_power_of_2_add(&w, 3).to_string(), "(1, 0, 3)");
198 /// ```
199 ///
200 /// This is equivalent to `_nmod_vec_add` from `nmod_vec/add.c`, FLINT 3.6.0, with the modulus
201 /// $2^k$.
202 fn mod_power_of_2_add(self, other: &UnsignedVector<T>, pow: u64) -> UnsignedVector<T> {
203 assert_reduced(self, other, pow);
204 UnsignedVector {
205 elements: self
206 .elements
207 .iter()
208 .zip(&other.elements)
209 .map(|(&x, &y)| x.wrapping_add(y).mod_power_of_2(pow))
210 .collect(),
211 }
212 }
213}
214
215impl<T: PrimitiveUnsigned> ModPowerOf2AddAssign<Self> for UnsignedVector<T> {
216 /// Adds an [`UnsignedVector`] to an [`UnsignedVector`] modulo $2^k$, in place, taking the
217 /// [`UnsignedVector`] on the right-hand side by value. The elements of both must already be
218 /// reduced modulo $2^k$.
219 ///
220 /// The sum is taken element by element, each reduced modulo $2^k$, so the result has the same
221 /// dimension as the summands.
222 ///
223 /// $$
224 /// f(v, w, k) = v + w \bmod 2^k.
225 /// $$
226 ///
227 /// # Worst-case complexity
228 /// $T(n) = O(n)$
229 ///
230 /// $M(n) = O(1)$
231 ///
232 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
233 ///
234 /// # Panics
235 /// Panics if `pow` is greater than `T::WIDTH`, if `self` and `other` have different dimensions,
236 /// or if any element of either is greater than or equal to $2^k$.
237 ///
238 /// # Examples
239 /// ```
240 /// use core::str::FromStr;
241 /// use malachite_base::num::arithmetic::traits::ModPowerOf2AddAssign;
242 /// use malachite_base::unsigned_vector::UnsignedVector;
243 ///
244 /// let mut v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
245 /// v.mod_power_of_2_add_assign(UnsignedVector::<u8>::from_str("(4, 7, 0)").unwrap(), 3);
246 /// assert_eq!(v.to_string(), "(1, 0, 3)");
247 /// ```
248 ///
249 /// This is equivalent to `_nmod_vec_add` from `nmod_vec/add.c`, FLINT 3.6.0, with the modulus
250 /// $2^k$.
251 fn mod_power_of_2_add_assign(&mut self, other: Self, pow: u64) {
252 assert_reduced(self, &other, pow);
253 for (x, y) in self.elements.iter_mut().zip(other.elements) {
254 *x = x.wrapping_add(y).mod_power_of_2(pow);
255 }
256 }
257}
258
259impl<T: PrimitiveUnsigned> ModPowerOf2AddAssign<&Self> for UnsignedVector<T> {
260 /// Adds an [`UnsignedVector`] to an [`UnsignedVector`] modulo $2^k$, in place, taking the
261 /// [`UnsignedVector`] on the right-hand side by reference. The elements of both must already be
262 /// reduced modulo $2^k$.
263 ///
264 /// The sum is taken element by element, each reduced modulo $2^k$, so the result has the same
265 /// dimension as the summands.
266 ///
267 /// $$
268 /// f(v, w, k) = v + w \bmod 2^k.
269 /// $$
270 ///
271 /// # Worst-case complexity
272 /// $T(n) = O(n)$
273 ///
274 /// $M(n) = O(1)$
275 ///
276 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
277 ///
278 /// # Panics
279 /// Panics if `pow` is greater than `T::WIDTH`, if `self` and `other` have different dimensions,
280 /// or if any element of either is greater than or equal to $2^k$.
281 ///
282 /// # Examples
283 /// ```
284 /// use core::str::FromStr;
285 /// use malachite_base::num::arithmetic::traits::ModPowerOf2AddAssign;
286 /// use malachite_base::unsigned_vector::UnsignedVector;
287 ///
288 /// let mut v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
289 /// v.mod_power_of_2_add_assign(&UnsignedVector::<u8>::from_str("(4, 7, 0)").unwrap(), 3);
290 /// assert_eq!(v.to_string(), "(1, 0, 3)");
291 /// ```
292 ///
293 /// This is equivalent to `_nmod_vec_add` from `nmod_vec/add.c`, FLINT 3.6.0, with the modulus
294 /// $2^k$.
295 fn mod_power_of_2_add_assign(&mut self, other: &Self, pow: u64) {
296 assert_reduced(self, other, pow);
297 for (x, y) in self.elements.iter_mut().zip(&other.elements) {
298 *x = x.wrapping_add(*y).mod_power_of_2(pow);
299 }
300 }
301}