1use super::super::MatPolyOverZ;
12use crate::error::MathError;
13use crate::integer_mod_q::MatPolynomialRingZq;
14use crate::macros::arithmetics::{
15 arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
16 arithmetic_trait_mixed_borrowed_owned,
17};
18use crate::traits::MatrixDimensions;
19use flint_sys::fmpz_poly_mat::fmpz_poly_mat_sub;
20use std::ops::{Sub, SubAssign};
21
22impl SubAssign<&MatPolyOverZ> for MatPolyOverZ {
23 fn sub_assign(&mut self, other: &Self) {
42 if self.get_num_rows() != other.get_num_rows()
43 || self.get_num_columns() != other.get_num_columns()
44 {
45 panic!(
46 "Tried to subtract a '{}x{}' matrix and a '{}x{}' matrix.",
47 self.get_num_rows(),
48 self.get_num_columns(),
49 other.get_num_rows(),
50 other.get_num_columns()
51 );
52 }
53
54 unsafe { fmpz_poly_mat_sub(&mut self.matrix, &self.matrix, &other.matrix) };
55 }
56}
57
58arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, MatPolyOverZ, MatPolyOverZ);
59
60impl Sub for &MatPolyOverZ {
61 type Output = MatPolyOverZ;
62 fn sub(self, other: Self) -> Self::Output {
87 self.sub_safe(other).unwrap()
88 }
89}
90
91arithmetic_trait_borrowed_to_owned!(Sub, sub, MatPolyOverZ, MatPolyOverZ, MatPolyOverZ);
92arithmetic_trait_mixed_borrowed_owned!(Sub, sub, MatPolyOverZ, MatPolyOverZ, MatPolyOverZ);
93
94impl Sub<&MatPolynomialRingZq> for &MatPolyOverZ {
95 type Output = MatPolynomialRingZq;
96 fn sub(self, other: &MatPolynomialRingZq) -> Self::Output {
119 self.sub_mat_poly_ring_zq_safe(other).unwrap()
120 }
121}
122
123arithmetic_trait_borrowed_to_owned!(
124 Sub,
125 sub,
126 MatPolyOverZ,
127 MatPolynomialRingZq,
128 MatPolynomialRingZq
129);
130arithmetic_trait_mixed_borrowed_owned!(
131 Sub,
132 sub,
133 MatPolyOverZ,
134 MatPolynomialRingZq,
135 MatPolynomialRingZq
136);
137
138impl MatPolyOverZ {
139 pub fn sub_safe(&self, other: &Self) -> Result<MatPolyOverZ, MathError> {
163 if self.get_num_rows() != other.get_num_rows()
164 || self.get_num_columns() != other.get_num_columns()
165 {
166 return Err(MathError::MismatchingMatrixDimension(format!(
167 "Tried to subtract a '{}x{}' matrix and a '{}x{}' matrix.",
168 other.get_num_rows(),
169 other.get_num_columns(),
170 self.get_num_rows(),
171 self.get_num_columns()
172 )));
173 }
174 let mut out = MatPolyOverZ::new(self.get_num_rows(), self.get_num_columns());
175 unsafe {
176 fmpz_poly_mat_sub(&mut out.matrix, &self.matrix, &other.matrix);
177 }
178 Ok(out)
179 }
180
181 pub fn sub_mat_poly_ring_zq_safe(
205 &self,
206 other: &MatPolynomialRingZq,
207 ) -> Result<MatPolynomialRingZq, MathError> {
208 let mut out =
209 MatPolynomialRingZq::new(self.get_num_rows(), self.get_num_columns(), other.get_mod());
210
211 out.matrix = self.sub_safe(&other.matrix)?;
212 out.reduce();
213
214 Ok(out)
215 }
216}
217
218#[cfg(test)]
219mod test_sub_assign {
220 use crate::integer::MatPolyOverZ;
221 use std::str::FromStr;
222
223 #[test]
225 fn correct_small() {
226 let mut a = MatPolyOverZ::identity(2, 2);
227 let b = MatPolyOverZ::from_str("[[1 -4, 2 -1 -5],[1 6, 1 1]]").unwrap();
228 let cmp = MatPolyOverZ::from_str("[[1 5, 2 1 5],[1 -6, 0]]").unwrap();
229
230 a -= b;
231
232 assert_eq!(cmp, a);
233 }
234
235 #[test]
237 fn correct_large() {
238 let mut a =
239 MatPolyOverZ::from_str(&format!("[[1 {}, 2 0 2],[1 {}, 0]]", i64::MAX, i64::MIN))
240 .unwrap();
241 let b =
242 MatPolyOverZ::from_str(&format!("[[1 -{}, 1 -1],[1 -6, 1 -3]]", i64::MAX)).unwrap();
243 let cmp = MatPolyOverZ::from_str(&format!(
244 "[[1 {}, 2 1 2],[1 {}, 1 3]]",
245 2 * (i64::MAX as u64),
246 i64::MIN + 6
247 ))
248 .unwrap();
249
250 a -= b;
251
252 assert_eq!(cmp, a);
253 }
254
255 #[test]
257 fn matrix_dimensions() {
258 let dimensions = [(3, 3), (5, 1), (1, 4)];
259
260 for (nr_rows, nr_cols) in dimensions {
261 let mut a = MatPolyOverZ::identity(nr_rows, nr_cols);
262 let b = MatPolyOverZ::new(nr_rows, nr_cols);
263
264 a -= b;
265
266 assert_eq!(MatPolyOverZ::identity(nr_rows, nr_cols), a);
267 }
268 }
269
270 #[test]
272 fn availability() {
273 let mut a = MatPolyOverZ::new(2, 2);
274 let b = MatPolyOverZ::new(2, 2);
275
276 a -= &b;
277 a -= b;
278 }
279}
280
281#[cfg(test)]
282mod test_sub {
283 use super::MatPolyOverZ;
284 use std::str::FromStr;
285
286 #[test]
288 fn sub() {
289 let a: MatPolyOverZ =
290 MatPolyOverZ::from_str("[[0, 1 42, 2 42 24],[3 17 24 42, 1 17, 1 42]]").unwrap();
291 let b: MatPolyOverZ =
292 MatPolyOverZ::from_str("[[1 -42, 0, 2 24 42],[3 1 12 4, 1 -1, 1 17]]").unwrap();
293 let c: MatPolyOverZ = a - b;
294 assert_eq!(
295 c,
296 MatPolyOverZ::from_str("[[1 42, 1 42, 2 18 -18],[3 16 12 38, 1 18, 1 25]]")
297 .unwrap()
298 );
299 }
300
301 #[test]
303 fn sub_borrow() {
304 let a: MatPolyOverZ =
305 MatPolyOverZ::from_str("[[0, 1 42, 2 42 24],[3 17 24 42, 1 17, 1 42]]").unwrap();
306 let b: MatPolyOverZ =
307 MatPolyOverZ::from_str("[[1 -42, 0, 2 24 42],[3 1 12 4, 1 -1, 1 17]]").unwrap();
308 let c: MatPolyOverZ = &a - &b;
309 assert_eq!(
310 c,
311 MatPolyOverZ::from_str("[[1 42, 1 42, 2 18 -18],[3 16 12 38, 1 18, 1 25]]")
312 .unwrap()
313 );
314 }
315
316 #[test]
318 fn sub_first_borrowed() {
319 let a: MatPolyOverZ =
320 MatPolyOverZ::from_str("[[0, 1 42, 2 42 24],[3 17 24 42, 1 17, 1 42]]").unwrap();
321 let b: MatPolyOverZ =
322 MatPolyOverZ::from_str("[[1 -42, 0, 2 24 42],[3 1 12 4, 1 -1, 1 17]]").unwrap();
323 let c: MatPolyOverZ = &a - b;
324 assert_eq!(
325 c,
326 MatPolyOverZ::from_str("[[1 42, 1 42, 2 18 -18],[3 16 12 38, 1 18, 1 25]]")
327 .unwrap()
328 );
329 }
330
331 #[test]
333 fn sub_second_borrowed() {
334 let a: MatPolyOverZ =
335 MatPolyOverZ::from_str("[[0, 1 42, 2 42 24],[3 17 24 42, 1 17, 1 42]]").unwrap();
336 let b: MatPolyOverZ =
337 MatPolyOverZ::from_str("[[1 -42, 0, 2 24 42],[3 1 12 4, 1 -1, 1 17]]").unwrap();
338 let c: MatPolyOverZ = a - &b;
339 assert_eq!(
340 c,
341 MatPolyOverZ::from_str("[[1 42, 1 42, 2 18 -18],[3 16 12 38, 1 18, 1 25]]")
342 .unwrap()
343 );
344 }
345
346 #[test]
348 fn sub_large_numbers() {
349 let a: MatPolyOverZ = MatPolyOverZ::from_str(&format!(
350 "[[1 {}, 2 1 {}],[2 -{} 7, 0]]",
351 i64::MAX,
352 i64::MIN,
353 u64::MAX
354 ))
355 .unwrap();
356 let b: MatPolyOverZ = MatPolyOverZ::from_str(&format!(
357 "[[1 {}, 2 1 {}],[2 {} 7, 0]]",
358 i64::MAX,
359 i64::MAX,
360 i64::MIN
361 ))
362 .unwrap();
363 let c: MatPolyOverZ = a - &b;
364 assert_eq!(
365 c,
366 MatPolyOverZ::from_str(&format!("[[0, 2 0 -{}],[1 -{}, 0]]", u64::MAX, i64::MAX))
367 .unwrap()
368 );
369 }
370
371 #[test]
373 fn sub_safe() {
374 let a: MatPolyOverZ =
375 MatPolyOverZ::from_str("[[0, 1 42, 2 42 24],[3 17 24 42, 1 17, 1 42]]").unwrap();
376 let b: MatPolyOverZ =
377 MatPolyOverZ::from_str("[[1 -42, 0, 2 24 42],[3 1 12 4, 1 -1, 1 17]]").unwrap();
378 let c: MatPolyOverZ = a.sub_safe(&b).unwrap();
379 assert_eq!(
380 c,
381 MatPolyOverZ::from_str("[[1 42, 1 42, 2 18 -18],[3 16 12 38, 1 18, 1 25]]")
382 .unwrap()
383 );
384 }
385
386 #[test]
388 fn sub_safe_is_err() {
389 let a: MatPolyOverZ =
390 MatPolyOverZ::from_str("[[0, 1 42, 2 42 24],[3 17 24 42, 1 17, 1 42]]").unwrap();
391 let b: MatPolyOverZ = MatPolyOverZ::from_str("[[1 -42, 0],[3 1 12 4, 1 17]]").unwrap();
392 let c: MatPolyOverZ = MatPolyOverZ::from_str("[[0, 1 42, 2 42 24]]").unwrap();
393 assert!(a.sub_safe(&b).is_err());
394 assert!(c.sub_safe(&b).is_err());
395 }
396}
397
398#[cfg(test)]
399mod test_mul_mat_poly_over_z {
400 use super::MatPolynomialRingZq;
401 use crate::{integer::MatPolyOverZ, integer_mod_q::ModulusPolynomialRingZq};
402 use std::str::FromStr;
403
404 const LARGE_PRIME: u64 = u64::MAX - 58;
405
406 #[test]
408 fn availability() {
409 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
410 let poly_mat = MatPolyOverZ::from_str("[[3 0 1 1, 1 3],[0, 2 1 2]]").unwrap();
411 let poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
412
413 let _ = &poly_mat - &poly_ring_mat;
414 let _ = &poly_mat - poly_ring_mat.clone();
415 let _ = poly_mat.clone() - &poly_ring_mat;
416 let _ = poly_mat.clone() - poly_ring_mat.clone();
417 }
418
419 #[test]
421 fn square_correctness() {
422 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
423 let poly_mat_1 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
424 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
425 let poly_mat_2 = MatPolyOverZ::from_str("[[2 1 1, 1 42],[0, 2 1 2]]").unwrap();
426
427 let poly_ring_mat_3 = &poly_mat_2 - &poly_ring_mat_1;
428
429 let poly_mat_cmp = MatPolyOverZ::from_str("[[3 -2 1 -1, 0],[0, 2 -16 2]]").unwrap();
430 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
431
432 assert_eq!(poly_ring_mat_cmp, poly_ring_mat_3);
433 }
434
435 #[test]
437 fn large_entries() {
438 let modulus =
439 ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {LARGE_PRIME}")).unwrap();
440 let poly_mat_1 = MatPolyOverZ::from_str(&format!("[[2 1 {}],[0]]", u64::MAX)).unwrap();
441 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
442 let poly_mat_2 = MatPolyOverZ::from_str(&format!("[[2 3 {}],[1 1]]", u64::MAX)).unwrap();
443
444 let poly_ring_mat_3 = &poly_mat_2 - &poly_ring_mat_1;
445
446 let poly_mat_cmp = MatPolyOverZ::from_str("[[2 2 0],[1 1]]").unwrap();
447 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
448
449 assert_eq!(poly_ring_mat_cmp, poly_ring_mat_3);
450 }
451
452 #[test]
455 fn errors() {
456 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
457 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 1],[2 1 2, 1 1]]").unwrap();
458 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
459 let poly_mat_2 = MatPolyOverZ::from_str("[[4 -1 0 1 1],[2 1 2]]").unwrap();
460
461 assert!((poly_mat_2.sub_mat_poly_ring_zq_safe(&poly_ring_mat_1)).is_err());
462 }
463
464 #[test]
466 #[should_panic]
467 fn mul_panic() {
468 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
469 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 1],[2 1 2, 1 1]]").unwrap();
470 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
471 let poly_mat_2 = MatPolyOverZ::from_str("[[1 3],[2 1 2]]").unwrap();
472
473 let _ = &poly_mat_2 - &poly_ring_mat_1;
474 }
475}