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