qfall_math/integer/z/arithmetic/
mul.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 [`Mul`] trait for [`Z`] values.
10
11use super::super::Z;
12use crate::{
13    integer_mod_q::Zq,
14    macros::arithmetics::{
15        arithmetic_assign_between_types, arithmetic_assign_trait_borrowed_to_owned,
16        arithmetic_between_types, arithmetic_trait_borrowed_to_owned,
17        arithmetic_trait_mixed_borrowed_owned,
18    },
19    rational::Q,
20};
21use flint_sys::{
22    fmpq::fmpq_mul_fmpz,
23    fmpz::{fmpz, fmpz_mul, fmpz_mul_si, fmpz_mul_ui},
24    fmpz_mod::fmpz_mod_mul_fmpz,
25};
26use std::ops::{Mul, MulAssign};
27
28impl MulAssign<&Z> for Z {
29    /// Computes the multiplication of `self` and `other` reusing
30    /// the memory of `self`.
31    /// [`MulAssign`] can be used on [`Z`] in combination with
32    /// [`Z`], [`i64`], [`i32`], [`i16`], [`i8`], [`u64`], [`u32`], [`u16`] and [`u8`].
33    ///
34    /// Parameters:
35    /// - `other`: specifies the value to multiply to `self`
36    ///
37    /// Returns the product of both numbers as a [`Z`].
38    ///
39    /// # Examples
40    /// ```
41    /// use qfall_math::integer::Z;
42    ///
43    /// let mut a: Z = Z::from(42);
44    /// let b: Z = Z::from(24);
45    ///
46    /// a *= &b;
47    /// a *= b;
48    /// a *= 5;
49    /// ```
50    fn mul_assign(&mut self, other: &Self) {
51        unsafe { fmpz_mul(&mut self.value, &self.value, &other.value) };
52    }
53}
54impl MulAssign<i64> for Z {
55    /// Documentation at [`Z::mul_assign`].
56    fn mul_assign(&mut self, other: i64) {
57        unsafe { fmpz_mul_si(&mut self.value, &self.value, other) };
58    }
59}
60impl MulAssign<u64> for Z {
61    /// Documentation at [`Z::mul_assign`].
62    fn mul_assign(&mut self, other: u64) {
63        unsafe { fmpz_mul_ui(&mut self.value, &self.value, other) };
64    }
65}
66
67arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, Z, Z);
68arithmetic_assign_between_types!(MulAssign, mul_assign, Z, i64, i32 i16 i8);
69arithmetic_assign_between_types!(MulAssign, mul_assign, Z, u64, u32 u16 u8);
70
71impl Mul for &Z {
72    type Output = Z;
73    /// Implements the [`Mul`] trait for two [`Z`] values.
74    /// [`Mul`] is implemented for any combination of [`Z`] and borrowed [`Z`].
75    ///
76    /// Parameters:
77    /// - `other`: specifies the value to multiply with `self`
78    ///
79    /// Returns the product of both numbers as a [`Z`].
80    ///
81    /// # Examples
82    /// ```
83    /// use qfall_math::integer::Z;
84    ///
85    /// let a: Z = Z::from(42);
86    /// let b: Z = Z::from(24);
87    ///
88    /// let c: Z = &a * &b;
89    /// let d: Z = a * b;
90    /// let e: Z = &c * d;
91    /// let f: Z = c * &e;
92    /// ```
93    fn mul(self, other: Self) -> Self::Output {
94        let mut out = Z::default();
95        unsafe {
96            fmpz_mul(&mut out.value, &self.value, &other.value);
97        }
98        out
99    }
100}
101
102arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, Z, Z);
103arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, Z, Z);
104arithmetic_between_types!(Mul, mul, Z, Z, i64 i32 i16 i8 u64 u32 u16 u8);
105
106impl Mul<&Q> for &Z {
107    type Output = Q;
108
109    /// Implements the [`Mul`] trait for [`Z`] and [`Q`] values.
110    /// [`Mul`] is implemented for any combination of owned and borrowed values.
111    ///
112    /// Parameters:
113    ///  - `other`: specifies the value to multiply with `self`
114    ///
115    /// Returns the product of both numbers as a [`Q`].
116    ///
117    /// # Examples
118    /// ```
119    /// use qfall_math::rational::Q;
120    /// use qfall_math::integer::Z;
121    /// use std::str::FromStr;
122    ///
123    /// let a: Z = Z::from(-42);
124    /// let b: Q = Q::from((42, 19));
125    ///
126    /// let c: Q = &a * &b;
127    /// let d: Q = a * b;
128    /// let e: Q = &Z::from(42) * d;
129    /// let f: Q = Z::from(42) * &e;
130    /// ```
131    fn mul(self, other: &Q) -> Self::Output {
132        let mut out = Q::default();
133        unsafe {
134            fmpq_mul_fmpz(&mut out.value, &other.value, &self.value);
135        }
136        out
137    }
138}
139
140arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, Q, Q);
141arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, Q, Q);
142arithmetic_between_types!(Mul, mul, Z, Q, f32 f64);
143
144impl Mul<&Zq> for &Z {
145    type Output = Zq;
146    /// Implements the [`Mul`] trait for [`Z`] and [`Zq`] values.
147    /// [`Mul`] is implemented for any combination of owned and borrowed values.
148    ///
149    /// Parameters:
150    ///  - `other`: specifies the value to multiply with `self`
151    ///
152    /// Returns the product of both numbers as a [`Zq`].
153    ///
154    /// # Examples
155    /// ```
156    /// use qfall_math::integer_mod_q::Zq;
157    /// use qfall_math::integer::Z;
158    /// use std::str::FromStr;
159    ///
160    /// let a: Z = Z::from(42);
161    /// let b: Zq = Zq::from((42, 9));
162    ///
163    /// let c: Zq = &a * &b;
164    /// let d: Zq = a * b;
165    /// let e: Zq = &Z::from(42) * d;
166    /// let f: Zq = Z::from(42) * &e;
167    /// ```
168    fn mul(self, other: &Zq) -> Self::Output {
169        let mut out = fmpz(0);
170        unsafe {
171            fmpz_mod_mul_fmpz(
172                &mut out,
173                &other.value.value,
174                &self.value,
175                other.modulus.get_fmpz_mod_ctx_struct(),
176            );
177        }
178        Zq {
179            modulus: other.modulus.clone(),
180            value: Z { value: out },
181        }
182    }
183}
184
185arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, Zq, Zq);
186arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, Zq, Zq);
187
188#[cfg(test)]
189mod test_mul_assign {
190    use crate::integer::Z;
191
192    /// Ensure that `mul_assign` works for small numbers.
193    #[test]
194    fn correct_small() {
195        let mut a: Z = Z::MINUS_ONE;
196        let b = Z::MINUS_ONE;
197        let c = Z::ZERO;
198
199        a *= &b;
200        assert_eq!(1, a);
201        a *= &b;
202        assert_eq!(-1, a);
203        a *= &c;
204        assert_eq!(0, a);
205        a *= &c;
206    }
207
208    /// Ensure that `mul_assign` works for large numbers.
209    #[test]
210    fn correct_large() {
211        let mut a: Z = Z::from(i64::MIN);
212        let mut b = Z::from(u64::MAX);
213
214        a *= Z::MINUS_ONE;
215        assert_eq!(-1 * Z::from(i64::MIN), a);
216        b *= Z::MINUS_ONE;
217        assert_eq!(-1 * Z::from(u64::MAX), b);
218    }
219
220    /// Ensure that `mul_assign` is available for all types.
221    #[test]
222    fn availability() {
223        let mut a: Z = Z::from(42);
224        let b: Z = Z::from(1);
225
226        a *= &b;
227        a *= b;
228        a *= 1_u8;
229        a *= 1_u16;
230        a *= 1_u32;
231        a *= 1_u64;
232        a *= 1_i8;
233        a *= 1_i16;
234        a *= 1_i32;
235        a *= 1_i64;
236    }
237}
238
239#[cfg(test)]
240mod test_mul_between_types {
241    use crate::integer::Z;
242
243    /// Testing multiplication between different types
244    #[test]
245    #[allow(clippy::op_ref)]
246    fn mul() {
247        let a: Z = Z::from(42);
248        let b: u64 = 5;
249        let c: u32 = 5;
250        let d: u16 = 5;
251        let e: u8 = 5;
252        let f: i64 = 5;
253        let g: i32 = 5;
254        let h: i16 = 5;
255        let i: i8 = 5;
256
257        let _: Z = &a * &b;
258        let _: Z = &a * &c;
259        let _: Z = &a * &d;
260        let _: Z = &a * &e;
261        let _: Z = &a * &f;
262        let _: Z = &a * &g;
263        let _: Z = &a * &h;
264        let _: Z = &a * &i;
265
266        let _: Z = &b * &a;
267        let _: Z = &c * &a;
268        let _: Z = &d * &a;
269        let _: Z = &e * &a;
270        let _: Z = &f * &a;
271        let _: Z = &g * &a;
272        let _: Z = &h * &a;
273        let _: Z = &i * &a;
274
275        let _: Z = &a * b;
276        let _: Z = &a * c;
277        let _: Z = &a * d;
278        let _: Z = &a * e;
279        let _: Z = &a * f;
280        let _: Z = &a * g;
281        let _: Z = &a * h;
282        let _: Z = &a * i;
283
284        let _: Z = &b * Z::from(42);
285        let _: Z = &c * Z::from(42);
286        let _: Z = &d * Z::from(42);
287        let _: Z = &e * Z::from(42);
288        let _: Z = &f * Z::from(42);
289        let _: Z = &g * Z::from(42);
290        let _: Z = &h * Z::from(42);
291        let _: Z = &i * Z::from(42);
292
293        let _: Z = Z::from(42) * &b;
294        let _: Z = Z::from(42) * &c;
295        let _: Z = Z::from(42) * &d;
296        let _: Z = Z::from(42) * &e;
297        let _: Z = Z::from(42) * &f;
298        let _: Z = Z::from(42) * &g;
299        let _: Z = Z::from(42) * &h;
300        let _: Z = Z::from(42) * &i;
301
302        let _: Z = b * &a;
303        let _: Z = c * &a;
304        let _: Z = d * &a;
305        let _: Z = e * &a;
306        let _: Z = f * &a;
307        let _: Z = g * &a;
308        let _: Z = h * &a;
309        let _: Z = i * &a;
310
311        let _: Z = Z::from(42) * b;
312        let _: Z = Z::from(42) * c;
313        let _: Z = Z::from(42) * d;
314        let _: Z = Z::from(42) * e;
315        let _: Z = Z::from(42) * f;
316        let _: Z = Z::from(42) * g;
317        let _: Z = Z::from(42) * h;
318        let _: Z = Z::from(42) * i;
319
320        let _: Z = b * Z::from(42);
321        let _: Z = c * Z::from(42);
322        let _: Z = d * Z::from(42);
323        let _: Z = e * Z::from(42);
324        let _: Z = f * Z::from(42);
325        let _: Z = g * Z::from(42);
326        let _: Z = h * Z::from(42);
327        let _: Z = i * Z::from(42);
328    }
329}
330
331#[cfg(test)]
332mod test_mul {
333    use super::Z;
334
335    /// Testing multiplication for two [`Z`]
336    #[test]
337    fn mul() {
338        let a: Z = Z::from(42);
339        let b: Z = Z::from(4);
340        let c: Z = a * b;
341        assert_eq!(c, Z::from(168));
342    }
343
344    /// Testing multiplication for two borrowed [`Z`]
345    #[test]
346    fn mul_borrow() {
347        let a: Z = Z::from(42);
348        let b: Z = Z::from(4);
349        let c: Z = &a * &b;
350        assert_eq!(c, Z::from(168));
351    }
352
353    /// Testing multiplication for borrowed [`Z`] and [`Z`]
354    #[test]
355    fn mul_first_borrowed() {
356        let a: Z = Z::from(42);
357        let b: Z = Z::from(4);
358        let c: Z = &a * b;
359        assert_eq!(c, Z::from(168));
360    }
361
362    /// Testing multiplication for [`Z`] and borrowed [`Z`]
363    #[test]
364    fn mul_second_borrowed() {
365        let a: Z = Z::from(42);
366        let b: Z = Z::from(4);
367        let c: Z = a * &b;
368        assert_eq!(c, Z::from(168));
369    }
370
371    /// Testing multiplication for large [`Z`]
372    #[test]
373    fn mul_large_numbers() {
374        let a: Z = Z::from(i64::MAX);
375        let b: Z = Z::from(2);
376        let c: Z = Z::from(i32::MIN);
377        let d: Z = Z::from(i32::MAX);
378
379        let e: Z = a * b;
380        let f: Z = c * d;
381
382        assert_eq!(e, Z::from(u64::MAX - 1));
383        assert_eq!(f, Z::from(i64::from(i32::MAX) * i64::from(i32::MIN)));
384    }
385}
386
387#[cfg(test)]
388mod test_mul_between_z_and_zq {
389    use super::Z;
390    use crate::integer_mod_q::Zq;
391
392    /// Testing multiplication for [`Z`] and [`Zq`]
393    #[test]
394    fn mul() {
395        let a: Z = Z::from(9);
396        let b: Zq = Zq::from((4, 11));
397        let c: Zq = a * b;
398        assert_eq!(c, Zq::from((3, 11)));
399    }
400
401    /// Testing multiplication for both borrowed [`Z`] and [`Zq`]
402    #[test]
403    fn mul_borrow() {
404        let a: Z = Z::from(9);
405        let b: Zq = Zq::from((4, 11));
406        let c: Zq = &a * &b;
407        assert_eq!(c, Zq::from((3, 11)));
408    }
409
410    /// Testing multiplication for borrowed [`Z`] and [`Zq`]
411    #[test]
412    fn mul_first_borrowed() {
413        let a: Z = Z::from(9);
414        let b: Zq = Zq::from((4, 11));
415        let c: Zq = &a * b;
416        assert_eq!(c, Zq::from((3, 11)));
417    }
418
419    /// Testing multiplication for [`Z`] and borrowed [`Zq`]
420    #[test]
421    fn mul_second_borrowed() {
422        let a: Z = Z::from(9);
423        let b: Zq = Zq::from((4, 11));
424        let c: Zq = a * &b;
425        assert_eq!(c, Zq::from((3, 11)));
426    }
427
428    /// Testing multiplication for large numbers
429    #[test]
430    fn mul_large_numbers() {
431        let a: Z = Z::from(u64::MAX);
432        let b: Zq = Zq::from((i64::MAX, u64::MAX - 58));
433        let c: Zq = Zq::from((i64::MAX - 1, i64::MAX));
434
435        let d: Zq = &a * b;
436        let e: Zq = a * c;
437
438        assert_eq!(
439            d,
440            Zq::from(((u64::MAX - 1) / 2, u64::MAX - 58)) * Zq::from((u64::MAX, u64::MAX - 58))
441        );
442        assert_eq!(e, Zq::from((u64::MAX, i64::MAX)) * Zq::from((-1, i64::MAX)));
443    }
444}
445
446#[cfg(test)]
447mod test_mul_between_z_and_q {
448    use super::Z;
449    use crate::rational::Q;
450
451    /// Ensuring multiplication between different types is available
452    #[test]
453    fn availability() {
454        let a: Z = Z::from(42);
455        let b: Q = Q::from((5, 7));
456
457        let _: Q = &a * &b;
458        let _: Q = &a * b.clone();
459        let _: Q = a.clone() * &b;
460        let _: Q = a.clone() * b;
461        let _: Q = &a * 0.5_f32;
462        let _: Q = &a * 0.5_f64;
463        let _: Q = a.clone() * 0.5_f32;
464        let _: Q = a.clone() * 0.5_f64;
465        let _: Q = 0.5_f32 * &a;
466        let _: Q = 0.5_f64 * &a;
467        let _: Q = 0.5_f32 * a.clone();
468        let _: Q = 0.5_f64 * a.clone();
469    }
470
471    /// Testing multiplication for [`Z`] and [`Q`]
472    #[test]
473    fn mul() {
474        let a: Z = Z::from(4);
475        let b: Q = Q::from((5, 7));
476        let c: Q = a * b;
477        assert_eq!(c, Q::from((20, 7)));
478    }
479
480    /// Testing multiplication for both borrowed [`Z`] and [`Q`]
481    #[test]
482    fn mul_borrow() {
483        let a: Z = Z::from(4);
484        let b: Q = Q::from((5, 7));
485        let c: Q = &a * &b;
486        assert_eq!(c, Q::from((20, 7)));
487    }
488
489    /// Testing multiplication for borrowed [`Z`] and [`Q`]
490    #[test]
491    fn mul_first_borrowed() {
492        let a: Z = Z::from(4);
493        let b: Q = Q::from((5, 7));
494        let c: Q = &a * b;
495        assert_eq!(c, Q::from((20, 7)));
496    }
497
498    /// Testing multiplication for [`Z`] and borrowed [`Q`]
499    #[test]
500    fn mul_second_borrowed() {
501        let a: Z = Z::from(4);
502        let b: Q = Q::from((5, 7));
503        let c: Q = a * &b;
504        assert_eq!(c, Q::from((20, 7)));
505    }
506
507    /// Testing multiplication for large numbers
508    #[test]
509    fn mul_large_numbers() {
510        let a: Z = Z::from(u64::MAX);
511        let b: Q = Q::from((1, u64::MAX));
512        let c: Q = Q::from((u64::MAX, 2));
513
514        let d: Q = &a * b;
515        let e: Q = a * c;
516
517        assert_eq!(d, Q::from((1, u64::MAX)) * Q::from(u64::MAX));
518        assert_eq!(e, Q::from(u64::MAX) * Q::from((u64::MAX, 2)));
519    }
520}