From d74645d633f4e2d9c5134de77eeb58f1c2bff3de Mon Sep 17 00:00:00 2001 From: jnsiemer Date: Sun, 21 Dec 2025 16:31:47 +0000 Subject: [PATCH 1/3] Ensure f64/f32 mul/div integer types are implemented --- .../mat_poly_over_z/arithmetic/mul_scalar.rs | 2 +- src/integer/mat_z/arithmetic/mul_scalar.rs | 34 ++++++++++++++++++- .../poly_over_z/arithmetic/mul_scalar.rs | 6 +++- .../arithmetic/mul_scalar.rs | 2 +- .../mat_zq/arithmetic/mul_scalar.rs | 2 +- .../poly_over_zq/arithmetic/mul_scalar.rs | 2 +- .../arithmetic/mul_scalar.rs | 2 +- src/macros/for_others.rs | 24 ++++++------- src/rational/mat_q/arithmetic/div_scalar.rs | 4 +-- src/rational/mat_q/arithmetic/mul_scalar.rs | 7 ++-- .../poly_over_q/arithmetic/div_scalar.rs | 4 +-- .../poly_over_q/arithmetic/mul_scalar.rs | 9 ++++- 12 files changed, 72 insertions(+), 26 deletions(-) diff --git a/src/integer/mat_poly_over_z/arithmetic/mul_scalar.rs b/src/integer/mat_poly_over_z/arithmetic/mul_scalar.rs index 2b652d82..bf602dd0 100644 --- a/src/integer/mat_poly_over_z/arithmetic/mul_scalar.rs +++ b/src/integer/mat_poly_over_z/arithmetic/mul_scalar.rs @@ -58,7 +58,7 @@ arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, MatPolyOverZ, MatPolyOverZ); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatPolyOverZ, Z, MatPolyOverZ); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, MatPolyOverZ, MatPolyOverZ); -implement_for_others!(Z, MatPolyOverZ, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); +implement_for_others!(Z, MatPolyOverZ, MatPolyOverZ, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); impl Mul<&PolyOverZ> for &MatPolyOverZ { type Output = MatPolyOverZ; diff --git a/src/integer/mat_z/arithmetic/mul_scalar.rs b/src/integer/mat_z/arithmetic/mul_scalar.rs index 8a9cf1ab..933933b1 100644 --- a/src/integer/mat_z/arithmetic/mul_scalar.rs +++ b/src/integer/mat_z/arithmetic/mul_scalar.rs @@ -60,7 +60,7 @@ arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, MatZ, MatZ); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatZ, Z, MatZ); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, MatZ, MatZ); -implement_for_others!(Z, MatZ, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); +implement_for_others!(Z, MatZ, MatZ, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); impl Mul<&Q> for &MatZ { type Output = MatQ; @@ -96,6 +96,8 @@ arithmetic_trait_borrowed_to_owned!(Mul, mul, Q, MatZ, MatQ); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatZ, Q, MatQ); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Q, MatZ, MatQ); +implement_for_others!(Q, MatZ, MatQ, Mul Scalar for f32 f64); + impl MulAssign<&Z> for MatZ { /// Computes the scalar multiplication of `self` and `scalar` reusing /// the memory of `self`. @@ -243,6 +245,24 @@ mod test_mul { assert_eq!(mat_3, integer_1 * mat_1); assert_eq!(mat_4, integer_2 * mat_2); } + + /// Checks if scalar multiplication is available for any integer type + #[test] + fn availability() { + let mat = MatZ::from_str("[[2, 1],[1, 2]]").unwrap(); + let integer = Z::from(3); + + let _ = &mat * 1u8; + let _ = &mat * 1u16; + let _ = &mat * 1u32; + let _ = &mat * 1u64; + let _ = &mat * 1i8; + let _ = &mat * 1i16; + let _ = &mat * 1i32; + let _ = &mat * 1i64; + let _ = &mat * &integer; + let _ = &mat * integer; + } } #[cfg(test)] @@ -328,6 +348,18 @@ mod test_mul_q { assert_eq!(mat_3, rational_1 * mat_1); assert_eq!(mat_4, rational_2 * mat_2); } + + /// Checks if scalar multiplication is available for any rational type + #[test] + fn availability() { + let mat = MatZ::from_str("[[2, 1],[1, 2]]").unwrap(); + let rational = Q::from(3); + + let _ = &mat * 1.0f32; + let _ = &mat * 1.0f64; + let _ = &mat * &rational; + let _ = &mat * rational; + } } #[cfg(test)] diff --git a/src/integer/poly_over_z/arithmetic/mul_scalar.rs b/src/integer/poly_over_z/arithmetic/mul_scalar.rs index 43ccf942..dfb47fc0 100644 --- a/src/integer/poly_over_z/arithmetic/mul_scalar.rs +++ b/src/integer/poly_over_z/arithmetic/mul_scalar.rs @@ -63,7 +63,7 @@ arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, PolyOverZ, PolyOverZ); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZ, Z, PolyOverZ); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, PolyOverZ, PolyOverZ); -implement_for_others!(Z, PolyOverZ, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); +implement_for_others!(Z, PolyOverZ, PolyOverZ, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); impl Mul<&Zq> for &PolyOverZ { type Output = PolyOverZq; @@ -146,6 +146,8 @@ arithmetic_trait_borrowed_to_owned!(Mul, mul, Q, PolyOverZ, PolyOverQ); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZ, Q, PolyOverQ); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Q, PolyOverZ, PolyOverQ); +implement_for_others!(Q, PolyOverZ, PolyOverQ, Mul Scalar for f32 f64); + impl MulAssign<&Z> for PolyOverZ { /// Computes the scalar multiplication of `self` and `scalar` reusing /// the memory of `self`. @@ -375,5 +377,7 @@ mod test_mul_q { _ = q.clone() * &poly; _ = &q * poly.clone(); _ = poly.clone() * &q; + _ = &poly * 1.0f32; + _ = &poly * 1.0f64; } } diff --git a/src/integer_mod_q/mat_polynomial_ring_zq/arithmetic/mul_scalar.rs b/src/integer_mod_q/mat_polynomial_ring_zq/arithmetic/mul_scalar.rs index 3d07a962..4592dd00 100644 --- a/src/integer_mod_q/mat_polynomial_ring_zq/arithmetic/mul_scalar.rs +++ b/src/integer_mod_q/mat_polynomial_ring_zq/arithmetic/mul_scalar.rs @@ -66,7 +66,7 @@ arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, MatPolynomialRingZq, MatPolynom arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatPolynomialRingZq, Z, MatPolynomialRingZq); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, MatPolynomialRingZq, MatPolynomialRingZq); -implement_for_others!(Z, MatPolynomialRingZq, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); +implement_for_others!(Z, MatPolynomialRingZq, MatPolynomialRingZq, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); impl Mul<&Zq> for &MatPolynomialRingZq { type Output = MatPolynomialRingZq; diff --git a/src/integer_mod_q/mat_zq/arithmetic/mul_scalar.rs b/src/integer_mod_q/mat_zq/arithmetic/mul_scalar.rs index 0d6c6605..74974e68 100644 --- a/src/integer_mod_q/mat_zq/arithmetic/mul_scalar.rs +++ b/src/integer_mod_q/mat_zq/arithmetic/mul_scalar.rs @@ -61,7 +61,7 @@ arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, MatZq, MatZq); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatZq, Z, MatZq); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, MatZq, MatZq); -implement_for_others!(Z, MatZq, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); +implement_for_others!(Z, MatZq, MatZq, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); impl Mul<&Zq> for &MatZq { type Output = MatZq; diff --git a/src/integer_mod_q/poly_over_zq/arithmetic/mul_scalar.rs b/src/integer_mod_q/poly_over_zq/arithmetic/mul_scalar.rs index 436cad09..839ac333 100644 --- a/src/integer_mod_q/poly_over_zq/arithmetic/mul_scalar.rs +++ b/src/integer_mod_q/poly_over_zq/arithmetic/mul_scalar.rs @@ -65,7 +65,7 @@ arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, PolyOverZq, PolyOverZq); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZq, Z, PolyOverZq); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, PolyOverZq, PolyOverZq); -implement_for_others!(Z, PolyOverZq, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); +implement_for_others!(Z, PolyOverZq, PolyOverZq, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); impl Mul<&Zq> for &PolyOverZq { type Output = PolyOverZq; diff --git a/src/integer_mod_q/polynomial_ring_zq/arithmetic/mul_scalar.rs b/src/integer_mod_q/polynomial_ring_zq/arithmetic/mul_scalar.rs index f08be047..edcb770d 100644 --- a/src/integer_mod_q/polynomial_ring_zq/arithmetic/mul_scalar.rs +++ b/src/integer_mod_q/polynomial_ring_zq/arithmetic/mul_scalar.rs @@ -59,7 +59,7 @@ arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, PolynomialRingZq, PolynomialRin arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolynomialRingZq, Z, PolynomialRingZq); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, PolynomialRingZq, PolynomialRingZq); -implement_for_others!(Z, PolynomialRingZq, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); +implement_for_others!(Z, PolynomialRingZq, PolynomialRingZq, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); impl Mul<&Zq> for &PolynomialRingZq { type Output = PolynomialRingZq; diff --git a/src/macros/for_others.rs b/src/macros/for_others.rs index daea85ba..dc344231 100644 --- a/src/macros/for_others.rs +++ b/src/macros/for_others.rs @@ -20,9 +20,9 @@ /// Implements a specified trait using implicit conversions to a bridge type. /// /// - ['Mul'](std::ops::Mul) with signature -/// `($bridge_type, $type, Mul Scalar for $source_type)` -/// - ['Div'](std::ops::Mul) with signature -/// `($bridge_type, $type, Div Scalar for $source_type)` +/// `($bridge_type, $type, $output_type, Mul Scalar for $source_type)` +/// - ['Div'](std::ops::Div) with signature +/// `($bridge_type, $type, $output_type, Div Scalar for $source_type)` /// - ['Rem'](std::ops::Rem) with signature /// `($bridge_type, $type, Rem for $source_type)` /// - ['PartialEq'](std::cmp::PartialEq) with signature @@ -32,16 +32,16 @@ /// /// # Examples /// ```compile_fail -/// implement_for_others!(Z, MatZ, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); +/// implement_for_others!(Z, MatZ, MatZ, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); /// implement_for_others!(Z, Q, PartialEq for fmpz i8 i16 i32 i64 u8 u16 u32 u64); /// implement_for_others!(Z, Q, PartialOrd for fmpz i8 i16 i32 i64 u8 u16 u32 u64); /// implement_for_others!(Z, PolyOverZ, Rem for i8 i16 i32 i64 u8 u16 u32 u64); /// ``` macro_rules! implement_for_others { // [`Mul`] trait scalar - ($bridge_type:ident, $type:ident, Mul Scalar for $($source_type:ident)*) => { + ($bridge_type:ident, $type:ident, $output_type:ident, Mul Scalar for $($source_type:ident)*) => { $(#[doc(hidden)] impl Mul<$source_type> for &$type { - type Output = $type; + type Output = $output_type; paste::paste! { #[doc = "Documentation can be found at [`" $type "::mul`]."] fn mul(self, scalar: $source_type) -> Self::Output { @@ -52,7 +52,7 @@ macro_rules! implement_for_others { #[doc(hidden)] impl Mul<$source_type> for $type { - type Output = $type; + type Output = $output_type; paste::paste! { #[doc = "Documentation can be found at [`" $type "::mul`]."] fn mul(self, scalar: $source_type) -> Self::Output { @@ -63,7 +63,7 @@ macro_rules! implement_for_others { #[doc(hidden)] impl Mul<&$type> for $source_type { - type Output = $type; + type Output = $output_type; paste::paste! { #[doc = "Documentation can be found at [`" $type "::mul`]."] fn mul(self, matrix: &$type) -> Self::Output { @@ -74,7 +74,7 @@ macro_rules! implement_for_others { #[doc(hidden)] impl Mul<$type> for $source_type { - type Output = $type; + type Output = $output_type; paste::paste! { #[doc = "Documentation can be found at [`" $type "::mul`]."] fn mul(self, matrix: $type) -> Self::Output { @@ -85,9 +85,9 @@ macro_rules! implement_for_others { }; // [`Div`] trait scalar - ($bridge_type:ident, $type:ident, Div Scalar for $($source_type:ident)*) => { + ($bridge_type:ident, $type:ident, $output_type:ident, Div Scalar for $($source_type:ident)*) => { $(#[doc(hidden)] impl Div<$source_type> for &$type { - type Output = $type; + type Output = $output_type; paste::paste! { #[doc = "Documentation can be found at [`" $type "::div`]."] fn div(self, scalar: $source_type) -> Self::Output { @@ -98,7 +98,7 @@ macro_rules! implement_for_others { #[doc(hidden)] impl Div<$source_type> for $type { - type Output = $type; + type Output = $output_type; paste::paste! { #[doc = "Documentation can be found at [`" $type "::div`]."] fn div(self, scalar: $source_type) -> Self::Output { diff --git a/src/rational/mat_q/arithmetic/div_scalar.rs b/src/rational/mat_q/arithmetic/div_scalar.rs index 744e2d0c..67ed7f6d 100644 --- a/src/rational/mat_q/arithmetic/div_scalar.rs +++ b/src/rational/mat_q/arithmetic/div_scalar.rs @@ -58,7 +58,7 @@ impl Div<&Z> for &MatQ { arithmetic_trait_borrowed_to_owned!(Div, div, MatQ, Z, MatQ); arithmetic_trait_mixed_borrowed_owned!(Div, div, MatQ, Z, MatQ); -implement_for_others!(Z, MatQ, Div Scalar for i8 i16 i32 i64 u8 u16 u32 u64); +implement_for_others!(Z, MatQ, MatQ, Div Scalar for i8 i16 i32 i64 u8 u16 u32 u64); impl Div<&Q> for &MatQ { type Output = MatQ; @@ -95,7 +95,7 @@ impl Div<&Q> for &MatQ { arithmetic_trait_borrowed_to_owned!(Div, div, MatQ, Q, MatQ); arithmetic_trait_mixed_borrowed_owned!(Div, div, MatQ, Q, MatQ); -implement_for_others!(Q, MatQ, Div Scalar for f32 f64); +implement_for_others!(Q, MatQ, MatQ, Div Scalar for f32 f64); impl DivAssign<&Q> for MatQ { /// Computes the scalar multiplication of `self` and `other` reusing diff --git a/src/rational/mat_q/arithmetic/mul_scalar.rs b/src/rational/mat_q/arithmetic/mul_scalar.rs index 3cf7cba0..8c6a3e01 100644 --- a/src/rational/mat_q/arithmetic/mul_scalar.rs +++ b/src/rational/mat_q/arithmetic/mul_scalar.rs @@ -58,7 +58,7 @@ arithmetic_trait_borrowed_to_owned!(Mul, mul, Q, MatQ, MatQ); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatQ, Q, MatQ); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Q, MatQ, MatQ); -implement_for_others!(Z, MatQ, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); +implement_for_others!(Z, MatQ, MatQ, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); impl Mul<&Q> for &MatQ { type Output = MatQ; @@ -97,7 +97,7 @@ arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, MatQ, MatQ); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatQ, Z, MatQ); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, MatQ, MatQ); -implement_for_others!(Q, MatQ, Mul Scalar for f32 f64); +implement_for_others!(Q, MatQ, MatQ, Mul Scalar for f32 f64); impl MulAssign<&Q> for MatQ { /// Computes the scalar multiplication of `self` and `other` reusing @@ -140,6 +140,7 @@ impl MulAssign<&Z> for MatQ { arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, MatQ, Q); arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, MatQ, Z); arithmetic_assign_between_types!(MulAssign, mul_assign, MatQ, Z, u64 u32 u16 u8 i64 i32 i16 i8); +arithmetic_assign_between_types!(MulAssign, mul_assign, MatQ, Q, f32 f64); #[cfg(test)] mod test_mul_z { @@ -404,5 +405,7 @@ mod test_mul_assign { a *= 1_i16; a *= 1_i32; a *= 1_i64; + a *= 1.0_f32; + a *= 1.0_f64; } } diff --git a/src/rational/poly_over_q/arithmetic/div_scalar.rs b/src/rational/poly_over_q/arithmetic/div_scalar.rs index 83d24f0c..6b430112 100644 --- a/src/rational/poly_over_q/arithmetic/div_scalar.rs +++ b/src/rational/poly_over_q/arithmetic/div_scalar.rs @@ -63,7 +63,7 @@ impl Div<&Z> for &PolyOverQ { arithmetic_trait_borrowed_to_owned!(Div, div, PolyOverQ, Z, PolyOverQ); arithmetic_trait_mixed_borrowed_owned!(Div, div, PolyOverQ, Z, PolyOverQ); -implement_for_others!(Z, PolyOverQ, Div Scalar for i8 i16 i32 i64 u8 u16 u32 u64); +implement_for_others!(Z, PolyOverQ, PolyOverQ, Div Scalar for i8 i16 i32 i64 u8 u16 u32 u64); impl Div<&Q> for &PolyOverQ { type Output = PolyOverQ; @@ -105,7 +105,7 @@ impl Div<&Q> for &PolyOverQ { arithmetic_trait_borrowed_to_owned!(Div, div, PolyOverQ, Q, PolyOverQ); arithmetic_trait_mixed_borrowed_owned!(Div, div, PolyOverQ, Q, PolyOverQ); -implement_for_others!(Q, PolyOverQ, Div Scalar for f32 f64); +implement_for_others!(Q, PolyOverQ, PolyOverQ, Div Scalar for f32 f64); impl DivAssign<&Q> for PolyOverQ { /// Divides the polynomial coefficient-wise. diff --git a/src/rational/poly_over_q/arithmetic/mul_scalar.rs b/src/rational/poly_over_q/arithmetic/mul_scalar.rs index 33231ba2..97a58b42 100644 --- a/src/rational/poly_over_q/arithmetic/mul_scalar.rs +++ b/src/rational/poly_over_q/arithmetic/mul_scalar.rs @@ -61,7 +61,7 @@ arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, PolyOverQ, PolyOverQ); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverQ, Z, PolyOverQ); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, PolyOverQ, PolyOverQ); -implement_for_others!(Z, PolyOverQ, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); +implement_for_others!(Z, PolyOverQ, PolyOverQ, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64); impl Mul<&Q> for &PolyOverQ { type Output = PolyOverQ; @@ -100,6 +100,8 @@ arithmetic_trait_borrowed_to_owned!(Mul, mul, Q, PolyOverQ, PolyOverQ); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverQ, Q, PolyOverQ); arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Q, PolyOverQ, PolyOverQ); +implement_for_others!(Q, PolyOverQ, PolyOverQ, Mul Scalar for f32 f64); + impl MulAssign<&Q> for PolyOverQ { /// Computes the scalar multiplication of `self` and `other` reusing /// the memory of `self`. @@ -156,6 +158,7 @@ arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, PolyOverQ, Q); arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, PolyOverQ, Z); arithmetic_assign_between_types!(MulAssign, mul_assign, PolyOverQ, i64, i32 i16 i8); arithmetic_assign_between_types!(MulAssign, mul_assign, PolyOverQ, u64, u32 u16 u8); +arithmetic_assign_between_types!(MulAssign, mul_assign, PolyOverQ, Q, f64 f32); #[cfg(test)] mod test_mul_z { @@ -243,6 +246,8 @@ mod test_mul_q { _ = q.clone() * &poly; _ = &q * poly.clone(); _ = poly.clone() * &q; + _ = &poly * 1.0_f32; + _ = &poly * 1.0_f64; } } @@ -301,5 +306,7 @@ mod test_mul_assign { a *= 1_i16; a *= 1_i32; a *= 1_i64; + a *= 1.0_f32; + a *= 1.0_f64; } } From c2e5342c4c83fdbdfa74cbd8ae18c5d0008e7534 Mon Sep 17 00:00:00 2001 From: jnsiemer Date: Sun, 21 Dec 2025 16:48:36 +0000 Subject: [PATCH 2/3] Implement MatZ * Zq = MatZq --- src/integer/mat_z/arithmetic/mul_scalar.rs | 118 ++++++++++++++++++++- 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/src/integer/mat_z/arithmetic/mul_scalar.rs b/src/integer/mat_z/arithmetic/mul_scalar.rs index 933933b1..25cf0d45 100644 --- a/src/integer/mat_z/arithmetic/mul_scalar.rs +++ b/src/integer/mat_z/arithmetic/mul_scalar.rs @@ -10,6 +10,7 @@ use super::super::MatZ; use crate::integer::Z; +use crate::integer_mod_q::{MatZq, Zq}; use crate::macros::arithmetics::{ arithmetic_assign_between_types, arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned, arithmetic_trait_mixed_borrowed_owned, @@ -75,7 +76,7 @@ impl Mul<&Q> for &MatZ { /// # Examples /// ``` /// use qfall_math::integer::MatZ; - /// use qfall_math::rational::{MatQ, Q}; + /// use qfall_math::rational::Q; /// use std::str::FromStr; /// /// let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap(); @@ -98,6 +99,40 @@ arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Q, MatZ, MatQ); implement_for_others!(Q, MatZ, MatQ, Mul Scalar for f32 f64); +impl Mul<&Zq> for &MatZ { + type Output = MatZq; + /// Implements the [`Mul`] trait for a [`MatZ`] matrix with a [`Zq`] representative of a residue class. + /// [`Mul`] is implemented for any combination of owned and borrowed values. + /// + /// Parameters: + /// - `scalar`: specifies the scalar by which the matrix is multiplied + /// + /// Returns the product of `self` and `scalar` as a [`MatZq`]. + /// + /// # Examples + /// ``` + /// use qfall_math::integer::MatZ; + /// use qfall_math::integer_mod_q::Zq; + /// use std::str::FromStr; + /// + /// let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap(); + /// let zq = Zq::from((1,3)); + /// + /// let mat_2 = &mat_1 * &zq; + /// ``` + fn mul(self, scalar: &Zq) -> Self::Output { + let out = MatZq::from((self, scalar.get_mod())); + out * scalar + } +} + +arithmetic_trait_reverse!(Mul, mul, Zq, MatZ, MatZq); + +arithmetic_trait_borrowed_to_owned!(Mul, mul, MatZ, Zq, MatZq); +arithmetic_trait_borrowed_to_owned!(Mul, mul, Zq, MatZ, MatZq); +arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatZ, Zq, MatZq); +arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Zq, MatZ, MatZq); + impl MulAssign<&Z> for MatZ { /// Computes the scalar multiplication of `self` and `scalar` reusing /// the memory of `self`. @@ -362,6 +397,87 @@ mod test_mul_q { } } +#[cfg(test)] +mod test_mul_zq { + use super::MatZ; + use crate::integer_mod_q::{MatZq, Zq}; + use std::str::FromStr; + + /// Checks if scalar multiplication works fine for both borrowed + #[test] + fn borrowed_correctness() { + let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap(); + let mat_2 = mat_1.clone(); + let mat_3 = MatZq::from_str("[[2, 1],[1, 2]] mod 3").unwrap(); + let zq = Zq::from((1, 3)); + + let mat_1 = &mat_1 * &zq; + let mat_2 = &zq * &mat_2; + + assert_eq!(mat_3, mat_1); + assert_eq!(mat_3, mat_2); + } + + /// Checks if scalar multiplication works fine for both owned + #[test] + fn owned_correctness() { + let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap(); + let mat_2 = mat_1.clone(); + let mat_3 = MatZq::from_str("[[2, 1],[1, 2]] mod 3").unwrap(); + let zq = Zq::from((1, 3)); + + let mat_1 = mat_1 * zq.clone(); + let mat_2 = zq * mat_2; + + assert_eq!(mat_3, mat_1); + assert_eq!(mat_3, mat_2); + } + + /// Checks if scalar multiplication works fine for half owned/borrowed + #[test] + fn half_correctness() { + let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap(); + let mat_2 = mat_1.clone(); + let mat_3 = mat_1.clone(); + let mat_4 = mat_1.clone(); + let mat_5 = MatZq::from_str("[[2, 1],[1, 2]] mod 3").unwrap(); + let zq = Zq::from((1, 3)); + + let mat_1 = mat_1 * &zq; + let mat_2 = &zq * mat_2; + let mat_3 = &mat_3 * zq.clone(); + let mat_4 = zq * &mat_4; + + assert_eq!(mat_5, mat_1); + assert_eq!(mat_5, mat_2); + assert_eq!(mat_5, mat_3); + assert_eq!(mat_5, mat_4); + } + + /// Checks if scalar multiplication works fine for matrices of different dimensions + #[test] + fn different_dimensions_correctness() { + let mat_1 = MatZ::from_str("[[1],[0],[4]]").unwrap(); + let mat_2 = MatZ::from_str("[[2, 5, 6],[1, 3, 1]]").unwrap(); + let mat_3 = MatZq::from_str("[[1],[0],[1]] mod 3").unwrap(); + let mat_4 = MatZq::from_str("[[2, 2, 0],[1, 0, 1]] mod 3").unwrap(); + let integer = Zq::from((1, 3)); + + assert_eq!(mat_3, &integer * mat_1); + assert_eq!(mat_4, integer * mat_2); + } + + /// Checks if scalar multiplication is available for any rational type + #[test] + fn availability() { + let mat = MatZ::from_str("[[2, 1],[1, 2]]").unwrap(); + let zq = Zq::from((1, 3)); + + let _ = &mat * &zq; + let _ = &mat * zq; + } +} + #[cfg(test)] mod test_mul_assign { use crate::integer::{MatZ, Z}; From c2de991279188618d20cfdf12608e47949a204bb Mon Sep 17 00:00:00 2001 From: jnsiemer Date: Tue, 23 Dec 2025 11:27:53 +0000 Subject: [PATCH 3/3] Address comments from code review --- src/integer/mat_z/arithmetic/mul_scalar.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/integer/mat_z/arithmetic/mul_scalar.rs b/src/integer/mat_z/arithmetic/mul_scalar.rs index 25cf0d45..f246a9b9 100644 --- a/src/integer/mat_z/arithmetic/mul_scalar.rs +++ b/src/integer/mat_z/arithmetic/mul_scalar.rs @@ -408,8 +408,8 @@ mod test_mul_zq { fn borrowed_correctness() { let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap(); let mat_2 = mat_1.clone(); - let mat_3 = MatZq::from_str("[[2, 1],[1, 2]] mod 3").unwrap(); - let zq = Zq::from((1, 3)); + let mat_3 = MatZq::from_str("[[1, 2],[2, 1]] mod 3").unwrap(); + let zq = Zq::from((2, 3)); let mat_1 = &mat_1 * &zq; let mat_2 = &zq * &mat_2;