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}