Skip to main content

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