1use super::super::MatPolyOverZ;
12use crate::{
13 integer::Z,
14 integer_mod_q::{MatPolynomialRingZq, Modulus, ModulusPolynomialRingZq},
15 macros::{
16 arithmetics::{arithmetic_trait_borrowed_to_owned, arithmetic_trait_mixed_borrowed_owned},
17 for_others::implement_for_others,
18 },
19 traits::{MatrixDimensions, MatrixGetEntry, MatrixSetEntry},
20};
21use std::ops::Rem;
22
23impl Rem<&Z> for &MatPolyOverZ {
24 type Output = MatPolyOverZ;
25 fn rem(self, modulus: &Z) -> Self::Output {
48 assert!(modulus > &1, "Modulus can not be smaller than 2.");
49 let num_cols = self.get_num_columns();
50 let num_rows = self.get_num_rows();
51
52 let mut out = MatPolyOverZ::new(num_rows, num_cols);
53
54 for i in 0..num_rows {
55 for j in 0..num_cols {
56 let mut entry = unsafe { self.get_entry_unchecked(i, j) };
57 entry = entry % modulus;
58 unsafe { out.set_entry_unchecked(i, j, entry) };
59 }
60 }
61
62 out
63 }
64}
65
66impl Rem<&Modulus> for &MatPolyOverZ {
67 type Output = MatPolyOverZ;
68 fn rem(self, modulus: &Modulus) -> Self::Output {
89 let mut out = MatPolyOverZ::new(self.get_num_rows(), self.get_num_rows());
90
91 for i in 0..self.get_num_rows() {
92 for j in 0..self.get_num_columns() {
93 let mut entry = unsafe { self.get_entry_unchecked(i, j) };
94 entry = entry % modulus;
95 unsafe { out.set_entry_unchecked(i, j, entry) };
96 }
97 }
98
99 out
100 }
101}
102
103impl<Mod: Into<ModulusPolynomialRingZq>> Rem<Mod> for &MatPolyOverZ {
104 type Output = MatPolyOverZ;
105 fn rem(self, modulus: Mod) -> Self::Output {
126 MatPolynomialRingZq::from((self, modulus)).matrix
127 }
128}
129
130impl<Mod: Into<ModulusPolynomialRingZq>> Rem<Mod> for MatPolyOverZ {
131 type Output = MatPolyOverZ;
132 fn rem(self, modulus: Mod) -> Self::Output {
153 MatPolynomialRingZq::from((self, modulus)).matrix
154 }
155}
156
157arithmetic_trait_borrowed_to_owned!(Rem, rem, MatPolyOverZ, Z, MatPolyOverZ);
158arithmetic_trait_mixed_borrowed_owned!(Rem, rem, MatPolyOverZ, Z, MatPolyOverZ);
159arithmetic_trait_borrowed_to_owned!(Rem, rem, MatPolyOverZ, Modulus, MatPolyOverZ);
160arithmetic_trait_mixed_borrowed_owned!(Rem, rem, MatPolyOverZ, Modulus, MatPolyOverZ);
161
162implement_for_others!(Z, MatPolyOverZ, Rem for i8 i16 i32 i64 u8 u16 u32 u64);
163
164#[cfg(test)]
165mod test_rem {
166 use super::Z;
167 use crate::{
168 integer::MatPolyOverZ,
169 integer_mod_q::{Modulus, ModulusPolynomialRingZq, PolyOverZq},
170 };
171 use std::str::FromStr;
172
173 #[test]
175 fn rem() {
176 let a = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap();
177 let b = Z::from(24);
178 let modulus = Modulus::from(24);
179 let poly_mod = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 24").unwrap();
180 let c1 = a.clone() % b;
181 let c2 = a.clone() % modulus;
182 let c3 = a % poly_mod;
183 let cmp = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 18, 0]]").unwrap();
184 assert_eq!(c1, cmp);
185 assert_eq!(c2, cmp);
186 assert_eq!(c3, cmp);
187 }
188
189 #[test]
191 fn rem_borrow() {
192 let a = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap();
193 let b = Z::from(24);
194 let modulus = Modulus::from(24);
195 let poly_mod = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 24").unwrap();
196 let c1 = &a % &b;
197 let c2 = &a % &modulus;
198 let c3 = &a % &poly_mod;
199 let cmp = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 18, 0]]").unwrap();
200 assert_eq!(c1, cmp);
201 assert_eq!(c2, cmp);
202 assert_eq!(c3, cmp);
203 }
204
205 #[test]
207 fn rem_first_borrowed() {
208 let a = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap();
209 let b = Z::from(24);
210 let modulus = Modulus::from(24);
211 let poly_mod = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 24").unwrap();
212 let c1 = &a % b;
213 let c2 = &a % modulus;
214 let c3 = &a % poly_mod;
215 let cmp = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 18, 0]]").unwrap();
216 assert_eq!(c1, cmp);
217 assert_eq!(c2, cmp);
218 assert_eq!(c3, cmp);
219 }
220
221 #[test]
223 fn rem_second_borrowed() {
224 let a = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap();
225 let b = Z::from(24);
226 let modulus = Modulus::from(24);
227 let poly_mod = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 24").unwrap();
228 let c1 = a.clone() % &b;
229 let c2 = a.clone() % &modulus;
230 let c3 = a % &poly_mod;
231 let cmp = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 18, 0]]").unwrap();
232 assert_eq!(c1, cmp);
233 assert_eq!(c2, cmp);
234 assert_eq!(c3, cmp);
235 }
236
237 #[test]
239 fn rem_negative_representation() {
240 let a = MatPolyOverZ::from_str("[[1 -2, 1 3],[2 3 42, 1 24]]").unwrap();
241 let b = Z::from(24);
242 let modulus = Modulus::from(24);
243 let poly_mod = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 24").unwrap();
244 let c1 = &a % &b;
245 let c2 = &a % &modulus;
246 let c3 = a % &poly_mod;
247 let cmp = MatPolyOverZ::from_str("[[1 22, 1 3],[2 3 18, 0]]").unwrap();
248 assert_eq!(c1, cmp);
249 assert_eq!(c2, cmp);
250 assert_eq!(c3, cmp);
251 }
252
253 #[test]
255 fn rem_large_numbers() {
256 let a =
257 MatPolyOverZ::from_str(&format!("[[1 2, 1 {}],[2 3 42, 1 24]]", u64::MAX)).unwrap();
258 let b = Z::from(u64::MAX - 2);
259 let modulus = Modulus::from(u64::MAX - 2);
260 let poly_mod =
261 ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {}", u64::MAX - 2)).unwrap();
262 let c1 = a.clone() % &b;
263 let c2 = a.clone() % &modulus;
264 let c3 = a % &poly_mod;
265 let cmp = MatPolyOverZ::from_str("[[1 2, 1 2],[2 3 42, 1 24]]").unwrap();
266 assert_eq!(c1, cmp);
267 assert_eq!(c2, cmp);
268 assert_eq!(c3, cmp);
269 }
270
271 #[test]
273 fn polynomial_reduction() {
274 let a = MatPolyOverZ::from_str("[[1 -2, 4 1 1 0 1],[2 3 42, 1 24]]").unwrap();
275 let b = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 24").unwrap();
276 let c = a % b;
277 let cmp = MatPolyOverZ::from_str("[[1 22, 2 0 1],[2 3 18, 0]]").unwrap();
278 assert_eq!(c, cmp);
279 }
280
281 #[test]
283 #[should_panic]
284 fn rem_negative_error() {
285 let a = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap();
286 let b = Z::from(-24);
287 _ = &a % &b;
288 }
289
290 #[test]
292 #[should_panic]
293 fn zero_modulus() {
294 _ = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap() % 0;
295 }
296
297 #[test]
299 fn availability() {
300 let _ = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap() % 2u8;
301 let _ = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap() % 2u16;
302 let _ = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap() % 2u32;
303 let _ = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap() % 2u64;
304 let _ = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap() % 2i8;
305 let _ = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap() % 2i16;
306 let _ = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap() % 2i32;
307 let _ = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap() % 2i64;
308 let _ = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap() % Z::from(2);
309 let _ = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap()
310 % ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 24").unwrap();
311
312 let _ = &MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap() % 2u8;
313 let _ = MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap() % &Z::from(2);
314 let _ = &MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap() % &Z::from(2);
315 let _ = &MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap()
316 % PolyOverZq::from_str("4 1 0 0 1 mod 24").unwrap();
317 let _ = &MatPolyOverZ::from_str("[[1 2, 1 3],[2 3 42, 1 24]]").unwrap()
318 % &PolyOverZq::from_str("4 1 0 0 1 mod 24").unwrap();
319 }
320}