1010
1111use super :: super :: MatZ ;
1212use crate :: integer:: Z ;
13+ use crate :: integer_mod_q:: { MatZq , Zq } ;
1314use crate :: macros:: arithmetics:: {
1415 arithmetic_assign_between_types, arithmetic_assign_trait_borrowed_to_owned,
1516 arithmetic_trait_borrowed_to_owned, arithmetic_trait_mixed_borrowed_owned,
@@ -60,7 +61,7 @@ arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, MatZ, MatZ);
6061arithmetic_trait_mixed_borrowed_owned ! ( Mul , mul, MatZ , Z , MatZ ) ;
6162arithmetic_trait_mixed_borrowed_owned ! ( Mul , mul, Z , MatZ , MatZ ) ;
6263
63- implement_for_others ! ( Z , MatZ , Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64 ) ;
64+ implement_for_others ! ( Z , MatZ , MatZ , Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64 ) ;
6465
6566impl Mul < & Q > for & MatZ {
6667 type Output = MatQ ;
@@ -75,7 +76,7 @@ impl Mul<&Q> for &MatZ {
7576 /// # Examples
7677 /// ```
7778 /// use qfall_math::integer::MatZ;
78- /// use qfall_math::rational::{MatQ, Q} ;
79+ /// use qfall_math::rational::Q ;
7980 /// use std::str::FromStr;
8081 ///
8182 /// let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
@@ -96,6 +97,42 @@ arithmetic_trait_borrowed_to_owned!(Mul, mul, Q, MatZ, MatQ);
9697arithmetic_trait_mixed_borrowed_owned ! ( Mul , mul, MatZ , Q , MatQ ) ;
9798arithmetic_trait_mixed_borrowed_owned ! ( Mul , mul, Q , MatZ , MatQ ) ;
9899
100+ implement_for_others ! ( Q , MatZ , MatQ , Mul Scalar for f32 f64 ) ;
101+
102+ impl Mul < & Zq > for & MatZ {
103+ type Output = MatZq ;
104+ /// Implements the [`Mul`] trait for a [`MatZ`] matrix with a [`Zq`] representative of a residue class.
105+ /// [`Mul`] is implemented for any combination of owned and borrowed values.
106+ ///
107+ /// Parameters:
108+ /// - `scalar`: specifies the scalar by which the matrix is multiplied
109+ ///
110+ /// Returns the product of `self` and `scalar` as a [`MatZq`].
111+ ///
112+ /// # Examples
113+ /// ```
114+ /// use qfall_math::integer::MatZ;
115+ /// use qfall_math::integer_mod_q::Zq;
116+ /// use std::str::FromStr;
117+ ///
118+ /// let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
119+ /// let zq = Zq::from((1,3));
120+ ///
121+ /// let mat_2 = &mat_1 * &zq;
122+ /// ```
123+ fn mul ( self , scalar : & Zq ) -> Self :: Output {
124+ let out = MatZq :: from ( ( self , scalar. get_mod ( ) ) ) ;
125+ out * scalar
126+ }
127+ }
128+
129+ arithmetic_trait_reverse ! ( Mul , mul, Zq , MatZ , MatZq ) ;
130+
131+ arithmetic_trait_borrowed_to_owned ! ( Mul , mul, MatZ , Zq , MatZq ) ;
132+ arithmetic_trait_borrowed_to_owned ! ( Mul , mul, Zq , MatZ , MatZq ) ;
133+ arithmetic_trait_mixed_borrowed_owned ! ( Mul , mul, MatZ , Zq , MatZq ) ;
134+ arithmetic_trait_mixed_borrowed_owned ! ( Mul , mul, Zq , MatZ , MatZq ) ;
135+
99136impl MulAssign < & Z > for MatZ {
100137 /// Computes the scalar multiplication of `self` and `scalar` reusing
101138 /// the memory of `self`.
@@ -243,6 +280,24 @@ mod test_mul {
243280 assert_eq ! ( mat_3, integer_1 * mat_1) ;
244281 assert_eq ! ( mat_4, integer_2 * mat_2) ;
245282 }
283+
284+ /// Checks if scalar multiplication is available for any integer type
285+ #[ test]
286+ fn availability ( ) {
287+ let mat = MatZ :: from_str ( "[[2, 1],[1, 2]]" ) . unwrap ( ) ;
288+ let integer = Z :: from ( 3 ) ;
289+
290+ let _ = & mat * 1u8 ;
291+ let _ = & mat * 1u16 ;
292+ let _ = & mat * 1u32 ;
293+ let _ = & mat * 1u64 ;
294+ let _ = & mat * 1i8 ;
295+ let _ = & mat * 1i16 ;
296+ let _ = & mat * 1i32 ;
297+ let _ = & mat * 1i64 ;
298+ let _ = & mat * & integer;
299+ let _ = & mat * integer;
300+ }
246301}
247302
248303#[ cfg( test) ]
@@ -328,6 +383,99 @@ mod test_mul_q {
328383 assert_eq ! ( mat_3, rational_1 * mat_1) ;
329384 assert_eq ! ( mat_4, rational_2 * mat_2) ;
330385 }
386+
387+ /// Checks if scalar multiplication is available for any rational type
388+ #[ test]
389+ fn availability ( ) {
390+ let mat = MatZ :: from_str ( "[[2, 1],[1, 2]]" ) . unwrap ( ) ;
391+ let rational = Q :: from ( 3 ) ;
392+
393+ let _ = & mat * 1.0f32 ;
394+ let _ = & mat * 1.0f64 ;
395+ let _ = & mat * & rational;
396+ let _ = & mat * rational;
397+ }
398+ }
399+
400+ #[ cfg( test) ]
401+ mod test_mul_zq {
402+ use super :: MatZ ;
403+ use crate :: integer_mod_q:: { MatZq , Zq } ;
404+ use std:: str:: FromStr ;
405+
406+ /// Checks if scalar multiplication works fine for both borrowed
407+ #[ test]
408+ fn borrowed_correctness ( ) {
409+ let mat_1 = MatZ :: from_str ( "[[2, 1],[1, 2]]" ) . unwrap ( ) ;
410+ let mat_2 = mat_1. clone ( ) ;
411+ let mat_3 = MatZq :: from_str ( "[[1, 2],[2, 1]] mod 3" ) . unwrap ( ) ;
412+ let zq = Zq :: from ( ( 2 , 3 ) ) ;
413+
414+ let mat_1 = & mat_1 * & zq;
415+ let mat_2 = & zq * & mat_2;
416+
417+ assert_eq ! ( mat_3, mat_1) ;
418+ assert_eq ! ( mat_3, mat_2) ;
419+ }
420+
421+ /// Checks if scalar multiplication works fine for both owned
422+ #[ test]
423+ fn owned_correctness ( ) {
424+ let mat_1 = MatZ :: from_str ( "[[2, 1],[1, 2]]" ) . unwrap ( ) ;
425+ let mat_2 = mat_1. clone ( ) ;
426+ let mat_3 = MatZq :: from_str ( "[[2, 1],[1, 2]] mod 3" ) . unwrap ( ) ;
427+ let zq = Zq :: from ( ( 1 , 3 ) ) ;
428+
429+ let mat_1 = mat_1 * zq. clone ( ) ;
430+ let mat_2 = zq * mat_2;
431+
432+ assert_eq ! ( mat_3, mat_1) ;
433+ assert_eq ! ( mat_3, mat_2) ;
434+ }
435+
436+ /// Checks if scalar multiplication works fine for half owned/borrowed
437+ #[ test]
438+ fn half_correctness ( ) {
439+ let mat_1 = MatZ :: from_str ( "[[2, 1],[1, 2]]" ) . unwrap ( ) ;
440+ let mat_2 = mat_1. clone ( ) ;
441+ let mat_3 = mat_1. clone ( ) ;
442+ let mat_4 = mat_1. clone ( ) ;
443+ let mat_5 = MatZq :: from_str ( "[[2, 1],[1, 2]] mod 3" ) . unwrap ( ) ;
444+ let zq = Zq :: from ( ( 1 , 3 ) ) ;
445+
446+ let mat_1 = mat_1 * & zq;
447+ let mat_2 = & zq * mat_2;
448+ let mat_3 = & mat_3 * zq. clone ( ) ;
449+ let mat_4 = zq * & mat_4;
450+
451+ assert_eq ! ( mat_5, mat_1) ;
452+ assert_eq ! ( mat_5, mat_2) ;
453+ assert_eq ! ( mat_5, mat_3) ;
454+ assert_eq ! ( mat_5, mat_4) ;
455+ }
456+
457+ /// Checks if scalar multiplication works fine for matrices of different dimensions
458+ #[ test]
459+ fn different_dimensions_correctness ( ) {
460+ let mat_1 = MatZ :: from_str ( "[[1],[0],[4]]" ) . unwrap ( ) ;
461+ let mat_2 = MatZ :: from_str ( "[[2, 5, 6],[1, 3, 1]]" ) . unwrap ( ) ;
462+ let mat_3 = MatZq :: from_str ( "[[1],[0],[1]] mod 3" ) . unwrap ( ) ;
463+ let mat_4 = MatZq :: from_str ( "[[2, 2, 0],[1, 0, 1]] mod 3" ) . unwrap ( ) ;
464+ let integer = Zq :: from ( ( 1 , 3 ) ) ;
465+
466+ assert_eq ! ( mat_3, & integer * mat_1) ;
467+ assert_eq ! ( mat_4, integer * mat_2) ;
468+ }
469+
470+ /// Checks if scalar multiplication is available for any rational type
471+ #[ test]
472+ fn availability ( ) {
473+ let mat = MatZ :: from_str ( "[[2, 1],[1, 2]]" ) . unwrap ( ) ;
474+ let zq = Zq :: from ( ( 1 , 3 ) ) ;
475+
476+ let _ = & mat * & zq;
477+ let _ = & mat * zq;
478+ }
331479}
332480
333481#[ cfg( test) ]
0 commit comments