Skip to main content

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}