@@ -12,7 +12,7 @@ use super::MatPolynomialRingZq;
1212use crate :: {
1313 integer:: { MatPolyOverZ , PolyOverZ } ,
1414 integer_mod_q:: { ModulusPolynomialRingZq , PolynomialRingZq } ,
15- traits:: { MatrixDimensions , MatrixGetEntry , MatrixGetSubmatrix } ,
15+ traits:: { MatrixDimensions , MatrixGetEntry , MatrixGetSubmatrix , MatrixSetEntry } ,
1616} ;
1717use flint_sys:: { fmpz_poly:: fmpz_poly_struct, fmpz_poly_mat:: fmpz_poly_mat_entry} ;
1818
@@ -37,11 +37,46 @@ impl MatPolynomialRingZq {
3737}
3838
3939impl MatPolynomialRingZq {
40+ /// Creates a [`MatPolyOverZ`] where each entry is a representative of the
41+ /// equivalence class of each entry from a [`MatPolynomialRingZq`] with coefficients centered around `0`.
42+ ///
43+ /// The representation of the coefficients is in the range `[-modulus/2, modulus/2]` and
44+ /// the representation of the polynomials is in the range `[0, modulus_polynomial)`.
45+ /// Use [`MatPolynomialRingZq::get_representative_least_nonnegative_residue`] if they should be
46+ /// in the range `[0, modulus)`.
47+ ///
48+ /// # Examples
49+ /// ```
50+ /// use qfall_math::integer_mod_q::MatPolynomialRingZq;
51+ /// use qfall_math::integer::MatPolyOverZ;
52+ /// use std::str::FromStr;
53+ ///
54+ /// let poly_ring_mat = MatPolynomialRingZq::from_str("[[1 10, 1 11]] / 4 1 0 0 1 mod 21").unwrap();
55+ ///
56+ /// let matrix = poly_ring_mat.get_representative_least_absolute_residue();
57+ ///
58+ /// let cmp_poly_mat = MatPolyOverZ::from_str("[[1 10, 1 -10]]").unwrap();
59+ /// assert_eq!(cmp_poly_mat, matrix);
60+ /// ```
61+ pub fn get_representative_least_absolute_residue ( & self ) -> MatPolyOverZ {
62+ let mut out = MatPolyOverZ :: new ( self . get_num_rows ( ) , self . get_num_columns ( ) ) ;
63+ for row in 0 ..self . get_num_rows ( ) {
64+ for col in 0 ..self . get_num_columns ( ) {
65+ let poly: PolynomialRingZq = unsafe { self . get_entry_unchecked ( row, col) } ;
66+ let lar_poly = poly. get_representative_least_absolute_residue ( ) ;
67+ unsafe { out. set_entry_unchecked ( row, col, lar_poly) } ;
68+ }
69+ }
70+ out
71+ }
72+
4073 /// Creates a [`MatPolyOverZ`] where each entry is a representative of the
4174 /// equivalence class of each entry from a [`MatPolynomialRingZq`].
4275 ///
4376 /// The representation of the coefficients is in the range `[0, modulus)` and
4477 /// the representation of the polynomials is in the range `[0, modulus_polynomial)`.
78+ /// Use [`MatPolynomialRingZq::get_representative_least_absolute_residue`] if they should be
79+ /// in the range `[-modulus/2, modulus/2]`.
4580 ///
4681 /// # Examples
4782 /// ```
@@ -440,6 +475,40 @@ mod test_mod {
440475 }
441476}
442477
478+ #[ cfg( test) ]
479+ mod test_get_representative_least_absolute_residue {
480+ use crate :: { integer:: MatPolyOverZ , integer_mod_q:: MatPolynomialRingZq } ;
481+ use std:: str:: FromStr ;
482+
483+ /// Check whether `get_representative_least_absolute_residue` outputs the correct value for large values
484+ #[ test]
485+ fn large_numbers ( ) {
486+ let poly_ring = MatPolynomialRingZq :: from_str ( & format ! (
487+ "[[2 {} {}]] / 4 1 0 0 1 mod {}" ,
488+ i64 :: MAX ,
489+ u64 :: MAX - 1 ,
490+ u64 :: MAX
491+ ) )
492+ . unwrap ( ) ;
493+
494+ let lar_mat = poly_ring. get_representative_least_absolute_residue ( ) ;
495+
496+ let cmp_mat = MatPolyOverZ :: from_str ( & format ! ( "[[2 {} -1]]" , i64 :: MAX ) ) . unwrap ( ) ;
497+ assert_eq ! ( cmp_mat, lar_mat) ;
498+ }
499+
500+ /// Check whether `get_representative_least_absolute_residue` outputs the correct value for special cases
501+ #[ test]
502+ fn special_numbers ( ) {
503+ let mat = MatPolynomialRingZq :: from_str ( "[[3 10 0 11]] / 4 1 0 0 1 mod 21" ) . unwrap ( ) ;
504+
505+ let lar_mat = mat. get_representative_least_absolute_residue ( ) ;
506+
507+ let cmp_mat = MatPolyOverZ :: from_str ( "[[3 10 0 -10]]" ) . unwrap ( ) ;
508+ assert_eq ! ( cmp_mat, lar_mat) ;
509+ }
510+ }
511+
443512#[ cfg( test) ]
444513mod test_get_representative_least_nonnegative_residue {
445514 use crate :: {
0 commit comments