Skip to main content

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