qfall_math/integer_mod_q/polynomial_ring_zq/arithmetic/
sub.rs1use super::super::PolynomialRingZq;
12use crate::{
13 error::MathError,
14 integer::PolyOverZ,
15 integer_mod_q::PolyOverZq,
16 macros::arithmetics::{
17 arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
18 arithmetic_trait_mixed_borrowed_owned,
19 },
20 traits::CompareBase,
21};
22use flint_sys::fq::fq_sub;
23use std::ops::{Sub, SubAssign};
24
25impl SubAssign<&PolynomialRingZq> for PolynomialRingZq {
26 fn sub_assign(&mut self, other: &Self) {
60 if !self.compare_base(other) {
61 panic!("{}", self.call_compare_base_error(other).unwrap());
62 }
63
64 unsafe {
65 fq_sub(
66 &mut self.poly.poly,
67 &self.poly.poly,
68 &other.poly.poly,
69 self.modulus.get_fq_ctx(),
70 );
71 };
72 }
73}
74impl SubAssign<&PolyOverZ> for PolynomialRingZq {
75 fn sub_assign(&mut self, other: &PolyOverZ) {
77 self.poly -= other;
78 self.reduce();
79 }
80}
81impl SubAssign<&PolyOverZq> for PolynomialRingZq {
82 fn sub_assign(&mut self, other: &PolyOverZq) {
87 if !self.compare_base(other) {
88 panic!("{}", self.call_compare_base_error(other).unwrap())
89 }
90 let other = other.get_representative_least_nonnegative_residue();
92
93 unsafe {
94 fq_sub(
95 &mut self.poly.poly,
96 &self.poly.poly,
97 &other.poly,
98 self.modulus.get_fq_ctx(),
99 );
100 };
101 }
102}
103
104arithmetic_assign_trait_borrowed_to_owned!(
105 SubAssign,
106 sub_assign,
107 PolynomialRingZq,
108 PolynomialRingZq
109);
110arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, PolynomialRingZq, PolyOverZ);
111arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, PolynomialRingZq, PolyOverZq);
112
113impl Sub for &PolynomialRingZq {
114 type Output = PolynomialRingZq;
115 fn sub(self, other: Self) -> Self::Output {
145 self.sub_safe(other).unwrap()
146 }
147}
148
149impl Sub<&PolyOverZ> for &PolynomialRingZq {
150 type Output = PolynomialRingZq;
151 fn sub(self, other: &PolyOverZ) -> Self::Output {
174 let mut out = PolynomialRingZq::from((&PolyOverZ::default(), &self.modulus));
175 unsafe {
176 fq_sub(
177 &mut out.poly.poly,
178 &self.poly.poly,
179 &other.poly,
180 self.modulus.get_fq_ctx(),
181 );
182 }
183 out
184 }
185}
186
187arithmetic_trait_borrowed_to_owned!(Sub, sub, PolynomialRingZq, PolyOverZ, PolynomialRingZq);
188arithmetic_trait_mixed_borrowed_owned!(Sub, sub, PolynomialRingZq, PolyOverZ, PolynomialRingZq);
189
190impl Sub<&PolyOverZq> for &PolynomialRingZq {
191 type Output = PolynomialRingZq;
192 fn sub(self, other: &PolyOverZq) -> Self::Output {
218 assert_eq!(
219 self.modulus.get_q(),
220 other.modulus,
221 "Tried to subtract polynomials with different moduli."
222 );
223
224 let mut out = PolynomialRingZq::from((&PolyOverZ::default(), &self.modulus));
225 unsafe {
226 fq_sub(
227 &mut out.poly.poly,
228 &self.poly.poly,
229 &other.get_representative_least_nonnegative_residue().poly,
230 self.modulus.get_fq_ctx(),
231 );
232 }
233 out
234 }
235}
236
237arithmetic_trait_borrowed_to_owned!(Sub, sub, PolynomialRingZq, PolyOverZq, PolynomialRingZq);
238arithmetic_trait_mixed_borrowed_owned!(Sub, sub, PolynomialRingZq, PolyOverZq, PolynomialRingZq);
239
240impl PolynomialRingZq {
241 pub fn sub_safe(&self, other: &Self) -> Result<PolynomialRingZq, MathError> {
268 if !self.compare_base(other) {
269 return Err(self.call_compare_base_error(other).unwrap());
270 }
271 let mut out = PolynomialRingZq::from((&PolyOverZ::default(), &self.modulus));
272 unsafe {
273 fq_sub(
274 &mut out.poly.poly,
275 &self.poly.poly,
276 &other.poly.poly,
277 self.modulus.get_fq_ctx(),
278 );
279 }
280 Ok(out)
281 }
282}
283
284arithmetic_trait_borrowed_to_owned!(
285 Sub,
286 sub,
287 PolynomialRingZq,
288 PolynomialRingZq,
289 PolynomialRingZq
290);
291arithmetic_trait_mixed_borrowed_owned!(
292 Sub,
293 sub,
294 PolynomialRingZq,
295 PolynomialRingZq,
296 PolynomialRingZq
297);
298
299#[cfg(test)]
300mod test_sub_assign {
301 use super::PolyOverZ;
302 use crate::integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq, PolynomialRingZq};
303 use std::str::FromStr;
304
305 #[test]
307 fn correct_small() {
308 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
309 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
310 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
311 let poly_2 = PolyOverZ::from_str("4 -2 0 -3 1").unwrap();
312 let b = PolynomialRingZq::from((&poly_2, &modulus));
313 let cmp = PolynomialRingZq::from((&PolyOverZ::from_str("3 1 0 4").unwrap(), &modulus));
314
315 a -= b;
316
317 assert_eq!(cmp, a);
318 }
319
320 #[test]
322 fn correct_large() {
323 let modulus = ModulusPolynomialRingZq::from_str(&format!(
324 "4 {} 0 0 {} mod {}",
325 u64::MAX,
326 i64::MIN,
327 u64::MAX - 58
328 ))
329 .unwrap();
330 let poly_1 = PolyOverZ::from_str(&format!("4 {} 0 1 {}", u64::MAX, i64::MIN)).unwrap();
331 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
332 let poly_2 = PolyOverZ::from_str(&format!("4 -{} 0 1 -{}", i64::MAX, i64::MAX)).unwrap();
333 let b = PolynomialRingZq::from((&poly_2, &modulus));
334 let cmp = PolynomialRingZq::from((
335 &PolyOverZ::from_str(&format!("4 {} 0 0 {}", (u64::MAX - 1) / 2 + 58, -1)).unwrap(),
336 &modulus,
337 ));
338
339 a -= b;
340
341 assert_eq!(cmp, a);
342 }
343
344 #[test]
346 fn availability() {
347 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
348 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
349 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
350 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
351 let b = PolynomialRingZq::from((&poly_2, &modulus));
352 let c = PolyOverZq::from((poly_2, 17));
353
354 a -= &b;
355 a -= b;
356 a -= &poly_1;
357 a -= poly_1;
358 a -= &c;
359 a -= c;
360 }
361
362 #[test]
364 #[should_panic]
365 fn mismatching_moduli() {
366 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
367 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
368 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
369 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 2 mod 17").unwrap();
370 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
371 let b = PolynomialRingZq::from((&poly_2, &modulus));
372
373 a -= b;
374 }
375}
376
377#[cfg(test)]
378mod test_sub {
379 use crate::integer::PolyOverZ;
380 use crate::integer_mod_q::ModulusPolynomialRingZq;
381 use crate::integer_mod_q::PolynomialRingZq;
382 use std::str::FromStr;
383
384 #[test]
386 fn sub() {
387 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
388 let poly_1 = PolyOverZ::from_str("4 -1 0 1 2").unwrap();
389 let a = PolynomialRingZq::from((&poly_1, &modulus));
390 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
391 let b = PolynomialRingZq::from((&poly_2, &modulus));
392 let c = a - b;
393 assert_eq!(
394 c,
395 PolynomialRingZq::from((&PolyOverZ::from_str("4 -3 0 -2 1").unwrap(), &modulus))
396 );
397 }
398
399 #[test]
401 fn sub_borrow() {
402 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
403 let poly_1 = PolyOverZ::from_str("4 -1 0 1 2").unwrap();
404 let a = PolynomialRingZq::from((&poly_1, &modulus));
405 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
406 let b = PolynomialRingZq::from((&poly_2, &modulus));
407 let c = &a - &b;
408 assert_eq!(
409 c,
410 PolynomialRingZq::from((&PolyOverZ::from_str("4 -3 0 -2 1").unwrap(), &modulus))
411 );
412 }
413
414 #[test]
416 fn sub_first_borrowed() {
417 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
418 let poly_1 = PolyOverZ::from_str("4 -1 0 1 2").unwrap();
419 let a = PolynomialRingZq::from((&poly_1, &modulus));
420 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
421 let b = PolynomialRingZq::from((&poly_2, &modulus));
422 let c = &a - b;
423 assert_eq!(
424 c,
425 PolynomialRingZq::from((&PolyOverZ::from_str("4 -3 0 -2 1").unwrap(), &modulus))
426 );
427 }
428
429 #[test]
431 fn sub_second_borrowed() {
432 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
433 let poly_1 = PolyOverZ::from_str("4 -1 0 1 2").unwrap();
434 let a = PolynomialRingZq::from((&poly_1, &modulus));
435 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
436 let b = PolynomialRingZq::from((&poly_2, &modulus));
437 let c = a - &b;
438 assert_eq!(
439 c,
440 PolynomialRingZq::from((&PolyOverZ::from_str("4 -3 0 -2 1").unwrap(), &modulus))
441 );
442 }
443
444 #[test]
446 fn sub_reduce() {
447 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
448 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
449 let a = PolynomialRingZq::from((&poly_1, &modulus));
450 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
451 let b = PolynomialRingZq::from((&poly_2, &modulus));
452 let c = a - &b;
453 assert_eq!(
454 c,
455 PolynomialRingZq::from((&PolyOverZ::from_str("3 -3 0 -2").unwrap(), &modulus))
456 );
457 }
458
459 #[test]
461 fn sub_large_numbers() {
462 let modulus = ModulusPolynomialRingZq::from_str(&format!(
463 "4 {} 0 0 {} mod {}",
464 u64::MAX,
465 i64::MIN + 12,
466 u64::MAX - 58
467 ))
468 .unwrap();
469
470 let poly_1 = PolyOverZ::from_str(&format!("4 {} 0 1 {}", u64::MAX, i64::MIN)).unwrap();
471 let a = PolynomialRingZq::from((&poly_1, &modulus));
472
473 let poly_2 = PolyOverZ::from_str(&format!("4 {} 0 -1 {}", i64::MAX, i64::MAX)).unwrap();
474 let b = PolynomialRingZq::from((&poly_2, &modulus));
475
476 let c = a - b;
477
478 assert_eq!(
479 c,
480 PolynomialRingZq::from((
481 &PolyOverZ::from_str(&format!(
482 "4 {} 0 2 {}",
483 (u64::MAX - 1) / 2 + 1,
484 -18446744073709551615_i128
485 ))
486 .unwrap(),
487 &modulus
488 ))
489 );
490 }
491
492 #[test]
494 #[should_panic]
495 fn sub_mismatching_modulus() {
496 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
497 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
498 let a = PolynomialRingZq::from((&poly_1, &modulus));
499 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 2 mod 17").unwrap();
500 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
501 let b = PolynomialRingZq::from((&poly_2, &modulus));
502 let _ = a - b;
503 }
504
505 #[test]
507 fn sub_safe_is_err() {
508 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
509 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
510 let a = PolynomialRingZq::from((&poly_1, &modulus));
511 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 2 mod 17").unwrap();
512 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
513 let b = PolynomialRingZq::from((&poly_2, &modulus));
514
515 assert!(&a.sub_safe(&b).is_err());
516 }
517}
518
519#[cfg(test)]
520mod test_sub_poly_over_z {
521 use super::PolynomialRingZq;
522 use crate::integer::PolyOverZ;
523 use std::str::FromStr;
524
525 #[test]
527 fn borrowed_correctness() {
528 let poly_1 =
529 PolynomialRingZq::from_str(&format!("2 2 {} / 4 1 2 3 4 mod {}", i64::MAX, u64::MAX))
530 .unwrap();
531 let poly_2 = PolynomialRingZq::from_str(&format!(
532 "2 1 {} / 4 1 2 3 4 mod {}",
533 i64::MAX as u64 - 2,
534 u64::MAX
535 ))
536 .unwrap();
537 let poly = PolyOverZ::from_str("2 1 2").unwrap();
538
539 let poly_1 = &poly_1 - &poly;
540
541 assert_eq!(poly_2, poly_1);
542 }
543
544 #[test]
546 fn availability() {
547 let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 4 mod 17").unwrap();
548 let z = PolyOverZ::from(2);
549
550 _ = poly.clone() - z.clone();
551 _ = &poly - &z;
552 _ = &poly - z.clone();
553 _ = poly.clone() - &z;
554 }
555}
556
557#[cfg(test)]
558mod test_sub_poly_over_zq {
559 use super::PolynomialRingZq;
560 use crate::integer_mod_q::PolyOverZq;
561 use std::str::FromStr;
562
563 #[test]
565 fn borrowed_correctness() {
566 let poly_1 =
567 PolynomialRingZq::from_str(&format!("2 2 {} / 4 1 2 3 4 mod {}", i64::MAX, u64::MAX))
568 .unwrap();
569 let poly_2 = PolynomialRingZq::from_str(&format!(
570 "2 1 {} / 4 1 2 3 4 mod {}",
571 i64::MAX as u64 - 2,
572 u64::MAX
573 ))
574 .unwrap();
575 let poly = PolyOverZq::from_str(&format!("2 1 2 mod {}", u64::MAX)).unwrap();
576
577 let poly_1 = &poly_1 - &poly;
578
579 assert_eq!(poly_2, poly_1);
580 }
581
582 #[test]
584 fn availability() {
585 let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 4 mod 17").unwrap();
586 let zq = PolyOverZq::from((2, 17));
587
588 _ = poly.clone() - zq.clone();
589 _ = &poly - &zq;
590 _ = &poly - zq.clone();
591 _ = poly.clone() - &zq;
592 }
593
594 #[test]
596 #[should_panic]
597 fn different_moduli_panic() {
598 let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 4 mod 17").unwrap();
599 let zq = PolyOverZq::from((2, 16));
600
601 _ = &poly - &zq;
602 }
603}