malachite_nz/integer_vector/arithmetic/mod_op.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::integer::Integer;
10use crate::integer_vector::IntegerVector;
11use crate::natural::Natural;
12use crate::natural_vector::NaturalVector;
13use alloc::vec::Vec;
14use core::ops::{Rem, RemAssign};
15use malachite_base::num::arithmetic::traits::{Mod, NegMod};
16use malachite_base::num::basic::unsigneds::PrimitiveUnsigned;
17use malachite_base::num::conversion::traits::ExactFrom;
18use malachite_base::unsigned_vector::UnsignedVector;
19
20// The remainder of `x` modulo `m`, in $[0, m)$.
21fn integer_mod_natural(x: &Integer, m: &Natural) -> Natural {
22 if x.sign {
23 &x.abs % m
24 } else {
25 (&x.abs).neg_mod(m)
26 }
27}
28
29impl Mod<Natural> for IntegerVector {
30 type Output = NaturalVector;
31
32 /// Divides every element of an [`IntegerVector`] by a [`Natural`], keeping the remainders as a
33 /// [`NaturalVector`], taking the vector by value and the modulus by value.
34 ///
35 /// Each remainder is taken in $[0, m)$, the way [`Mod`] does for [`Integer`]s, so a negative
36 /// element $x$ that is not a multiple of $m$ becomes $m - (-x \bmod m)$. The result is
37 /// therefore reduced modulo $m$, which is to say that
38 /// [`mod_is_reduced`](malachite_base::num::arithmetic::traits::ModIsReduced::mod_is_reduced)
39 /// returns `true` for it, and every element of the result is congruent to the corresponding
40 /// element of the input. The dimension is unchanged: unlike a polynomial, a vector keeps the
41 /// elements that reduce to zero.
42 ///
43 /// $$
44 /// f(v, m) = w, \quad \text{where} \quad w_i = v_i - m \left \lfloor \frac{v_i}{m}
45 /// \right \rfloor.
46 /// $$
47 ///
48 /// # Worst-case complexity
49 /// $T(n) = O(n \log n \log\log n)$
50 ///
51 /// $M(n) = O(n \log n)$
52 ///
53 /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits in the
54 /// vector's elements.
55 ///
56 /// # Panics
57 /// Panics if `m` is zero.
58 ///
59 /// # Examples
60 /// ```
61 /// use core::str::FromStr;
62 /// use malachite_base::num::arithmetic::traits::Mod;
63 /// use malachite_nz::integer_vector::IntegerVector;
64 /// use malachite_nz::natural::Natural;
65 ///
66 /// // Every element is taken modulo 3, and negative ones become non-negative.
67 /// let v = IntegerVector::from_str("(1, -4, -5)").unwrap();
68 /// assert_eq!(
69 /// v.clone().mod_op(Natural::from(3u32)).to_string(),
70 /// "(1, 2, 1)"
71 /// );
72 ///
73 /// // An element that reduces to zero stays, so the dimension is unchanged.
74 /// let v = IntegerVector::from_str("(-6, 3)").unwrap();
75 /// assert_eq!(v.clone().mod_op(Natural::from(3u32)).to_string(), "(0, 0)");
76 /// ```
77 ///
78 /// This is equivalent to `_fmpz_vec_scalar_mod_fmpz` from `fmpz_vec/scalar_mod.c`, FLINT 3.6.0,
79 /// for a positive modulus.
80 #[inline]
81 fn mod_op(self, m: Natural) -> NaturalVector {
82 self.mod_op(&m)
83 }
84}
85
86impl<'a> Mod<&'a Natural> for IntegerVector {
87 type Output = NaturalVector;
88
89 /// Divides every element of an [`IntegerVector`] by a [`Natural`], keeping the remainders as a
90 /// [`NaturalVector`], taking the vector by value and the modulus by reference.
91 ///
92 /// See the documentation for the [`Mod`] implementation on [`IntegerVector`] that takes both
93 /// arguments by value for details, including how negative elements are handled.
94 ///
95 /// # Worst-case complexity
96 /// $T(n) = O(n \log n \log\log n)$
97 ///
98 /// $M(n) = O(n \log n)$
99 ///
100 /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits in the
101 /// vector's elements.
102 ///
103 /// # Panics
104 /// Panics if `m` is zero.
105 ///
106 /// # Examples
107 /// ```
108 /// use core::str::FromStr;
109 /// use malachite_base::num::arithmetic::traits::Mod;
110 /// use malachite_nz::integer_vector::IntegerVector;
111 /// use malachite_nz::natural::Natural;
112 ///
113 /// // Every element is taken modulo 3, and negative ones become non-negative.
114 /// let v = IntegerVector::from_str("(1, -4, -5)").unwrap();
115 /// assert_eq!(
116 /// v.clone().mod_op(&Natural::from(3u32)).to_string(),
117 /// "(1, 2, 1)"
118 /// );
119 ///
120 /// // An element that reduces to zero stays, so the dimension is unchanged.
121 /// let v = IntegerVector::from_str("(-6, 3)").unwrap();
122 /// assert_eq!(v.clone().mod_op(&Natural::from(3u32)).to_string(), "(0, 0)");
123 /// ```
124 fn mod_op(self, m: &'a Natural) -> NaturalVector {
125 assert_ne!(*m, 0u32, "division by zero");
126 NaturalVector {
127 elements: self
128 .elements
129 .into_iter()
130 .map(|Integer { sign, abs }| if sign { abs % m } else { abs.neg_mod(m) })
131 .collect(),
132 }
133 }
134}
135
136impl Mod<Natural> for &IntegerVector {
137 type Output = NaturalVector;
138
139 /// Divides every element of an [`IntegerVector`] by a [`Natural`], keeping the remainders as a
140 /// [`NaturalVector`], taking the vector by reference and the modulus by value.
141 ///
142 /// See the documentation for the [`Mod`] implementation on [`IntegerVector`] that takes both
143 /// arguments by value for details, including how negative elements are handled.
144 ///
145 /// # Worst-case complexity
146 /// $T(n) = O(n \log n \log\log n)$
147 ///
148 /// $M(n) = O(n \log n)$
149 ///
150 /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits in the
151 /// vector's elements.
152 ///
153 /// # Panics
154 /// Panics if `m` is zero.
155 ///
156 /// # Examples
157 /// ```
158 /// use core::str::FromStr;
159 /// use malachite_base::num::arithmetic::traits::Mod;
160 /// use malachite_nz::integer_vector::IntegerVector;
161 /// use malachite_nz::natural::Natural;
162 ///
163 /// // Every element is taken modulo 3, and negative ones become non-negative.
164 /// let v = IntegerVector::from_str("(1, -4, -5)").unwrap();
165 /// assert_eq!((&v).mod_op(Natural::from(3u32)).to_string(), "(1, 2, 1)");
166 ///
167 /// // An element that reduces to zero stays, so the dimension is unchanged.
168 /// let v = IntegerVector::from_str("(-6, 3)").unwrap();
169 /// assert_eq!((&v).mod_op(Natural::from(3u32)).to_string(), "(0, 0)");
170 /// ```
171 #[inline]
172 fn mod_op(self, m: Natural) -> NaturalVector {
173 self.mod_op(&m)
174 }
175}
176
177impl<'a> Mod<&'a Natural> for &IntegerVector {
178 type Output = NaturalVector;
179
180 /// Divides every element of an [`IntegerVector`] by a [`Natural`], keeping the remainders as a
181 /// [`NaturalVector`], taking the vector by reference and the modulus by reference.
182 ///
183 /// See the documentation for the [`Mod`] implementation on [`IntegerVector`] that takes both
184 /// arguments by value for details, including how negative elements are handled.
185 ///
186 /// # Worst-case complexity
187 /// $T(n) = O(n \log n \log\log n)$
188 ///
189 /// $M(n) = O(n \log n)$
190 ///
191 /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits in the
192 /// vector's elements.
193 ///
194 /// # Panics
195 /// Panics if `m` is zero.
196 ///
197 /// # Examples
198 /// ```
199 /// use core::str::FromStr;
200 /// use malachite_base::num::arithmetic::traits::Mod;
201 /// use malachite_nz::integer_vector::IntegerVector;
202 /// use malachite_nz::natural::Natural;
203 ///
204 /// // Every element is taken modulo 3, and negative ones become non-negative.
205 /// let v = IntegerVector::from_str("(1, -4, -5)").unwrap();
206 /// assert_eq!((&v).mod_op(&Natural::from(3u32)).to_string(), "(1, 2, 1)");
207 ///
208 /// // An element that reduces to zero stays, so the dimension is unchanged.
209 /// let v = IntegerVector::from_str("(-6, 3)").unwrap();
210 /// assert_eq!((&v).mod_op(&Natural::from(3u32)).to_string(), "(0, 0)");
211 /// ```
212 fn mod_op(self, m: &'a Natural) -> NaturalVector {
213 assert_ne!(*m, 0u32, "division by zero");
214 NaturalVector {
215 elements: self
216 .elements
217 .iter()
218 .map(|x| integer_mod_natural(x, m))
219 .collect(),
220 }
221 }
222}
223
224impl<T: PrimitiveUnsigned + for<'a> ExactFrom<&'a Natural>> Mod<T> for &IntegerVector
225where
226 Natural: From<T>,
227{
228 type Output = UnsignedVector<T>;
229
230 /// Divides every element of an [`IntegerVector`] by a value of an unsigned primitive integer
231 /// type, keeping the remainders as an [`UnsignedVector`] with that element type, taking the
232 /// vector by reference.
233 ///
234 /// Each remainder is taken in $[0, m)$, so negative elements become non-negative, and every
235 /// remainder fits in `m`'s type. Apart from the result's type, this is the same operation as
236 /// reducing modulo `Natural::from(m)`; see the documentation for the [`Mod`] implementation on
237 /// [`IntegerVector`] that takes both arguments by value for details.
238 ///
239 /// The result is reduced modulo $m$, which is to say that
240 /// [`mod_is_reduced`](malachite_base::num::arithmetic::traits::ModIsReduced::mod_is_reduced)
241 /// returns `true` for it.
242 ///
243 /// # Worst-case complexity
244 /// $T(n) = O(n)$
245 ///
246 /// $M(n) = O(m)$
247 ///
248 /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits in the vector's
249 /// elements, and $m$ is `self.dimension()`.
250 ///
251 /// # Panics
252 /// Panics if `m` is zero.
253 ///
254 /// # Examples
255 /// ```
256 /// use core::str::FromStr;
257 /// use malachite_base::num::arithmetic::traits::Mod;
258 /// use malachite_base::unsigned_vector::UnsignedVector;
259 /// use malachite_nz::integer_vector::IntegerVector;
260 ///
261 /// let v = IntegerVector::from_str("(-1000000000001, 2000000000003, -5)").unwrap();
262 /// let w: UnsignedVector<u8> = (&v).mod_op(7u8);
263 /// assert_eq!(w.to_string(), "(5, 5, 2)");
264 ///
265 /// // An element that reduces to zero stays, so the dimension is unchanged.
266 /// let v = IntegerVector::from_str("(-1024, -3)").unwrap();
267 /// assert_eq!((&v).mod_op(4u64).to_string(), "(0, 1)");
268 /// ```
269 ///
270 /// This is equivalent to `_fmpz_vec_get_nmod_vec` from `fmpz_vec/get_nmod_vec.c`, FLINT 3.6.0.
271 fn mod_op(self, m: T) -> UnsignedVector<T> {
272 assert_ne!(m, T::ZERO, "division by zero");
273 let m = Natural::from(m);
274 UnsignedVector {
275 elements: self
276 .elements
277 .iter()
278 .map(|x| T::exact_from(&integer_mod_natural(x, &m)))
279 .collect::<Vec<_>>(),
280 }
281 }
282}
283
284impl<T: PrimitiveUnsigned + for<'a> ExactFrom<&'a Natural>> Mod<T> for IntegerVector
285where
286 Natural: From<T>,
287{
288 type Output = UnsignedVector<T>;
289
290 /// Divides every element of an [`IntegerVector`] by a value of an unsigned primitive integer
291 /// type, keeping the remainders as an [`UnsignedVector`] with that element type, taking the
292 /// vector by value.
293 ///
294 /// Taking the vector by value saves nothing, since the remainders go into new storage either
295 /// way. See the documentation for the [`Mod`] implementation that takes the vector by reference
296 /// for details.
297 ///
298 /// # Worst-case complexity
299 /// $T(n) = O(n)$
300 ///
301 /// $M(n) = O(m)$
302 ///
303 /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits in the vector's
304 /// elements, and $m$ is `self.dimension()`.
305 ///
306 /// # Panics
307 /// Panics if `m` is zero.
308 ///
309 /// # Examples
310 /// ```
311 /// use core::str::FromStr;
312 /// use malachite_base::num::arithmetic::traits::Mod;
313 /// use malachite_nz::integer_vector::IntegerVector;
314 ///
315 /// let v = IntegerVector::from_str("(1, -4, -5)").unwrap();
316 /// assert_eq!(v.mod_op(3u32).to_string(), "(1, 2, 1)");
317 /// ```
318 ///
319 /// This is equivalent to `_fmpz_vec_get_nmod_vec` from `fmpz_vec/get_nmod_vec.c`, FLINT 3.6.0.
320 #[inline]
321 fn mod_op(self, m: T) -> UnsignedVector<T> {
322 (&self).mod_op(m)
323 }
324}
325
326impl Rem<Integer> for IntegerVector {
327 type Output = Self;
328
329 /// Divides every element of an [`IntegerVector`] by an [`Integer`], keeping the remainders,
330 /// taking the vector by value and the modulus by value.
331 ///
332 /// Each remainder has the sign of its element and a smaller absolute value than $m$, as with
333 /// [`Rem`] for [`Integer`]s, so the sign of $m$ makes no difference. This is the remainder of
334 /// truncating division. For a remainder that is always non-negative, and a [`NaturalVector`]
335 /// result, use [`Mod`]. The dimension is unchanged.
336 ///
337 /// $$
338 /// f(v, m) = w, \quad \text{where} \quad w_i = v_i - m \operatorname{sgn}(v_im)
339 /// \left \lfloor \left | \frac{v_i}{m} \right | \right \rfloor.
340 /// $$
341 ///
342 /// # Worst-case complexity
343 /// $T(n) = O(n \log n \log\log n)$
344 ///
345 /// $M(n) = O(n \log n)$
346 ///
347 /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits in the
348 /// vector's elements.
349 ///
350 /// # Panics
351 /// Panics if `m` is zero.
352 ///
353 /// # Examples
354 /// ```
355 /// use core::str::FromStr;
356 /// use malachite_nz::integer::Integer;
357 /// use malachite_nz::integer_vector::IntegerVector;
358 ///
359 /// // Every element is taken modulo 3, keeping its sign.
360 /// let v = IntegerVector::from_str("(1, -4, -5)").unwrap();
361 /// assert_eq!((v.clone() % Integer::from(3)).to_string(), "(1, -1, -2)");
362 ///
363 /// // The sign of the modulus makes no difference, and an element that reduces to zero stays.
364 /// let v = IntegerVector::from_str("(-6, 3, -1)").unwrap();
365 /// assert_eq!((v.clone() % Integer::from(-3)).to_string(), "(0, 0, -1)");
366 /// ```
367 #[inline]
368 fn rem(mut self, m: Integer) -> Self {
369 self %= m;
370 self
371 }
372}
373
374impl<'a> Rem<&'a Integer> for IntegerVector {
375 type Output = Self;
376
377 /// Divides every element of an [`IntegerVector`] by an [`Integer`], keeping the remainders,
378 /// taking the vector by value and the modulus by reference.
379 ///
380 /// See the documentation for the [`Rem`] implementation on [`IntegerVector`] that takes both
381 /// arguments by value for details, including the signs of the remainders.
382 ///
383 /// # Worst-case complexity
384 /// $T(n) = O(n \log n \log\log n)$
385 ///
386 /// $M(n) = O(n \log n)$
387 ///
388 /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits in the
389 /// vector's elements.
390 ///
391 /// # Panics
392 /// Panics if `m` is zero.
393 ///
394 /// # Examples
395 /// ```
396 /// use core::str::FromStr;
397 /// use malachite_nz::integer::Integer;
398 /// use malachite_nz::integer_vector::IntegerVector;
399 ///
400 /// // Every element is taken modulo 3, keeping its sign.
401 /// let v = IntegerVector::from_str("(1, -4, -5)").unwrap();
402 /// assert_eq!((v.clone() % &Integer::from(3)).to_string(), "(1, -1, -2)");
403 ///
404 /// // The sign of the modulus makes no difference, and an element that reduces to zero stays.
405 /// let v = IntegerVector::from_str("(-6, 3, -1)").unwrap();
406 /// assert_eq!((v.clone() % &Integer::from(-3)).to_string(), "(0, 0, -1)");
407 /// ```
408 #[inline]
409 fn rem(mut self, m: &'a Integer) -> Self {
410 self %= m;
411 self
412 }
413}
414
415impl Rem<Integer> for &IntegerVector {
416 type Output = IntegerVector;
417
418 /// Divides every element of an [`IntegerVector`] by an [`Integer`], keeping the remainders,
419 /// taking the vector by reference and the modulus by value.
420 ///
421 /// See the documentation for the [`Rem`] implementation on [`IntegerVector`] that takes both
422 /// arguments by value for details, including the signs of the remainders.
423 ///
424 /// # Worst-case complexity
425 /// $T(n) = O(n \log n \log\log n)$
426 ///
427 /// $M(n) = O(n \log n)$
428 ///
429 /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits in the
430 /// vector's elements.
431 ///
432 /// # Panics
433 /// Panics if `m` is zero.
434 ///
435 /// # Examples
436 /// ```
437 /// use core::str::FromStr;
438 /// use malachite_nz::integer::Integer;
439 /// use malachite_nz::integer_vector::IntegerVector;
440 ///
441 /// // Every element is taken modulo 3, keeping its sign.
442 /// let v = IntegerVector::from_str("(1, -4, -5)").unwrap();
443 /// assert_eq!((&v % Integer::from(3)).to_string(), "(1, -1, -2)");
444 ///
445 /// // The sign of the modulus makes no difference, and an element that reduces to zero stays.
446 /// let v = IntegerVector::from_str("(-6, 3, -1)").unwrap();
447 /// assert_eq!((&v % Integer::from(-3)).to_string(), "(0, 0, -1)");
448 /// ```
449 #[inline]
450 fn rem(self, m: Integer) -> IntegerVector {
451 self % &m
452 }
453}
454
455impl<'a> Rem<&'a Integer> for &IntegerVector {
456 type Output = IntegerVector;
457
458 /// Divides every element of an [`IntegerVector`] by an [`Integer`], keeping the remainders,
459 /// taking the vector by reference and the modulus by reference.
460 ///
461 /// See the documentation for the [`Rem`] implementation on [`IntegerVector`] that takes both
462 /// arguments by value for details, including the signs of the remainders.
463 ///
464 /// # Worst-case complexity
465 /// $T(n) = O(n \log n \log\log n)$
466 ///
467 /// $M(n) = O(n \log n)$
468 ///
469 /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits in the
470 /// vector's elements.
471 ///
472 /// # Panics
473 /// Panics if `m` is zero.
474 ///
475 /// # Examples
476 /// ```
477 /// use core::str::FromStr;
478 /// use malachite_nz::integer::Integer;
479 /// use malachite_nz::integer_vector::IntegerVector;
480 ///
481 /// // Every element is taken modulo 3, keeping its sign.
482 /// let v = IntegerVector::from_str("(1, -4, -5)").unwrap();
483 /// assert_eq!((&v % &Integer::from(3)).to_string(), "(1, -1, -2)");
484 ///
485 /// // The sign of the modulus makes no difference, and an element that reduces to zero stays.
486 /// let v = IntegerVector::from_str("(-6, 3, -1)").unwrap();
487 /// assert_eq!((&v % &Integer::from(-3)).to_string(), "(0, 0, -1)");
488 /// ```
489 fn rem(self, m: &'a Integer) -> IntegerVector {
490 assert_ne!(*m, 0u32, "division by zero");
491 IntegerVector {
492 elements: self.elements.iter().map(|x| x % m).collect(),
493 }
494 }
495}
496
497impl RemAssign<Integer> for IntegerVector {
498 /// Divides every element of an [`IntegerVector`] by an [`Integer`], replacing each element by
499 /// the remainder, taking the modulus by value.
500 ///
501 /// See the documentation for the [`Rem`] implementation on [`IntegerVector`] that takes both
502 /// arguments by value for details, including the signs of the remainders.
503 ///
504 /// # Worst-case complexity
505 /// $T(n) = O(n \log n \log\log n)$
506 ///
507 /// $M(n) = O(n \log n)$
508 ///
509 /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits in the
510 /// vector's elements.
511 ///
512 /// # Panics
513 /// Panics if `m` is zero.
514 ///
515 /// # Examples
516 /// ```
517 /// use core::str::FromStr;
518 /// use malachite_nz::integer::Integer;
519 /// use malachite_nz::integer_vector::IntegerVector;
520 ///
521 /// let mut v = IntegerVector::from_str("(1, -4, -5)").unwrap();
522 /// v %= Integer::from(3);
523 /// assert_eq!(v.to_string(), "(1, -1, -2)");
524 ///
525 /// let mut v = IntegerVector::from_str("(-6, 3, -1)").unwrap();
526 /// v %= Integer::from(-3);
527 /// assert_eq!(v.to_string(), "(0, 0, -1)");
528 /// ```
529 #[inline]
530 fn rem_assign(&mut self, m: Integer) {
531 *self %= &m;
532 }
533}
534
535impl<'a> RemAssign<&'a Integer> for IntegerVector {
536 /// Divides every element of an [`IntegerVector`] by an [`Integer`], replacing each element by
537 /// the remainder, taking the modulus by reference.
538 ///
539 /// See the documentation for the [`Rem`] implementation on [`IntegerVector`] that takes both
540 /// arguments by value for details, including the signs of the remainders.
541 ///
542 /// # Worst-case complexity
543 /// $T(n) = O(n \log n \log\log n)$
544 ///
545 /// $M(n) = O(n \log n)$
546 ///
547 /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits in the
548 /// vector's elements.
549 ///
550 /// # Panics
551 /// Panics if `m` is zero.
552 ///
553 /// # Examples
554 /// ```
555 /// use core::str::FromStr;
556 /// use malachite_nz::integer::Integer;
557 /// use malachite_nz::integer_vector::IntegerVector;
558 ///
559 /// let mut v = IntegerVector::from_str("(1, -4, -5)").unwrap();
560 /// v %= &Integer::from(3);
561 /// assert_eq!(v.to_string(), "(1, -1, -2)");
562 ///
563 /// let mut v = IntegerVector::from_str("(-6, 3, -1)").unwrap();
564 /// v %= &Integer::from(-3);
565 /// assert_eq!(v.to_string(), "(0, 0, -1)");
566 /// ```
567 fn rem_assign(&mut self, m: &'a Integer) {
568 assert_ne!(*m, 0u32, "division by zero");
569 for x in &mut self.elements {
570 *x %= m;
571 }
572 }
573}