use super::MatPolynomialRingZq;
use crate::{
integer::fmpz_poly_helpers::reduce_fmpz_poly_by_fmpz_mod_poly_sparse, traits::MatrixDimensions,
};
use flint_sys::fmpz_poly_mat::fmpz_poly_mat_entry;
impl MatPolynomialRingZq {
pub(crate) fn reduce(&mut self) {
for row_num in 0..self.matrix.get_num_rows() {
for column_num in 0..self.matrix.get_num_columns() {
unsafe { self.reduce_entry(row_num, column_num) };
}
}
}
pub(crate) unsafe fn reduce_entry(&mut self, row: i64, column: i64) {
let entry = unsafe { fmpz_poly_mat_entry(&self.matrix.matrix, row, column) };
if (unsafe { *entry }).length > 0 {
unsafe {
reduce_fmpz_poly_by_fmpz_mod_poly_sparse(
&mut *entry,
&self.modulus.modulus.poly,
&self.modulus.non_zero,
self.modulus.get_q_as_modulus().get_fmpz_mod_ctx_struct(),
)
}
}
}
}
#[cfg(test)]
mod test_reduced {
use crate::{
integer::MatPolyOverZ,
integer_mod_q::{ModulusPolynomialRingZq, mat_polynomial_ring_zq::MatPolynomialRingZq},
};
use std::str::FromStr;
const LARGE_PRIME: u64 = u64::MAX - 58;
#[test]
fn reduces() {
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 11").unwrap();
let poly_mat = MatPolyOverZ::from_str("[[4 -1 0 1 1, 1 42],[0, 2 1 2]]").unwrap();
let mut poly_ring_mat = MatPolynomialRingZq {
matrix: poly_mat,
modulus,
};
let cmp_modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 11").unwrap();
let cmp_poly_mat = MatPolyOverZ::from_str("[[3 9 0 1, 1 9],[0, 2 1 2]]").unwrap();
let cmp_poly_ring_mat = MatPolynomialRingZq {
matrix: cmp_poly_mat.clone(),
modulus: cmp_modulus,
};
assert_ne!(poly_ring_mat.matrix, cmp_poly_mat);
assert_ne!(poly_ring_mat, cmp_poly_ring_mat);
poly_ring_mat.reduce();
assert_eq!(poly_ring_mat.matrix, cmp_poly_mat);
assert_eq!(poly_ring_mat, cmp_poly_ring_mat);
}
#[test]
fn large_values() {
let modulus =
ModulusPolynomialRingZq::from_str(&format!("4 {} 0 0 1 mod {LARGE_PRIME}", i64::MAX))
.unwrap();
let poly_mat =
MatPolyOverZ::from_str(&format!("[[4 -1 0 {} 1, 1 42],[0, 2 1 2]]", i64::MAX))
.unwrap();
let mut poly_ring_mat = MatPolynomialRingZq {
matrix: poly_mat,
modulus,
};
let cmp_modulus =
ModulusPolynomialRingZq::from_str(&format!("4 {} 0 0 1 mod {LARGE_PRIME}", i64::MAX))
.unwrap();
let cmp_poly_mat = MatPolyOverZ::from_str(&format!(
"[[3 {} 0 {}, 1 42],[0, 2 1 2]]",
LARGE_PRIME - i64::MAX as u64 - 1,
i64::MAX
))
.unwrap();
let cmp_poly_ring_mat = MatPolynomialRingZq {
matrix: cmp_poly_mat.clone(),
modulus: cmp_modulus,
};
assert_ne!(poly_ring_mat.matrix, cmp_poly_mat);
assert_ne!(poly_ring_mat, cmp_poly_ring_mat);
poly_ring_mat.reduce();
assert_eq!(poly_ring_mat.matrix, cmp_poly_mat);
assert_eq!(poly_ring_mat, cmp_poly_ring_mat);
}
}