diff --git a/src/integer_mod_q/mat_polynomial_ring_zq/get.rs b/src/integer_mod_q/mat_polynomial_ring_zq/get.rs index 4240fa79..4d3bbe59 100644 --- a/src/integer_mod_q/mat_polynomial_ring_zq/get.rs +++ b/src/integer_mod_q/mat_polynomial_ring_zq/get.rs @@ -12,7 +12,7 @@ use super::MatPolynomialRingZq; use crate::{ integer::{MatPolyOverZ, PolyOverZ}, integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq}, - traits::{MatrixDimensions, MatrixGetEntry, MatrixGetSubmatrix}, + traits::{MatrixDimensions, MatrixGetEntry, MatrixGetSubmatrix, MatrixSetEntry}, }; use flint_sys::{fmpz_poly::fmpz_poly_struct, fmpz_poly_mat::fmpz_poly_mat_entry}; @@ -37,11 +37,46 @@ impl MatPolynomialRingZq { } impl MatPolynomialRingZq { + /// Creates a [`MatPolyOverZ`] where each entry is a representative of the + /// equivalence class of each entry from a [`MatPolynomialRingZq`] with coefficients centered around `0`. + /// + /// The representation of the coefficients is in the range `[-modulus/2, modulus/2]` and + /// the representation of the polynomials is in the range `[0, modulus_polynomial)`. + /// Use [`MatPolynomialRingZq::get_representative_least_nonnegative_residue`] if they should be + /// in the range `[0, modulus)`. + /// + /// # Examples + /// ``` + /// use qfall_math::integer_mod_q::MatPolynomialRingZq; + /// use qfall_math::integer::MatPolyOverZ; + /// use std::str::FromStr; + /// + /// let poly_ring_mat = MatPolynomialRingZq::from_str("[[1 10, 1 11]] / 4 1 0 0 1 mod 21").unwrap(); + /// + /// let matrix = poly_ring_mat.get_representative_least_absolute_residue(); + /// + /// let cmp_poly_mat = MatPolyOverZ::from_str("[[1 10, 1 -10]]").unwrap(); + /// assert_eq!(cmp_poly_mat, matrix); + /// ``` + pub fn get_representative_least_absolute_residue(&self) -> MatPolyOverZ { + let mut out = MatPolyOverZ::new(self.get_num_rows(), self.get_num_columns()); + for row in 0..self.get_num_rows() { + for col in 0..self.get_num_columns() { + let poly: PolynomialRingZq = unsafe { self.get_entry_unchecked(row, col) }; + let lar_poly = poly.get_representative_least_absolute_residue(); + unsafe { out.set_entry_unchecked(row, col, lar_poly) }; + } + } + out + } + /// Creates a [`MatPolyOverZ`] where each entry is a representative of the /// equivalence class of each entry from a [`MatPolynomialRingZq`]. /// /// The representation of the coefficients is in the range `[0, modulus)` and /// the representation of the polynomials is in the range `[0, modulus_polynomial)`. + /// Use [`MatPolynomialRingZq::get_representative_least_absolute_residue`] if they should be + /// in the range `[-modulus/2, modulus/2]`. /// /// # Examples /// ``` @@ -440,6 +475,40 @@ mod test_mod { } } +#[cfg(test)] +mod test_get_representative_least_absolute_residue { + use crate::{integer::MatPolyOverZ, integer_mod_q::MatPolynomialRingZq}; + use std::str::FromStr; + + /// Check whether `get_representative_least_absolute_residue` outputs the correct value for large values + #[test] + fn large_numbers() { + let poly_ring = MatPolynomialRingZq::from_str(&format!( + "[[2 {} {}]] / 4 1 0 0 1 mod {}", + i64::MAX, + u64::MAX - 1, + u64::MAX + )) + .unwrap(); + + let lar_mat = poly_ring.get_representative_least_absolute_residue(); + + let cmp_mat = MatPolyOverZ::from_str(&format!("[[2 {} -1]]", i64::MAX)).unwrap(); + assert_eq!(cmp_mat, lar_mat); + } + + /// Check whether `get_representative_least_absolute_residue` outputs the correct value for special cases + #[test] + fn special_numbers() { + let mat = MatPolynomialRingZq::from_str("[[3 10 0 11]] / 4 1 0 0 1 mod 21").unwrap(); + + let lar_mat = mat.get_representative_least_absolute_residue(); + + let cmp_mat = MatPolyOverZ::from_str("[[3 10 0 -10]]").unwrap(); + assert_eq!(cmp_mat, lar_mat); + } +} + #[cfg(test)] mod test_get_representative_least_nonnegative_residue { use crate::{ diff --git a/src/integer_mod_q/poly_over_zq/get.rs b/src/integer_mod_q/poly_over_zq/get.rs index accc5bd1..fa5a22c3 100644 --- a/src/integer_mod_q/poly_over_zq/get.rs +++ b/src/integer_mod_q/poly_over_zq/get.rs @@ -12,7 +12,7 @@ use super::PolyOverZq; use crate::{ integer::{PolyOverZ, Z}, integer_mod_q::{Modulus, Zq}, - traits::GetCoefficient, + traits::{GetCoefficient, SetCoefficient}, }; use flint_sys::fmpz_mod_poly::{ fmpz_mod_poly_degree, fmpz_mod_poly_get_coeff_fmpz, fmpz_mod_poly_get_fmpz_poly, @@ -133,9 +133,40 @@ impl PolyOverZq { self.modulus.clone() } + /// Returns a representative polynomial of the [`PolyOverZq`] element with coefficients centered around `0`. + /// + /// The output [`PolyOverZ`] has coefficients in the range of `[-modulus/2, modulus/2]`. + /// For even moduli, the positive representative is chosen for the element `modulus / 2`. + /// Use [`PolyOverZq::get_representative_least_nonnegative_residue`] if they should be + /// in the range `[0, modulus)`. + /// + /// # Examples + /// ``` + /// use qfall_math::integer_mod_q::PolyOverZq; + /// use qfall_math::integer::PolyOverZ; + /// use std::str::FromStr; + /// + /// let value = PolyOverZq::from_str("2 10 11 mod 21").unwrap(); + /// + /// let least_abs_residue = value.get_representative_least_absolute_residue(); + /// + /// assert_eq!(PolyOverZ::from_str("2 10 -10").unwrap(), least_abs_residue); + /// ``` + pub fn get_representative_least_absolute_residue(&self) -> PolyOverZ { + let mut out = PolyOverZ::default(); + for i in 0..=self.get_degree() { + let coeff: Zq = unsafe { self.get_coeff_unchecked(i) }; + let lar_coeff = coeff.get_representative_least_absolute_residue(); + unsafe { out.set_coeff_unchecked(i, lar_coeff) }; + } + out + } + /// Returns a representative polynomial of the [`PolyOverZq`] element. /// /// The representation of the coefficients is in the range `[0, modulus)`. + /// Use [`PolyOverZq::get_representative_least_absolute_residue`] if they should be + /// in the range `[-modulus/2, modulus/2]`. /// /// # Examples /// ``` @@ -339,6 +370,40 @@ mod test_mod { } } +#[cfg(test)] +mod test_get_representative_least_absolute_residue { + use crate::{integer::PolyOverZ, integer_mod_q::PolyOverZq}; + use std::str::FromStr; + + /// Check whether `get_representative_least_absolute_residue` outputs the correct value for large values + #[test] + fn large_numbers() { + let poly_zq = PolyOverZq::from_str(&format!( + "2 {} {} mod {}", + i64::MAX, + u64::MAX - 1, + u64::MAX + )) + .unwrap(); + + let poly_z = poly_zq.get_representative_least_absolute_residue(); + + let cmp_poly = PolyOverZ::from_str(&format!("2 {} -1", i64::MAX)).unwrap(); + assert_eq!(cmp_poly, poly_z); + } + + /// Check whether `get_representative_least_absolute_residue` outputs the correct value for special cases + #[test] + fn special_numbers() { + let poly_zq = PolyOverZq::from_str("3 10 0 11 mod 21").unwrap(); + + let poly_z = poly_zq.get_representative_least_absolute_residue(); + + let cmp_poly = PolyOverZ::from_str("3 10 0 -10").unwrap(); + assert_eq!(cmp_poly, poly_z); + } +} + #[cfg(test)] mod test_get_representative_least_nonnegative_residue { use crate::{integer::PolyOverZ, integer_mod_q::PolyOverZq}; diff --git a/src/integer_mod_q/polynomial_ring_zq/get.rs b/src/integer_mod_q/polynomial_ring_zq/get.rs index d083f827..5ba2c786 100644 --- a/src/integer_mod_q/polynomial_ring_zq/get.rs +++ b/src/integer_mod_q/polynomial_ring_zq/get.rs @@ -12,7 +12,7 @@ use super::PolynomialRingZq; use crate::{ integer::{PolyOverZ, Z}, integer_mod_q::{ModulusPolynomialRingZq, Zq}, - traits::GetCoefficient, + traits::{GetCoefficient, SetCoefficient}, }; use flint_sys::fmpz_poly::{fmpz_poly_degree, fmpz_poly_get_coeff_fmpz}; @@ -116,10 +116,41 @@ impl PolynomialRingZq { self.modulus.clone() } + /// Returns a representative polynomial of the [`PolynomialRingZq`] element with coefficients centered around `0`. + /// + /// The output [`PolyOverZ`] has coefficients in the range of `[-modulus/2, modulus/2]`. + /// For even moduli, the positive representative is chosen for the element `modulus / 2`. + /// Use [`PolynomialRingZq::get_representative_least_nonnegative_residue`] if they should be + /// in the range `[0, modulus)`. + /// + /// # Examples + /// ``` + /// use qfall_math::integer_mod_q::PolynomialRingZq; + /// use qfall_math::integer::PolyOverZ; + /// use std::str::FromStr; + /// + /// let value = PolynomialRingZq::from_str("2 10 11 / 4 1 0 0 1 mod 21").unwrap(); + /// + /// let least_abs_residue = value.get_representative_least_absolute_residue(); + /// + /// assert_eq!(PolyOverZ::from_str("2 10 -10").unwrap(), least_abs_residue); + /// ``` + pub fn get_representative_least_absolute_residue(&self) -> PolyOverZ { + let mut out = PolyOverZ::default(); + for i in 0..=self.get_degree() { + let coeff: Zq = unsafe { self.get_coeff_unchecked(i) }; + let lar_coeff = coeff.get_representative_least_absolute_residue(); + unsafe { out.set_coeff_unchecked(i, lar_coeff) }; + } + out + } + /// Returns a representative polynomial of the [`PolynomialRingZq`] element. /// /// The representation of the coefficients is in the range `[0, modulus)` and /// the representation of the polynomial is in the range `[0, modulus_polynomial)`. + /// Use [`PolynomialRingZq::get_representative_least_absolute_residue`] if they should be + /// in the range `[-modulus/2, modulus/2]`. /// /// # Examples /// ``` @@ -258,6 +289,40 @@ mod test_get_mod { } } +#[cfg(test)] +mod test_get_representative_least_absolute_residue { + use crate::{integer::PolyOverZ, integer_mod_q::PolynomialRingZq}; + use std::str::FromStr; + + /// Check whether `get_representative_least_absolute_residue` outputs the correct value for large values + #[test] + fn large_numbers() { + let poly_ring = PolynomialRingZq::from_str(&format!( + "2 {} {} / 4 1 0 0 1 mod {}", + i64::MAX, + u64::MAX - 1, + u64::MAX + )) + .unwrap(); + + let poly_z = poly_ring.get_representative_least_absolute_residue(); + + let cmp_poly = PolyOverZ::from_str(&format!("2 {} -1", i64::MAX)).unwrap(); + assert_eq!(cmp_poly, poly_z); + } + + /// Check whether `get_representative_least_absolute_residue` outputs the correct value for special cases + #[test] + fn special_numbers() { + let poly_ring = PolynomialRingZq::from_str("3 10 0 11 / 4 1 0 0 1 mod 21").unwrap(); + + let poly_z = poly_ring.get_representative_least_absolute_residue(); + + let cmp_poly = PolyOverZ::from_str("3 10 0 -10").unwrap(); + assert_eq!(cmp_poly, poly_z); + } +} + #[cfg(test)] mod test_get_representative_least_nonnegative_residue { use crate::{ diff --git a/src/integer_mod_q/z_q/get.rs b/src/integer_mod_q/z_q/get.rs index f25b9af9..f9177f53 100644 --- a/src/integer_mod_q/z_q/get.rs +++ b/src/integer_mod_q/z_q/get.rs @@ -49,14 +49,15 @@ impl Zq { /// /// let z_value = zq_value.get_representative_least_absolute_residue(); /// - /// assert_eq!(Z::from(2), z_value); + /// assert_eq!(Z::from(-2), z_value); /// ``` pub fn get_representative_least_absolute_residue(&self) -> Z { let mod_z = Z::from(&self.modulus); - if self.value < mod_z.div_ceil(2) { - self.value.clone() + let mod_half = mod_z.div_floor(2); + if self.value > mod_half { + &self.value - mod_z } else { - Z::from(self.modulus.clone()) - self.value.clone() + self.value.clone() } } @@ -123,7 +124,7 @@ mod test_get_representative_least_absolute_residue { let res_1 = value_1.get_representative_least_absolute_residue(); assert_eq!(res_0, Z::from(2)); - assert_eq!(res_1, Z::from(2)); + assert_eq!(res_1, Z::from(-2)); } /// Check whether `get_representative_least_absolute_residue` outputs the correct value for large values @@ -136,7 +137,7 @@ mod test_get_representative_least_absolute_residue { let res_1 = value_1.get_representative_least_absolute_residue(); assert_eq!(res_0, Z::from(i64::MAX)); - assert_eq!(res_1, Z::from(1)); + assert_eq!(res_1, Z::from(-1)); } /// Check whether `get_representative_least_absolute_residue` outputs the correct value for special cases @@ -144,12 +145,15 @@ mod test_get_representative_least_absolute_residue { fn get_special() { let value_0 = Zq::from((10, 20)); let value_1 = Zq::from((0, 20)); + let value_2 = Zq::from((11, 21)); let res_0 = value_0.get_representative_least_absolute_residue(); let res_1 = value_1.get_representative_least_absolute_residue(); + let res_2 = value_2.get_representative_least_absolute_residue(); assert_eq!(res_0, Z::from(10)); assert_eq!(res_1, Z::from(0)); + assert_eq!(res_2, Z::from(-10)); } }