Skip to main content

qfall_math/integer/z/arithmetic/
add.rs

1// Copyright 2023 Phil Milewski
2//
3// This file is part of qFALL-math.
4//
5// qFALL-math is free software: you can redistribute it and/or modify it under
6// the terms of the Mozilla Public License Version 2.0 as published by the
7// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.
8
9//! Implementation of the [`Add`] trait for [`Z`] values.
10
11use super::super::Z;
12use crate::{
13    integer::PolyOverZ,
14    integer_mod_q::Zq,
15    macros::arithmetics::{
16        arithmetic_assign_between_types, arithmetic_assign_trait_borrowed_to_owned,
17        arithmetic_between_types, arithmetic_trait_borrowed_to_owned,
18        arithmetic_trait_mixed_borrowed_owned,
19    },
20    rational::Q,
21};
22use flint3_sys::{
23    fmpq_add_fmpz, fmpz, fmpz_mod_add_fmpz, {fmpz_add, fmpz_add_si, fmpz_add_ui},
24};
25use std::ops::{Add, AddAssign};
26
27impl AddAssign<&Z> for Z {
28    /// Computes the addition of `self` and `other` reusing
29    /// the memory of `self`.
30    /// [`AddAssign`] can be used on [`Z`] in combination with
31    /// [`Z`], [`i64`], [`i32`], [`i16`], [`i8`], [`u64`], [`u32`], [`u16`] and [`u8`].
32    ///
33    /// Parameters:
34    /// - `other`: specifies the value to add to `self`
35    ///
36    /// Returns the sum of both numbers as a [`Z`].
37    ///
38    /// # Examples
39    /// ```
40    /// use qfall_math::integer::Z;
41    ///
42    /// let mut a: Z = Z::from(42);
43    /// let b: Z = Z::from(24);
44    ///
45    /// a += &b;
46    /// a += b;
47    /// a += 5;
48    /// ```
49    fn add_assign(&mut self, other: &Self) {
50        unsafe { fmpz_add(&mut self.value, &self.value, &other.value) };
51    }
52}
53impl AddAssign<i64> for Z {
54    /// Documentation at [`Z::add_assign`].
55    fn add_assign(&mut self, other: i64) {
56        unsafe { fmpz_add_si(&mut self.value, &self.value, other) };
57    }
58}
59impl AddAssign<u64> for Z {
60    /// Documentation at [`Z::add_assign`].
61    fn add_assign(&mut self, other: u64) {
62        unsafe { fmpz_add_ui(&mut self.value, &self.value, other) };
63    }
64}
65
66arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, Z, Z);
67arithmetic_assign_between_types!(AddAssign, add_assign, Z, i64, i32 i16 i8);
68arithmetic_assign_between_types!(AddAssign, add_assign, Z, u64, u32 u16 u8);
69
70impl Add for &Z {
71    type Output = Z;
72    /// Implements the [`Add`] trait for two [`Z`] values.
73    /// [`Add`] is implemented for any combination of [`Z`] and borrowed [`Z`].
74    ///
75    /// Parameters:
76    /// - `other`: specifies the value to add to `self`
77    ///
78    /// Returns the sum of both numbers as a [`Z`].
79    ///
80    /// # Examples
81    /// ```
82    /// use qfall_math::integer::Z;
83    ///
84    /// let a: Z = Z::from(42);
85    /// let b: Z = Z::from(24);
86    ///
87    /// let c: Z = &a + &b;
88    /// let d: Z = a + b;
89    /// let e: Z = &c + d;
90    /// let f: Z = c + &e;
91    /// ```
92    fn add(self, other: Self) -> Self::Output {
93        let mut out = Z::default();
94        unsafe {
95            fmpz_add(&mut out.value, &self.value, &other.value);
96        }
97        out
98    }
99}
100
101arithmetic_trait_borrowed_to_owned!(Add, add, Z, Z, Z);
102arithmetic_trait_mixed_borrowed_owned!(Add, add, Z, Z, Z);
103arithmetic_between_types!(Add, add, Z, Z, i64 i32 i16 i8 u64 u32 u16 u8);
104
105impl Add<&Q> for &Z {
106    type Output = Q;
107
108    /// Implements the [`Add`] trait for [`Z`] and [`Q`] values.
109    /// [`Add`] is implemented for any combination of owned and borrowed values.
110    ///
111    /// Parameters:
112    ///  - `other`: specifies the value to add to `self`
113    ///
114    /// Returns the sum of both numbers as a [`Q`].
115    ///
116    /// # Examples
117    /// ```
118    /// use qfall_math::rational::Q;
119    /// use qfall_math::integer::Z;
120    /// use std::str::FromStr;
121    ///
122    /// let a: Z = Z::from(-42);
123    /// let b: Q = Q::from((42, 19));
124    ///
125    /// let c: Q = &a + &b;
126    /// let d: Q = a + b;
127    /// let e: Q = &Z::from(42) + d;
128    /// let f: Q = Z::from(42) + &e;
129    /// ```
130    fn add(self, other: &Q) -> Self::Output {
131        let mut out = Q::default();
132        unsafe {
133            fmpq_add_fmpz(&mut out.value, &other.value, &self.value);
134        }
135        out
136    }
137}
138
139arithmetic_trait_borrowed_to_owned!(Add, add, Z, Q, Q);
140arithmetic_trait_mixed_borrowed_owned!(Add, add, Z, Q, Q);
141arithmetic_between_types!(Add, add, Z, Q, f32 f64);
142
143impl Add<&Zq> for &Z {
144    type Output = Zq;
145    /// Implements the [`Add`] trait for [`Z`] and [`Zq`] values.
146    /// [`Add`] is implemented for any combination of owned and borrowed values.
147    ///
148    /// Parameters:
149    ///  - `other`: specifies the value to add to `self`
150    ///
151    /// Returns the sum of both numbers as a [`Zq`].
152    ///
153    /// # Examples
154    /// ```
155    /// use qfall_math::integer_mod_q::Zq;
156    /// use qfall_math::integer::Z;
157    /// use std::str::FromStr;
158    ///
159    /// let a: Z = Z::from(42);
160    /// let b: Zq = Zq::from((42, 19));
161    ///
162    /// let c: Zq = &a + &b;
163    /// let d: Zq = a + b;
164    /// let e: Zq = &Z::from(42) + d;
165    /// let f: Zq = Z::from(42) + &e;
166    /// ```
167    fn add(self, other: &Zq) -> Self::Output {
168        let mut out: fmpz = 0;
169        unsafe {
170            fmpz_mod_add_fmpz(
171                &mut out,
172                &other.value.value,
173                &self.value,
174                other.modulus.get_fmpz_mod_ctx_struct(),
175            );
176        }
177        Zq {
178            modulus: other.modulus.clone(),
179            value: Z { value: out },
180        }
181    }
182}
183
184arithmetic_trait_borrowed_to_owned!(Add, add, Z, Zq, Zq);
185arithmetic_trait_mixed_borrowed_owned!(Add, add, Z, Zq, Zq);
186
187impl Add<&PolyOverZ> for &Z {
188    type Output = PolyOverZ;
189    /// Implements the [`Add`] trait for [`Z`] and [`PolyOverZ`] values.
190    /// [`Add`] is implemented for any combination of owned and borrowed values.
191    ///
192    /// Parameters:
193    ///  - `other`: specifies the polynomial to add to `self`
194    ///
195    /// Returns the sum of both as a [`PolyOverZ`].
196    ///
197    /// # Examples
198    /// ```
199    /// use qfall_math::integer::PolyOverZ;
200    /// use qfall_math::integer::Z;
201    /// use std::str::FromStr;
202    ///
203    /// let a: Z = Z::from(42);
204    /// let b: PolyOverZ = PolyOverZ::from_str("4  5 1 2 3").unwrap();
205    ///
206    /// let c: PolyOverZ = &a + &b;
207    /// let d: PolyOverZ = a + b;
208    /// let e: PolyOverZ = &Z::from(42) + d;
209    /// let f: PolyOverZ = Z::from(42) + &e;
210    /// ```
211    fn add(self, other: &PolyOverZ) -> Self::Output {
212        // check if the first coefficient of the polynomial is initiated and
213        // can be addressed
214        if other.is_zero() {
215            PolyOverZ::from(self)
216        } else {
217            let out = other.clone();
218            unsafe {
219                fmpz_add(out.poly.coeffs, &self.value, out.poly.coeffs);
220            }
221            out
222        }
223    }
224}
225
226arithmetic_trait_borrowed_to_owned!(Add, add, Z, PolyOverZ, PolyOverZ);
227arithmetic_trait_mixed_borrowed_owned!(Add, add, Z, PolyOverZ, PolyOverZ);
228
229#[cfg(test)]
230mod test_add_assign {
231    use crate::integer::Z;
232
233    /// Ensure that `add_assign` works for small numbers.
234    #[test]
235    fn correct_small() {
236        let mut a: Z = Z::MINUS_ONE;
237        let b = Z::MINUS_ONE;
238        let c = Z::ONE;
239
240        a += &b;
241        assert_eq!(-2, a);
242        a += &c;
243        assert_eq!(-1, a);
244        a += &c;
245        assert_eq!(0, a);
246        a += &c;
247        assert_eq!(1, a);
248        a += &c;
249        assert_eq!(2, a);
250        a += 2 * b;
251        assert_eq!(0, a);
252    }
253
254    /// Ensure that `add_assign` works for large numbers.
255    #[test]
256    fn correct_large() {
257        let mut a: Z = Z::from(i64::MAX);
258        let b = Z::from(i64::MIN);
259        let c = Z::from(u64::MAX);
260
261        a += b;
262        assert_eq!(-1, a);
263        a += c;
264        assert_eq!(u64::MAX - 1, a);
265    }
266
267    /// Ensure that `add_assign` is available for all types.
268    #[test]
269    fn availability() {
270        let mut a: Z = Z::from(42);
271        let b: Z = Z::from(1);
272
273        a += &b;
274        a += b;
275        a += 1_u8;
276        a += 1_u16;
277        a += 1_u32;
278        a += 1_u64;
279        a += 1_i8;
280        a += 1_i16;
281        a += 1_i32;
282        a += 1_i64;
283    }
284}
285
286#[cfg(test)]
287mod test_add_between_types {
288    use crate::integer::Z;
289
290    /// Testing addition between different types
291    #[test]
292    #[allow(clippy::op_ref)]
293    fn add() {
294        let a: Z = Z::from(42);
295        let b: u64 = 1;
296        let c: u32 = 1;
297        let d: u16 = 1;
298        let e: u8 = 1;
299        let f: i64 = 1;
300        let g: i32 = 1;
301        let h: i16 = 1;
302        let i: i8 = 1;
303
304        let _: Z = &a + &b;
305        let _: Z = &a + &c;
306        let _: Z = &a + &d;
307        let _: Z = &a + &e;
308        let _: Z = &a + &f;
309        let _: Z = &a + &g;
310        let _: Z = &a + &h;
311        let _: Z = &a + &i;
312
313        let _: Z = &b + &a;
314        let _: Z = &c + &a;
315        let _: Z = &d + &a;
316        let _: Z = &e + &a;
317        let _: Z = &f + &a;
318        let _: Z = &g + &a;
319        let _: Z = &h + &a;
320        let _: Z = &i + &a;
321
322        let _: Z = &a + b;
323        let _: Z = &a + c;
324        let _: Z = &a + d;
325        let _: Z = &a + e;
326        let _: Z = &a + f;
327        let _: Z = &a + g;
328        let _: Z = &a + h;
329        let _: Z = &a + i;
330
331        let _: Z = &b + Z::from(42);
332        let _: Z = &c + Z::from(42);
333        let _: Z = &d + Z::from(42);
334        let _: Z = &e + Z::from(42);
335        let _: Z = &f + Z::from(42);
336        let _: Z = &g + Z::from(42);
337        let _: Z = &h + Z::from(42);
338        let _: Z = &i + Z::from(42);
339
340        let _: Z = Z::from(42) + &b;
341        let _: Z = Z::from(42) + &c;
342        let _: Z = Z::from(42) + &d;
343        let _: Z = Z::from(42) + &e;
344        let _: Z = Z::from(42) + &f;
345        let _: Z = Z::from(42) + &g;
346        let _: Z = Z::from(42) + &h;
347        let _: Z = Z::from(42) + &i;
348
349        let _: Z = b + &a;
350        let _: Z = c + &a;
351        let _: Z = d + &a;
352        let _: Z = e + &a;
353        let _: Z = f + &a;
354        let _: Z = g + &a;
355        let _: Z = h + &a;
356        let _: Z = i + &a;
357
358        let _: Z = Z::from(42) + b;
359        let _: Z = Z::from(42) + c;
360        let _: Z = Z::from(42) + d;
361        let _: Z = Z::from(42) + e;
362        let _: Z = Z::from(42) + f;
363        let _: Z = Z::from(42) + g;
364        let _: Z = Z::from(42) + h;
365        let _: Z = Z::from(42) + i;
366
367        let _: Z = b + Z::from(42);
368        let _: Z = c + Z::from(42);
369        let _: Z = d + Z::from(42);
370        let _: Z = e + Z::from(42);
371        let _: Z = f + Z::from(42);
372        let _: Z = g + Z::from(42);
373        let _: Z = h + Z::from(42);
374        let _: Z = i + Z::from(42);
375    }
376}
377
378#[cfg(test)]
379mod test_add_between_z_and_q {
380    use super::Z;
381    use crate::rational::Q;
382
383    /// Ensuring addition between different types is available
384    #[test]
385    fn availability() {
386        let a: Z = Z::from(42);
387        let b: Q = Q::from((5, 7));
388
389        let _: Q = &a + &b;
390        let _: Q = &a + b.clone();
391        let _: Q = a.clone() + &b;
392        let _: Q = a.clone() + b;
393        let _: Q = &a + 0.5_f32;
394        let _: Q = &a + 0.5_f64;
395        let _: Q = a.clone() + 0.5_f32;
396        let _: Q = a.clone() + 0.5_f64;
397        let _: Q = 0.5_f32 + &a;
398        let _: Q = 0.5_f64 + &a;
399        let _: Q = 0.5_f32 + a.clone();
400        let _: Q = 0.5_f64 + a.clone();
401    }
402
403    /// Testing addition for [`Z`] and [`Q`]
404    #[test]
405    fn add() {
406        let a: Z = Z::from(4);
407        let b: Q = Q::from((5, 7));
408        let c: Q = a + b;
409        assert_eq!(c, Q::from((33, 7)));
410    }
411
412    /// Testing addition for both borrowed [`Z`] and [`Q`]
413    #[test]
414    fn add_borrow() {
415        let a: Z = Z::from(4);
416        let b: Q = Q::from((5, 7));
417        let c: Q = &a + &b;
418        assert_eq!(c, Q::from((33, 7)));
419    }
420
421    /// Testing addition for borrowed [`Z`] and [`Q`]
422    #[test]
423    fn add_first_borrowed() {
424        let a: Z = Z::from(4);
425        let b: Q = Q::from((5, 7));
426        let c: Q = &a + b;
427        assert_eq!(c, Q::from((33, 7)));
428    }
429
430    /// Testing addition for [`Z`] and borrowed [`Q`]
431    #[test]
432    fn add_second_borrowed() {
433        let a: Z = Z::from(4);
434        let b: Q = Q::from((5, 7));
435        let c: Q = a + &b;
436        assert_eq!(c, Q::from((33, 7)));
437    }
438
439    /// Testing addition for large numbers
440    #[test]
441    fn add_large_numbers() {
442        let a: Z = Z::from(u64::MAX);
443        let b: Q = Q::from((1, u64::MAX));
444        let c: Q = Q::from((u64::MAX, 2));
445
446        let d: Q = &a + b;
447        let e: Q = a + c;
448
449        assert_eq!(d, Q::from((1, u64::MAX)) + Q::from(u64::MAX));
450        assert_eq!(e, Q::from(u64::MAX) + Q::from((u64::MAX, 2)));
451    }
452}
453
454#[cfg(test)]
455mod test_add {
456    use super::Z;
457
458    /// Testing addition for two [`Z`]
459    #[test]
460    fn add() {
461        let a: Z = Z::from(42);
462        let b: Z = Z::from(24);
463        let c: Z = a + b;
464        assert_eq!(c, Z::from(66));
465    }
466
467    /// Testing addition for two borrowed [`Z`]
468    #[test]
469    fn add_borrow() {
470        let a: Z = Z::from(42);
471        let b: Z = Z::from(24);
472        let c: Z = &a + &b;
473        assert_eq!(c, Z::from(66));
474    }
475
476    /// Testing addition for borrowed [`Z`] and [`Z`]
477    #[test]
478    fn add_first_borrowed() {
479        let a: Z = Z::from(42);
480        let b: Z = Z::from(24);
481        let c: Z = &a + b;
482        assert_eq!(c, Z::from(66));
483    }
484
485    /// Testing addition for [`Z`] and borrowed [`Z`]
486    #[test]
487    fn add_second_borrowed() {
488        let a: Z = Z::from(42);
489        let b: Z = Z::from(24);
490        let c: Z = a + &b;
491        assert_eq!(c, Z::from(66));
492    }
493
494    /// Testing addition for large numbers
495    #[test]
496    fn add_large_numbers() {
497        let a: Z = Z::from(u64::MAX);
498        let b: Z = Z::from(-221319874);
499        let c: Z = Z::from(i64::MIN);
500
501        let d: Z = &a + b;
502        let e: Z = a + c;
503
504        assert_eq!(d, Z::from(u64::MAX - 221319874));
505        assert_eq!(e, Z::from(i64::MAX));
506    }
507}
508
509#[cfg(test)]
510mod test_add_between_z_and_zq {
511    use super::Z;
512    use crate::integer_mod_q::Zq;
513
514    /// Testing addition for [`Z`] and [`Zq`]
515    #[test]
516    fn add() {
517        let a: Z = Z::from(9);
518        let b: Zq = Zq::from((4, 11));
519        let c: Zq = a + b;
520        assert_eq!(c, Zq::from((2, 11)));
521    }
522
523    /// Testing addition for both borrowed [`Z`] and [`Zq`]
524    #[test]
525    fn add_borrow() {
526        let a: Z = Z::from(9);
527        let b: Zq = Zq::from((4, 11));
528        let c: Zq = &a + &b;
529        assert_eq!(c, Zq::from((2, 11)));
530    }
531
532    /// Testing addition for borrowed [`Z`] and [`Zq`]
533    #[test]
534    fn add_first_borrowed() {
535        let a: Z = Z::from(9);
536        let b: Zq = Zq::from((4, 11));
537        let c: Zq = &a + b;
538        assert_eq!(c, Zq::from((2, 11)));
539    }
540
541    /// Testing addition for [`Z`] and borrowed [`Zq`]
542    #[test]
543    fn add_second_borrowed() {
544        let a: Z = Z::from(9);
545        let b: Zq = Zq::from((4, 11));
546        let c: Zq = a + &b;
547        assert_eq!(c, Zq::from((2, 11)));
548    }
549
550    /// Testing addition for large numbers
551    #[test]
552    fn add_large_numbers() {
553        let a: Z = Z::from(u64::MAX);
554        let b: Zq = Zq::from((i64::MAX, u64::MAX - 58));
555        let c: Zq = Zq::from((i64::MAX - 1, i64::MAX));
556
557        let d: Zq = &a + b;
558        let e: Zq = a + c;
559
560        assert_eq!(d, Zq::from(((u64::MAX - 1) / 2 + 58, u64::MAX - 58)));
561        assert_eq!(e, Zq::from((0, i64::MAX)));
562    }
563}
564
565#[cfg(test)]
566mod test_add_between_z_and_poly_over_z {
567    use super::Z;
568    use crate::integer::PolyOverZ;
569    use std::str::FromStr;
570
571    /// Testing addition for [`Z`] and [`PolyOverZ`]
572    #[test]
573    fn add() {
574        let a: Z = Z::from(9);
575        let b: PolyOverZ = PolyOverZ::from_str("4  1 1 2 3").unwrap();
576        let c: PolyOverZ = a + b;
577        assert_eq!(c, PolyOverZ::from_str("4  10 1 2 3").unwrap());
578    }
579
580    /// Testing addition for both borrowed [`Z`] and [`PolyOverZ`]
581    #[test]
582    fn add_borrow() {
583        let a: Z = Z::from(9);
584        let b: PolyOverZ = PolyOverZ::from_str("4  1 1 2 3").unwrap();
585        let c: PolyOverZ = &a + &b;
586        assert_eq!(c, PolyOverZ::from_str("4  10 1 2 3").unwrap());
587    }
588
589    /// Testing addition for borrowed [`Z`] and [`PolyOverZ`]
590    #[test]
591    fn add_first_borrowed() {
592        let a: Z = Z::from(9);
593        let b: PolyOverZ = PolyOverZ::from_str("4  1 1 2 3").unwrap();
594        let c: PolyOverZ = &a + b;
595        assert_eq!(c, PolyOverZ::from_str("4  10 1 2 3").unwrap());
596    }
597
598    /// Testing addition for [`Z`] and borrowed [`PolyOverZ`]
599    #[test]
600    fn add_second_borrowed() {
601        let a: Z = Z::from(9);
602        let b: PolyOverZ = PolyOverZ::from_str("4  1 1 2 3").unwrap();
603        let c: PolyOverZ = a + &b;
604        assert_eq!(c, PolyOverZ::from_str("4  10 1 2 3").unwrap());
605    }
606
607    /// Testing addition for large numbers
608    #[test]
609    fn add_large_numbers() {
610        let a: Z = Z::from(i64::MAX);
611        let b: PolyOverZ =
612            PolyOverZ::from_str(&format!("3  {} {} {}", i64::MAX, u64::MAX, i32::MAX)).unwrap();
613        let c: PolyOverZ = a + b;
614        assert_eq!(
615            c,
616            PolyOverZ::from_str(&format!("3  {} {} {}", u64::MAX - 1, u64::MAX, i32::MAX)).unwrap()
617        );
618    }
619
620    /// Testing addition for an empty polynomial and a zero [`Z`]
621    #[test]
622    fn add_zero() {
623        let a: Z = Z::from(15);
624        let b: PolyOverZ = PolyOverZ::default();
625        let c: PolyOverZ = a + b;
626        assert_eq!(c, PolyOverZ::from_str("1  15").unwrap());
627
628        let d: Z = Z::ZERO;
629        let e: PolyOverZ = PolyOverZ::from_str("1  15").unwrap();
630        let f: PolyOverZ = d + e;
631        assert_eq!(f, PolyOverZ::from_str("1  15").unwrap());
632    }
633}