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}