use crate::{
integer::{PolyOverZ, Z},
integer_mod_q::{Modulus, ModulusPolynomialRingZq, PolyOverZq, Zq},
traits::GetCoefficient,
};
use flint_sys::fmpz_mod_poly::fmpz_mod_poly_get_coeff_fmpz;
impl GetCoefficient<Zq> for ModulusPolynomialRingZq {
unsafe fn get_coeff_unchecked(&self, index: i64) -> Zq {
let out_z: Z = unsafe { self.get_coeff_unchecked(index) };
let modulus = self.modulus.modulus.clone();
Zq::from((out_z, modulus))
}
}
impl GetCoefficient<Z> for ModulusPolynomialRingZq {
unsafe fn get_coeff_unchecked(&self, index: i64) -> Z {
let mut out = Z::default();
let modulus = self.get_q_as_modulus();
unsafe {
fmpz_mod_poly_get_coeff_fmpz(
&mut out.value,
&self.modulus.poly,
index,
modulus.get_fmpz_mod_ctx_struct(),
)
}
out
}
}
impl ModulusPolynomialRingZq {
pub fn get_q_as_modulus(&self) -> Modulus {
self.modulus.modulus.clone()
}
pub fn get_q(&self) -> Z {
Z::from(&self.modulus.modulus)
}
pub fn get_degree(&self) -> i64 {
self.modulus.get_degree()
}
pub fn get_representative_least_nonnegative_residue(&self) -> PolyOverZ {
let poly_zq = PolyOverZq::from(self);
poly_zq.get_representative_least_nonnegative_residue()
}
}
#[cfg(test)]
mod test_get_coeff_z {
use crate::{
integer::Z,
integer_mod_q::{ModulusPolynomialRingZq, Zq},
traits::GetCoefficient,
};
use std::str::FromStr;
#[test]
fn index_out_of_range() {
let poly = ModulusPolynomialRingZq::from_str("4 0 1 2 1 mod 17").unwrap();
let zero_coeff_1: Z = poly.get_coeff(4).unwrap();
let zero_coeff_2 = poly.get_coeff(4).unwrap();
assert_eq!(0, zero_coeff_1);
assert_eq!(Zq::from((0, 17)), zero_coeff_2);
}
#[test]
fn positive_coeff() {
let poly = ModulusPolynomialRingZq::from_str("4 0 1 2 1 mod 17").unwrap();
let coeff_1: Z = poly.get_coeff(2).unwrap();
let coeff_2 = poly.get_coeff(2).unwrap();
assert_eq!(2, coeff_1);
assert_eq!(Zq::from((2, 17)), coeff_2);
}
#[test]
fn large_coeff() {
let poly =
ModulusPolynomialRingZq::from_str(&format!("2 {} 1 mod {}", u64::MAX - 1, u64::MAX))
.unwrap();
let coefficient_1: Z = poly.get_coeff(0).unwrap();
let coefficient_2: Zq = poly.get_coeff(0).unwrap();
assert_eq!(u64::MAX - 1, coefficient_1);
assert_eq!(Zq::from((u64::MAX - 1, u64::MAX)), coefficient_2);
}
#[test]
#[should_panic]
fn negative_index_error_z() {
let poly = ModulusPolynomialRingZq::from_str("4 0 1 2 1 mod 17").unwrap();
let _: Z = poly.get_coeff(-1).unwrap();
}
#[test]
#[should_panic]
fn negative_index_error_zq() {
let poly = ModulusPolynomialRingZq::from_str("4 0 1 2 1 mod 17").unwrap();
let _: Zq = poly.get_coeff(-1).unwrap();
}
}
#[cfg(test)]
mod test_get_degree {
use crate::integer_mod_q::ModulusPolynomialRingZq;
use std::str::FromStr;
#[test]
fn degree_constant() {
let degrees = [1, 3, 7, 15, 32, 120];
for degree in degrees {
let modulus_ring = ModulusPolynomialRingZq::from_str(&format!(
"{} {}1 mod 17",
degree + 1,
"0 ".repeat(degree)
))
.unwrap();
assert_eq!(degree as i64, modulus_ring.get_degree());
}
}
#[test]
fn degree_leading_zeros() {
let poly = ModulusPolynomialRingZq::from_str("4 2 1 0 0 mod 199").unwrap();
let deg = poly.get_degree();
assert_eq!(1, deg);
}
#[test]
fn degree_many_coefficients() {
let poly_1 = ModulusPolynomialRingZq::from_str("7 1 2 3 4 8 1 1 mod 2").unwrap();
let poly_2 = ModulusPolynomialRingZq::from_str(&format!(
"7 1 2 3 4 8 {} 1 mod {}",
u64::MAX,
u128::MAX
))
.unwrap();
let deg_1 = poly_1.get_degree();
let deg_2 = poly_2.get_degree();
assert_eq!(6, deg_1);
assert_eq!(6, deg_2);
}
}
#[cfg(test)]
mod test_get_q {
use crate::{integer::Z, integer_mod_q::ModulusPolynomialRingZq};
use std::str::FromStr;
#[test]
fn correct_large() {
let large_prime = u64::MAX - 58;
let modulus_ring =
ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {large_prime}")).unwrap();
let modulus = modulus_ring.get_q();
let cmp_modulus = Z::from(large_prime);
assert_eq!(cmp_modulus, modulus);
}
}
#[cfg(test)]
mod test_get_representative_least_nonnegative_residue {
use crate::{
integer::PolyOverZ,
integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq},
};
use std::str::FromStr;
#[test]
fn large_positive() {
let large_prime = u64::MAX - 58;
let modulus =
ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {large_prime}")).unwrap();
let poly = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
let poly_ring = PolynomialRingZq::from((&poly, &modulus));
let poly_z = poly_ring.get_representative_least_nonnegative_residue();
let cmp_poly = PolyOverZ::from_str(&format!("3 {} 0 1", u64::MAX - 60)).unwrap();
assert_eq!(cmp_poly, poly_z);
}
}