Skip to main content

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}