1use crate::error::MathError;
12use crate::integer::MatPolyOverZ;
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::{CompareBase, MatrixDimensions};
19use core::panic;
20use std::ops::{Sub, SubAssign};
21
22impl SubAssign<&MatPolynomialRingZq> for MatPolynomialRingZq {
23 fn sub_assign(&mut self, other: &Self) {
53 if !self.compare_base(other) {
54 panic!("{}", self.call_compare_base_error(other).unwrap());
55 }
56
57 self.matrix -= &other.matrix;
58
59 self.reduce();
60 }
61}
62impl SubAssign<&MatPolyOverZ> for MatPolynomialRingZq {
63 fn sub_assign(&mut self, other: &MatPolyOverZ) {
65 self.matrix -= other;
66
67 self.reduce();
68 }
69}
70
71arithmetic_assign_trait_borrowed_to_owned!(
72 SubAssign,
73 sub_assign,
74 MatPolynomialRingZq,
75 MatPolynomialRingZq
76);
77arithmetic_assign_trait_borrowed_to_owned!(
78 SubAssign,
79 sub_assign,
80 MatPolynomialRingZq,
81 MatPolyOverZ
82);
83
84impl Sub for &MatPolynomialRingZq {
85 type Output = MatPolynomialRingZq;
86 fn sub(self, other: Self) -> Self::Output {
118 self.sub_safe(other).unwrap()
119 }
120}
121
122arithmetic_trait_borrowed_to_owned!(
123 Sub,
124 sub,
125 MatPolynomialRingZq,
126 MatPolynomialRingZq,
127 MatPolynomialRingZq
128);
129arithmetic_trait_mixed_borrowed_owned!(
130 Sub,
131 sub,
132 MatPolynomialRingZq,
133 MatPolynomialRingZq,
134 MatPolynomialRingZq
135);
136
137impl Sub<&MatPolyOverZ> for &MatPolynomialRingZq {
138 type Output = MatPolynomialRingZq;
139 fn sub(self, other: &MatPolyOverZ) -> Self::Output {
162 self.sub_mat_poly_over_z_safe(other).unwrap()
163 }
164}
165
166arithmetic_trait_borrowed_to_owned!(
167 Sub,
168 sub,
169 MatPolynomialRingZq,
170 MatPolyOverZ,
171 MatPolynomialRingZq
172);
173arithmetic_trait_mixed_borrowed_owned!(
174 Sub,
175 sub,
176 MatPolynomialRingZq,
177 MatPolyOverZ,
178 MatPolynomialRingZq
179);
180
181impl MatPolynomialRingZq {
182 pub fn sub_safe(&self, other: &Self) -> Result<MatPolynomialRingZq, MathError> {
212 if !self.compare_base(other) {
213 return Err(self.call_compare_base_error(other).unwrap());
214 }
215 let matrix = self.matrix.sub_safe(&other.matrix)?;
216
217 Ok(MatPolynomialRingZq::from((&matrix, &self.modulus)))
218 }
219
220 pub fn sub_mat_poly_over_z_safe(&self, other: &MatPolyOverZ) -> Result<Self, MathError> {
244 let mut out =
245 MatPolynomialRingZq::new(self.get_num_rows(), self.get_num_columns(), self.get_mod());
246
247 out.matrix = self.matrix.sub_safe(other)?;
248 out.reduce();
249
250 Ok(out)
251 }
252}
253
254#[cfg(test)]
255mod test_sub_assign {
256 use crate::{
257 integer::MatPolyOverZ,
258 integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq},
259 };
260 use std::str::FromStr;
261
262 #[test]
264 fn correct_small() {
265 let mut a = MatPolynomialRingZq::from_str("[[1 1, 0],[0, 1 1]] / 2 0 1 mod 7").unwrap();
266 let b = MatPolynomialRingZq::from_str("[[1 -4, 1 -5],[1 6, 2 -6 -1]] / 2 0 1 mod 7")
267 .unwrap();
268 let cmp = MatPolynomialRingZq::from_str("[[1 5, 1 5],[1 1, 0]] / 2 0 1 mod 7").unwrap();
269
270 a -= b;
271
272 assert_eq!(cmp, a);
273 }
274
275 #[test]
277 fn correct_large() {
278 let mut a = MatPolynomialRingZq::from_str(&format!(
279 "[[1 {}, 1 5],[1 {}, 1 -1]] / 2 0 1 mod {}",
280 i64::MAX,
281 i64::MIN,
282 u64::MAX
283 ))
284 .unwrap();
285 let b = MatPolynomialRingZq::from_str(&format!(
286 "[[1 -{}, 1 6],[1 -6, 1 1]] / 2 0 1 mod {}",
287 i64::MAX,
288 u64::MAX
289 ))
290 .unwrap();
291 let cmp = MatPolynomialRingZq::from_str(&format!(
292 "[[1 {}, 1 -1],[1 {}, 1 -2]] / 2 0 1 mod {}",
293 2 * (i64::MAX as u64),
294 i64::MIN + 6,
295 u64::MAX
296 ))
297 .unwrap();
298
299 a -= b;
300
301 assert_eq!(cmp, a);
302 }
303
304 #[test]
306 fn matrix_dimensions() {
307 let modulus = ModulusPolynomialRingZq::from_str("3 1 0 1 mod 7").unwrap();
308 let dimensions = [(3, 3), (5, 1), (1, 4)];
309
310 for (nr_rows, nr_cols) in dimensions {
311 let mut a = MatPolynomialRingZq::identity(nr_rows, nr_cols, &modulus);
312 let b = MatPolynomialRingZq::new(nr_rows, nr_cols, &modulus);
313
314 a -= b;
315
316 assert_eq!(MatPolynomialRingZq::identity(nr_rows, nr_cols, &modulus), a);
317 }
318 }
319
320 #[test]
322 #[should_panic]
323 fn mismatching_dimensions() {
324 let modulus = ModulusPolynomialRingZq::from_str("3 1 0 1 mod 7").unwrap();
325 let mut a = MatPolynomialRingZq::new(2, 1, &modulus);
326 let b = MatPolynomialRingZq::new(1, 1, &modulus);
327
328 a -= b;
329 }
330
331 #[test]
333 #[should_panic]
334 fn mismatching_moduli() {
335 let modulus_0 = ModulusPolynomialRingZq::from_str("3 1 0 1 mod 7").unwrap();
336 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 7").unwrap();
337 let mut a = MatPolynomialRingZq::new(1, 1, &modulus_0);
338 let b = MatPolynomialRingZq::new(1, 1, &modulus_1);
339
340 a -= b;
341 }
342
343 #[test]
345 fn availability() {
346 let modulus = ModulusPolynomialRingZq::from_str("3 1 0 1 mod 7").unwrap();
347 let mut a = MatPolynomialRingZq::new(2, 2, &modulus);
348 let b = MatPolynomialRingZq::new(2, 2, &modulus);
349 let c = MatPolyOverZ::new(2, 2);
350
351 a -= &b;
352 a -= b;
353 a -= &c;
354 a -= c;
355 }
356}
357
358#[cfg(test)]
359mod test_sub {
360 use crate::{
361 integer::MatPolyOverZ,
362 integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq},
363 };
364 use std::str::FromStr;
365
366 #[test]
368 fn sub() {
369 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
370 let poly_mat_1 = MatPolyOverZ::from_str("[[3 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
371 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
372 let poly_mat_2 = MatPolyOverZ::from_str("[[2 0 1, 1 42],[2 3 4, 2 0 1]]").unwrap();
373 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus));
374
375 let poly_ring_mat_3 = poly_ring_mat_1 - poly_ring_mat_2;
376
377 let cmp_poly_mat = MatPolyOverZ::from_str("[[3 0 0 1, 0],[2 -3 -4, 2 1 1]]").unwrap();
378 let cmp_poly_ring_mat = MatPolynomialRingZq::from((&cmp_poly_mat, &modulus));
379 assert_eq!(cmp_poly_ring_mat, poly_ring_mat_3);
380 }
381
382 #[test]
384 fn sub_large_numbers() {
385 let modulus =
386 ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {}", u64::MAX)).unwrap();
387 let poly_mat_1 =
388 MatPolyOverZ::from_str(&format!("[[3 0 {} 1, 1 42],[0, 2 1 2]]", i64::MAX)).unwrap();
389 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
390 let poly_mat_2 =
391 MatPolyOverZ::from_str(&format!("[[2 0 {}, 1 42],[2 3 4, 2 0 1]]", i64::MAX))
392 .unwrap();
393 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus));
394
395 let poly_ring_mat_3 = poly_ring_mat_1 - poly_ring_mat_2;
396
397 let cmp_poly_mat = MatPolyOverZ::from_str("[[3 0 0 1, 0],[2 -3 -4, 2 1 1]]").unwrap();
398 let cmp_poly_ring_mat = MatPolynomialRingZq::from((&cmp_poly_mat, &modulus));
399 assert_eq!(cmp_poly_ring_mat, poly_ring_mat_3);
400 }
401
402 #[test]
404 fn sub_safe() {
405 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
406 let poly_mat_1 = MatPolyOverZ::from_str("[[3 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
407 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
408 let poly_mat_2 = MatPolyOverZ::from_str("[[2 0 1, 1 42],[2 3 4, 2 0 1]]").unwrap();
409 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus));
410
411 let poly_ring_mat_3 = poly_ring_mat_1.sub_safe(&poly_ring_mat_2).unwrap();
412
413 let cmp_poly_mat = MatPolyOverZ::from_str("[[3 0 0 1, 0],[2 -3 -4, 2 1 1]]").unwrap();
414 let cmp_poly_ring_mat = MatPolynomialRingZq::from((&cmp_poly_mat, &modulus));
415 assert_eq!(cmp_poly_ring_mat, poly_ring_mat_3);
416 }
417
418 #[test]
420 fn sub_safe_error_dim() {
421 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
422 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
423 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
424 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42, 0],[0, 1 17, 1 1]]").unwrap();
425 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus));
426 let poly_mat_3 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42, 0]]").unwrap();
427 let poly_ring_mat_3 = MatPolynomialRingZq::from((&poly_mat_3, &modulus));
428
429 assert!(poly_ring_mat_1.sub_safe(&poly_ring_mat_2).is_err());
430 assert!(poly_ring_mat_3.sub_safe(&poly_ring_mat_2).is_err());
431 }
432
433 #[test]
435 fn sub_safe_error_modulus() {
436 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
437 let modulus_2 = ModulusPolynomialRingZq::from_str("4 1 0 1 1 mod 17").unwrap();
438 let modulus_3 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 18").unwrap();
439 let poly_mat = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
440 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat, &modulus_1));
441 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat, &modulus_2));
442 let poly_ring_mat_3 = MatPolynomialRingZq::from((&poly_mat, &modulus_3));
443
444 assert!(poly_ring_mat_1.sub_safe(&poly_ring_mat_2).is_err());
445 assert!(poly_ring_mat_3.sub_safe(&poly_ring_mat_2).is_err());
446 }
447
448 #[test]
450 fn doc_test() {
451 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
452 let poly_mat_1 = MatPolyOverZ::from_str("[[3 0 1 1, 1 3],[0, 2 1 2]]").unwrap();
453 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
454 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 7],[0, 1 16]]").unwrap();
455 let poly_ring_mat_2 = MatPolynomialRingZq::from((&poly_mat_2, &modulus));
456
457 let poly_ring_mat_3: MatPolynomialRingZq = &poly_ring_mat_1 - &poly_ring_mat_2;
458 let poly_ring_mat_4: MatPolynomialRingZq = poly_ring_mat_1 - poly_ring_mat_2;
459 let poly_ring_mat_5: MatPolynomialRingZq = &poly_ring_mat_3 - poly_ring_mat_4;
460 let _poly_ring_mat_6: MatPolynomialRingZq = poly_ring_mat_3 - &poly_ring_mat_5;
461 }
462}
463
464#[cfg(test)]
465mod test_mul_mat_poly_over_z {
466 use super::MatPolynomialRingZq;
467 use crate::{integer::MatPolyOverZ, integer_mod_q::ModulusPolynomialRingZq};
468 use std::str::FromStr;
469
470 const LARGE_PRIME: u64 = u64::MAX - 58;
471
472 #[test]
474 fn availability() {
475 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
476 let poly_mat = MatPolyOverZ::from_str("[[3 0 1 1, 1 3],[0, 2 1 2]]").unwrap();
477 let poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
478
479 let _ = &poly_ring_mat - &poly_mat;
480 let _ = &poly_ring_mat - poly_mat.clone();
481 let _ = poly_ring_mat.clone() - &poly_mat;
482 let _ = poly_ring_mat - poly_mat;
483 }
484
485 #[test]
487 fn square_correctness() {
488 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
489 let poly_mat_1 = MatPolyOverZ::from_str("[[2 1 1, 1 42],[0, 2 1 2]]").unwrap();
490 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
491 let poly_mat_2 = MatPolyOverZ::from_str("[[3 3 0 1, 1 42],[0, 1 17]]").unwrap();
492
493 let poly_ring_mat_3 = &poly_ring_mat_1 - &poly_mat_2;
494
495 let poly_mat_cmp = MatPolyOverZ::from_str("[[3 -2 1 -1, 0],[0, 2 -16 2]]").unwrap();
496 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
497
498 assert_eq!(poly_ring_mat_cmp, poly_ring_mat_3);
499 }
500
501 #[test]
503 fn large_entries() {
504 let modulus =
505 ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {LARGE_PRIME}")).unwrap();
506 let poly_mat_1 = MatPolyOverZ::from_str(&format!("[[2 3 {}],[1 1]]", u64::MAX)).unwrap();
507 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus));
508 let poly_mat_2 = MatPolyOverZ::from_str(&format!("[[2 1 {}],[0]]", u64::MAX)).unwrap();
509
510 let poly_ring_mat_3 = &poly_ring_mat_1 - &poly_mat_2;
511
512 let poly_mat_cmp = MatPolyOverZ::from_str("[[2 2 0],[1 1]]").unwrap();
513 let poly_ring_mat_cmp = MatPolynomialRingZq::from((&poly_mat_cmp, &modulus));
514
515 assert_eq!(poly_ring_mat_cmp, poly_ring_mat_3);
516 }
517
518 #[test]
521 fn errors() {
522 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
523 let poly_mat_1 = MatPolyOverZ::from_str("[[4 -1 0 1 1],[2 1 2]]").unwrap();
524 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
525 let poly_mat_2 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 1],[2 1 2, 1 1]]").unwrap();
526
527 assert!((poly_ring_mat_1.sub_mat_poly_over_z_safe(&poly_mat_2)).is_err());
528 }
529
530 #[test]
532 #[should_panic]
533 fn mul_panic() {
534 let modulus_1 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
535 let poly_mat_1 = MatPolyOverZ::from_str("[[1 3],[2 1 2]]").unwrap();
536 let poly_ring_mat_1 = MatPolynomialRingZq::from((&poly_mat_1, &modulus_1));
537 let poly_mat_2 = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 1],[2 1 2, 1 1]]").unwrap();
538
539 let _ = &poly_ring_mat_1 - &poly_mat_2;
540 }
541}