Skip to main content

malachite_nz/integer_vector/arithmetic/
balanced_mod.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 malachite_base::num::arithmetic::traits::{BalancedMod, BalancedModAssign};
12
13impl BalancedMod<Integer> for IntegerVector {
14    type Output = Self;
15
16    /// Reduces every element of an [`IntegerVector`] modulo an [`Integer`] to the representative
17    /// closest to zero, taking the vector by value and the modulus by value.
18    ///
19    /// Each element $w_i$ of the result satisfies $-|m|/2 < w_i \leq |m|/2$ and $w_i \equiv v_i
20    /// \bmod m$, which determine it uniquely, as with [`BalancedMod`] for [`Integer`]s. A remainder
21    /// of exactly $|m|/2$ is positive, and only the magnitude of $m$ matters. The dimension is
22    /// unchanged: unlike a polynomial, a vector keeps the elements that reduce to zero.
23    ///
24    /// # Worst-case complexity
25    /// $T(n) = O(n \log n \log\log n)$
26    ///
27    /// $M(n) = O(n \log n)$
28    ///
29    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits in the
30    /// vector's elements.
31    ///
32    /// # Panics
33    /// Panics if `m` is zero.
34    ///
35    /// # Examples
36    /// ```
37    /// use core::str::FromStr;
38    /// use malachite_base::num::arithmetic::traits::BalancedMod;
39    /// use malachite_nz::integer::Integer;
40    /// use malachite_nz::integer_vector::IntegerVector;
41    ///
42    /// // Each element goes to the representative closest to zero, and half the modulus is
43    /// // positive.
44    /// let v = IntegerVector::from_str("(1, 27, -23, -5)").unwrap();
45    /// assert_eq!(
46    ///     v.clone().balanced_mod(Integer::from(10)).to_string(),
47    ///     "(1, -3, -3, 5)"
48    /// );
49    ///
50    /// // Only the modulus's magnitude matters, and an element that reduces to zero stays.
51    /// let v = IntegerVector::from_str("(10, 7)").unwrap();
52    /// assert_eq!(
53    ///     v.clone().balanced_mod(Integer::from(-10)).to_string(),
54    ///     "(0, -3)"
55    /// );
56    /// ```
57    ///
58    /// This is equivalent to `_fmpz_vec_scalar_smod_fmpz` from `fmpz_vec/scalar_smod.c`, FLINT
59    /// 3.6.0, for a positive modulus.
60    #[inline]
61    fn balanced_mod(mut self, m: Integer) -> Self {
62        self.balanced_mod_assign(m);
63        self
64    }
65}
66
67impl<'a> BalancedMod<&'a Integer> for IntegerVector {
68    type Output = Self;
69
70    /// Reduces every element of an [`IntegerVector`] modulo an [`Integer`] to the representative
71    /// closest to zero, taking the vector by value and the modulus by reference.
72    ///
73    /// See the documentation for the [`BalancedMod`] implementation on [`IntegerVector`] that takes
74    /// both arguments by value for details.
75    ///
76    /// # Worst-case complexity
77    /// $T(n) = O(n \log n \log\log n)$
78    ///
79    /// $M(n) = O(n \log n)$
80    ///
81    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits in the
82    /// vector's elements.
83    ///
84    /// # Panics
85    /// Panics if `m` is zero.
86    ///
87    /// # Examples
88    /// ```
89    /// use core::str::FromStr;
90    /// use malachite_base::num::arithmetic::traits::BalancedMod;
91    /// use malachite_nz::integer::Integer;
92    /// use malachite_nz::integer_vector::IntegerVector;
93    ///
94    /// // Each element goes to the representative closest to zero, and half the modulus is
95    /// // positive.
96    /// let v = IntegerVector::from_str("(1, 27, -23, -5)").unwrap();
97    /// assert_eq!(
98    ///     v.clone().balanced_mod(&Integer::from(10)).to_string(),
99    ///     "(1, -3, -3, 5)"
100    /// );
101    ///
102    /// // Only the modulus's magnitude matters, and an element that reduces to zero stays.
103    /// let v = IntegerVector::from_str("(10, 7)").unwrap();
104    /// assert_eq!(
105    ///     v.clone().balanced_mod(&Integer::from(-10)).to_string(),
106    ///     "(0, -3)"
107    /// );
108    /// ```
109    #[inline]
110    fn balanced_mod(mut self, m: &'a Integer) -> Self {
111        self.balanced_mod_assign(m);
112        self
113    }
114}
115
116impl BalancedMod<Integer> for &IntegerVector {
117    type Output = IntegerVector;
118
119    /// Reduces every element of an [`IntegerVector`] modulo an [`Integer`] to the representative
120    /// closest to zero, taking the vector by reference and the modulus by value.
121    ///
122    /// See the documentation for the [`BalancedMod`] implementation on [`IntegerVector`] that takes
123    /// both arguments by value for details.
124    ///
125    /// # Worst-case complexity
126    /// $T(n) = O(n \log n \log\log n)$
127    ///
128    /// $M(n) = O(n \log n)$
129    ///
130    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits in the
131    /// vector's elements.
132    ///
133    /// # Panics
134    /// Panics if `m` is zero.
135    ///
136    /// # Examples
137    /// ```
138    /// use core::str::FromStr;
139    /// use malachite_base::num::arithmetic::traits::BalancedMod;
140    /// use malachite_nz::integer::Integer;
141    /// use malachite_nz::integer_vector::IntegerVector;
142    ///
143    /// // Each element goes to the representative closest to zero, and half the modulus is
144    /// // positive.
145    /// let v = IntegerVector::from_str("(1, 27, -23, -5)").unwrap();
146    /// assert_eq!(
147    ///     (&v).balanced_mod(Integer::from(10)).to_string(),
148    ///     "(1, -3, -3, 5)"
149    /// );
150    ///
151    /// // Only the modulus's magnitude matters, and an element that reduces to zero stays.
152    /// let v = IntegerVector::from_str("(10, 7)").unwrap();
153    /// assert_eq!((&v).balanced_mod(Integer::from(-10)).to_string(), "(0, -3)");
154    /// ```
155    #[inline]
156    fn balanced_mod(self, m: Integer) -> IntegerVector {
157        self.balanced_mod(&m)
158    }
159}
160
161impl<'a> BalancedMod<&'a Integer> for &IntegerVector {
162    type Output = IntegerVector;
163
164    /// Reduces every element of an [`IntegerVector`] modulo an [`Integer`] to the representative
165    /// closest to zero, taking the vector by reference and the modulus by reference.
166    ///
167    /// See the documentation for the [`BalancedMod`] implementation on [`IntegerVector`] that takes
168    /// both arguments by value for details.
169    ///
170    /// # Worst-case complexity
171    /// $T(n) = O(n \log n \log\log n)$
172    ///
173    /// $M(n) = O(n \log n)$
174    ///
175    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits in the
176    /// vector's elements.
177    ///
178    /// # Panics
179    /// Panics if `m` is zero.
180    ///
181    /// # Examples
182    /// ```
183    /// use core::str::FromStr;
184    /// use malachite_base::num::arithmetic::traits::BalancedMod;
185    /// use malachite_nz::integer::Integer;
186    /// use malachite_nz::integer_vector::IntegerVector;
187    ///
188    /// // Each element goes to the representative closest to zero, and half the modulus is
189    /// // positive.
190    /// let v = IntegerVector::from_str("(1, 27, -23, -5)").unwrap();
191    /// assert_eq!(
192    ///     (&v).balanced_mod(&Integer::from(10)).to_string(),
193    ///     "(1, -3, -3, 5)"
194    /// );
195    ///
196    /// // Only the modulus's magnitude matters, and an element that reduces to zero stays.
197    /// let v = IntegerVector::from_str("(10, 7)").unwrap();
198    /// assert_eq!(
199    ///     (&v).balanced_mod(&Integer::from(-10)).to_string(),
200    ///     "(0, -3)"
201    /// );
202    /// ```
203    fn balanced_mod(self, m: &'a Integer) -> IntegerVector {
204        assert_ne!(*m, 0u32, "division by zero");
205        IntegerVector {
206            elements: self.elements.iter().map(|x| x.balanced_mod(m)).collect(),
207        }
208    }
209}
210
211impl BalancedModAssign<Integer> for IntegerVector {
212    /// Reduces every element of an [`IntegerVector`] modulo an [`Integer`] to the representative
213    /// closest to zero, in place, taking the modulus by value.
214    ///
215    /// See the documentation for the [`BalancedMod`] implementation on [`IntegerVector`] that takes
216    /// both arguments by value for details.
217    ///
218    /// # Worst-case complexity
219    /// $T(n) = O(n \log n \log\log n)$
220    ///
221    /// $M(n) = O(n \log n)$
222    ///
223    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits in the
224    /// vector's elements.
225    ///
226    /// # Panics
227    /// Panics if `m` is zero.
228    ///
229    /// # Examples
230    /// ```
231    /// use core::str::FromStr;
232    /// use malachite_base::num::arithmetic::traits::BalancedModAssign;
233    /// use malachite_nz::integer::Integer;
234    /// use malachite_nz::integer_vector::IntegerVector;
235    ///
236    /// let mut v = IntegerVector::from_str("(1, 27, -23, -5)").unwrap();
237    /// v.balanced_mod_assign(Integer::from(10));
238    /// assert_eq!(v.to_string(), "(1, -3, -3, 5)");
239    ///
240    /// let mut v = IntegerVector::from_str("(10, 7)").unwrap();
241    /// v.balanced_mod_assign(Integer::from(-10));
242    /// assert_eq!(v.to_string(), "(0, -3)");
243    /// ```
244    #[inline]
245    fn balanced_mod_assign(&mut self, m: Integer) {
246        self.balanced_mod_assign(&m);
247    }
248}
249
250impl<'a> BalancedModAssign<&'a Integer> for IntegerVector {
251    /// Reduces every element of an [`IntegerVector`] modulo an [`Integer`] to the representative
252    /// closest to zero, in place, taking the modulus by reference.
253    ///
254    /// See the documentation for the [`BalancedMod`] implementation on [`IntegerVector`] that takes
255    /// both arguments by value for details.
256    ///
257    /// # Worst-case complexity
258    /// $T(n) = O(n \log n \log\log n)$
259    ///
260    /// $M(n) = O(n \log n)$
261    ///
262    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits in the
263    /// vector's elements.
264    ///
265    /// # Panics
266    /// Panics if `m` is zero.
267    ///
268    /// # Examples
269    /// ```
270    /// use core::str::FromStr;
271    /// use malachite_base::num::arithmetic::traits::BalancedModAssign;
272    /// use malachite_nz::integer::Integer;
273    /// use malachite_nz::integer_vector::IntegerVector;
274    ///
275    /// let mut v = IntegerVector::from_str("(1, 27, -23, -5)").unwrap();
276    /// v.balanced_mod_assign(&Integer::from(10));
277    /// assert_eq!(v.to_string(), "(1, -3, -3, 5)");
278    ///
279    /// let mut v = IntegerVector::from_str("(10, 7)").unwrap();
280    /// v.balanced_mod_assign(&Integer::from(-10));
281    /// assert_eq!(v.to_string(), "(0, -3)");
282    /// ```
283    fn balanced_mod_assign(&mut self, m: &'a Integer) {
284        assert_ne!(*m, 0u32, "division by zero");
285        for x in &mut self.elements {
286            x.balanced_mod_assign(m);
287        }
288    }
289}