1use 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, arithmetic_trait_reverse,
19 },
20 traits::CompareBase,
21};
22use flint_sys::fq::fq_add;
23use std::ops::{Add, AddAssign};
24
25impl AddAssign<&PolynomialRingZq> for PolynomialRingZq {
26 fn add_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_add(
66 &mut self.poly.poly,
67 &self.poly.poly,
68 &other.poly.poly,
69 self.modulus.get_fq_ctx(),
70 );
71 };
72 }
73}
74impl AddAssign<&PolyOverZ> for PolynomialRingZq {
75 fn add_assign(&mut self, other: &PolyOverZ) {
77 self.poly += other;
78 self.reduce();
79 }
80}
81impl AddAssign<&PolyOverZq> for PolynomialRingZq {
82 fn add_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_add(
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 AddAssign,
106 add_assign,
107 PolynomialRingZq,
108 PolynomialRingZq
109);
110arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, PolynomialRingZq, PolyOverZ);
111arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, PolynomialRingZq, PolyOverZq);
112
113impl Add for &PolynomialRingZq {
114 type Output = PolynomialRingZq;
115 fn add(self, other: Self) -> Self::Output {
145 self.add_safe(other).unwrap()
146 }
147}
148
149impl Add<&PolyOverZ> for &PolynomialRingZq {
150 type Output = PolynomialRingZq;
151 fn add(self, other: &PolyOverZ) -> Self::Output {
174 let mut out = PolynomialRingZq::from((&PolyOverZ::default(), &self.modulus));
175 unsafe {
176 fq_add(
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_reverse!(Add, add, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
188
189arithmetic_trait_borrowed_to_owned!(Add, add, PolynomialRingZq, PolyOverZ, PolynomialRingZq);
190arithmetic_trait_borrowed_to_owned!(Add, add, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
191arithmetic_trait_mixed_borrowed_owned!(Add, add, PolynomialRingZq, PolyOverZ, PolynomialRingZq);
192arithmetic_trait_mixed_borrowed_owned!(Add, add, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
193
194impl Add<&PolyOverZq> for &PolynomialRingZq {
195 type Output = PolynomialRingZq;
196 fn add(self, other: &PolyOverZq) -> Self::Output {
222 assert_eq!(
223 self.modulus.get_q(),
224 other.modulus,
225 "Tried to add polynomials with different moduli."
226 );
227
228 let mut out = PolynomialRingZq::from((&PolyOverZ::default(), &self.modulus));
229 unsafe {
230 fq_add(
231 &mut out.poly.poly,
232 &self.poly.poly,
233 &other.get_representative_least_nonnegative_residue().poly,
234 self.modulus.get_fq_ctx(),
235 );
236 }
237 out
238 }
239}
240
241arithmetic_trait_reverse!(Add, add, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
242
243arithmetic_trait_borrowed_to_owned!(Add, add, PolynomialRingZq, PolyOverZq, PolynomialRingZq);
244arithmetic_trait_borrowed_to_owned!(Add, add, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
245arithmetic_trait_mixed_borrowed_owned!(Add, add, PolynomialRingZq, PolyOverZq, PolynomialRingZq);
246arithmetic_trait_mixed_borrowed_owned!(Add, add, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
247
248impl PolynomialRingZq {
249 pub fn add_safe(&self, other: &Self) -> Result<PolynomialRingZq, MathError> {
276 if !self.compare_base(other) {
277 return Err(self.call_compare_base_error(other).unwrap());
278 }
279 let mut out = PolynomialRingZq::from((&PolyOverZ::default(), &self.modulus));
280 unsafe {
281 fq_add(
282 &mut out.poly.poly,
283 &self.poly.poly,
284 &other.poly.poly,
285 self.modulus.get_fq_ctx(),
286 );
287 }
288 Ok(out)
289 }
290}
291
292arithmetic_trait_borrowed_to_owned!(
293 Add,
294 add,
295 PolynomialRingZq,
296 PolynomialRingZq,
297 PolynomialRingZq
298);
299arithmetic_trait_mixed_borrowed_owned!(
300 Add,
301 add,
302 PolynomialRingZq,
303 PolynomialRingZq,
304 PolynomialRingZq
305);
306
307#[cfg(test)]
308mod test_add_assign {
309 use super::PolyOverZ;
310 use crate::integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq, PolynomialRingZq};
311 use std::str::FromStr;
312
313 #[test]
315 fn correct_small() {
316 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
317 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
318 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
319 let poly_2 = PolyOverZ::from_str("4 2 0 3 -1").unwrap();
320 let b = PolynomialRingZq::from((&poly_2, &modulus));
321 let cmp = PolynomialRingZq::from((&PolyOverZ::from_str("3 1 0 4").unwrap(), &modulus));
322
323 a += b;
324
325 assert_eq!(cmp, a);
326 }
327
328 #[test]
330 fn correct_large() {
331 let modulus = ModulusPolynomialRingZq::from_str(&format!(
332 "4 {} 0 0 {} mod {}",
333 u64::MAX,
334 i64::MIN,
335 u64::MAX - 58
336 ))
337 .unwrap();
338 let poly_1 = PolyOverZ::from_str(&format!("4 {} 0 1 {}", u64::MAX, i64::MIN)).unwrap();
339 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
340 let poly_2 = PolyOverZ::from_str(&format!("4 {} 0 -1 {}", i64::MAX, i64::MAX)).unwrap();
341 let b = PolynomialRingZq::from((&poly_2, &modulus));
342 let cmp = PolynomialRingZq::from((
343 &PolyOverZ::from_str(&format!("4 {} 0 0 {}", (u64::MAX - 1) / 2 + 58, -1)).unwrap(),
344 &modulus,
345 ));
346
347 a += b;
348
349 assert_eq!(cmp, a);
350 }
351
352 #[test]
354 fn availability() {
355 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
356 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
357 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
358 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
359 let b = PolynomialRingZq::from((&poly_2, &modulus));
360 let c = PolyOverZq::from((poly_2, 17));
361
362 a += &b;
363 a += b;
364 a += &poly_1;
365 a += poly_1;
366 a += &c;
367 a += c;
368 }
369
370 #[test]
372 #[should_panic]
373 fn mismatching_moduli() {
374 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
375 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
376 let mut a = PolynomialRingZq::from((&poly_1, &modulus));
377 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 2 mod 17").unwrap();
378 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
379 let b = PolynomialRingZq::from((&poly_2, &modulus));
380
381 a += b;
382 }
383}
384
385#[cfg(test)]
386mod test_add {
387 use crate::integer::PolyOverZ;
388 use crate::integer_mod_q::ModulusPolynomialRingZq;
389 use crate::integer_mod_q::PolynomialRingZq;
390 use std::str::FromStr;
391
392 #[test]
394 fn add() {
395 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
396 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
397 let a = PolynomialRingZq::from((&poly_1, &modulus));
398 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
399 let b = PolynomialRingZq::from((&poly_2, &modulus));
400 let c = a + b;
401 assert_eq!(
402 c,
403 PolynomialRingZq::from((&PolyOverZ::from_str("4 1 0 4 2").unwrap(), &modulus))
404 );
405 }
406
407 #[test]
409 fn add_borrow() {
410 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
411 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
412 let a = PolynomialRingZq::from((&poly_1, &modulus));
413 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
414 let b = PolynomialRingZq::from((&poly_2, &modulus));
415 let c = &a + &b;
416 assert_eq!(
417 c,
418 PolynomialRingZq::from((&PolyOverZ::from_str("4 1 0 4 2").unwrap(), &modulus))
419 );
420 }
421
422 #[test]
424 fn add_first_borrowed() {
425 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
426 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
427 let a = PolynomialRingZq::from((&poly_1, &modulus));
428 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
429 let b = PolynomialRingZq::from((&poly_2, &modulus));
430 let c = &a + b;
431 assert_eq!(
432 c,
433 PolynomialRingZq::from((&PolyOverZ::from_str("4 1 0 4 2").unwrap(), &modulus))
434 );
435 }
436
437 #[test]
439 fn add_second_borrowed() {
440 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
441 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
442 let a = PolynomialRingZq::from((&poly_1, &modulus));
443 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
444 let b = PolynomialRingZq::from((&poly_2, &modulus));
445 let c = a + &b;
446 assert_eq!(
447 c,
448 PolynomialRingZq::from((&PolyOverZ::from_str("4 1 0 4 2").unwrap(), &modulus))
449 );
450 }
451
452 #[test]
454 fn add_reduce() {
455 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
456 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
457 let a = PolynomialRingZq::from((&poly_1, &modulus));
458 let poly_2 = PolyOverZ::from_str("4 2 0 3 -1").unwrap();
459 let b = PolynomialRingZq::from((&poly_2, &modulus));
460 let c = a + &b;
461 assert_eq!(
462 c,
463 PolynomialRingZq::from((&PolyOverZ::from_str("3 1 0 4").unwrap(), &modulus))
464 );
465 }
466
467 #[test]
469 fn add_large_numbers() {
470 let modulus = ModulusPolynomialRingZq::from_str(&format!(
471 "4 {} 0 0 {} mod {}",
472 u64::MAX,
473 i64::MIN,
474 u64::MAX - 58
475 ))
476 .unwrap();
477
478 let poly_1 = PolyOverZ::from_str(&format!("4 {} 0 1 {}", u64::MAX, i64::MIN)).unwrap();
479 let a = PolynomialRingZq::from((&poly_1, &modulus));
480
481 let poly_2 = PolyOverZ::from_str(&format!("4 {} 0 -1 {}", i64::MAX, i64::MAX)).unwrap();
482 let b = PolynomialRingZq::from((&poly_2, &modulus));
483
484 let c = a + b;
485 assert_eq!(
486 c,
487 PolynomialRingZq::from((
488 &PolyOverZ::from_str(&format!("4 {} 0 0 {}", (u64::MAX - 1) / 2 + 58, -1))
489 .unwrap(),
490 &modulus
491 ))
492 );
493 }
494
495 #[test]
497 #[should_panic]
498 fn add_mismatching_modulus() {
499 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
500 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
501 let a = PolynomialRingZq::from((&poly_1, &modulus));
502 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 2 mod 17").unwrap();
503 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
504 let b = PolynomialRingZq::from((&poly_2, &modulus));
505 let _ = a + b;
506 }
507
508 #[test]
510 fn add_safe_is_err() {
511 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
512 let poly_1 = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
513 let a = PolynomialRingZq::from((&poly_1, &modulus));
514 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 2 mod 17").unwrap();
515 let poly_2 = PolyOverZ::from_str("4 2 0 3 1").unwrap();
516 let b = PolynomialRingZq::from((&poly_2, &modulus));
517
518 assert!(&a.add_safe(&b).is_err());
519 }
520}
521
522#[cfg(test)]
523mod test_add_poly_over_z {
524 use super::PolynomialRingZq;
525 use crate::integer::PolyOverZ;
526 use std::str::FromStr;
527
528 #[test]
530 fn borrowed_correctness() {
531 let poly_1 =
532 PolynomialRingZq::from_str(&format!("2 2 {} / 4 1 2 3 4 mod {}", i64::MAX, u64::MAX))
533 .unwrap();
534 let poly_2 = PolynomialRingZq::from_str(&format!(
535 "2 3 {} / 4 1 2 3 4 mod {}",
536 i64::MAX as u64 + 2,
537 u64::MAX
538 ))
539 .unwrap();
540 let poly = PolyOverZ::from_str("2 1 2").unwrap();
541
542 let poly_1 = &poly_1 + &poly;
543
544 assert_eq!(poly_2, poly_1);
545 }
546
547 #[test]
549 fn availability() {
550 let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 4 mod 17").unwrap();
551 let z = PolyOverZ::from(2);
552
553 _ = poly.clone() + z.clone();
554 _ = z.clone() + poly.clone();
555 _ = &poly + &z;
556 _ = &z + &poly;
557 _ = &poly + z.clone();
558 _ = z.clone() + &poly;
559 _ = &z + poly.clone();
560 _ = poly.clone() + &z;
561 }
562}
563
564#[cfg(test)]
565mod test_add_poly_over_zq {
566 use super::PolynomialRingZq;
567 use crate::integer_mod_q::PolyOverZq;
568 use std::str::FromStr;
569
570 #[test]
572 fn borrowed_correctness() {
573 let poly_1 =
574 PolynomialRingZq::from_str(&format!("2 2 {} / 4 1 2 3 4 mod {}", i64::MAX, u64::MAX))
575 .unwrap();
576 let poly_2 = PolynomialRingZq::from_str(&format!(
577 "2 3 {} / 4 1 2 3 4 mod {}",
578 i64::MAX as u64 + 2,
579 u64::MAX
580 ))
581 .unwrap();
582 let poly = PolyOverZq::from_str(&format!("2 1 2 mod {}", u64::MAX)).unwrap();
583
584 let poly_1 = &poly_1 + &poly;
585
586 assert_eq!(poly_2, poly_1);
587 }
588
589 #[test]
591 fn availability() {
592 let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 4 mod 17").unwrap();
593 let zq = PolyOverZq::from((2, 17));
594
595 _ = poly.clone() + zq.clone();
596 _ = zq.clone() + poly.clone();
597 _ = &poly + &zq;
598 _ = &zq + &poly;
599 _ = &poly + zq.clone();
600 _ = zq.clone() + &poly;
601 _ = &zq + poly.clone();
602 _ = poly.clone() + &zq;
603 }
604
605 #[test]
607 #[should_panic]
608 fn different_moduli_panic() {
609 let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 4 mod 17").unwrap();
610 let zq = PolyOverZq::from((2, 16));
611
612 _ = &poly + &zq;
613 }
614}