use super::super::PolyOverZq;
use crate::{
error::MathError,
integer::PolyOverZ,
integer_mod_q::PolynomialRingZq,
macros::arithmetics::{
arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
arithmetic_trait_mixed_borrowed_owned,
},
traits::CompareBase,
};
use flint_sys::fmpz_mod_poly::fmpz_mod_poly_sub;
use std::{
ops::{Sub, SubAssign},
str::FromStr,
};
impl SubAssign<&PolyOverZq> for PolyOverZq {
fn sub_assign(&mut self, other: &Self) {
if !self.compare_base(other) {
panic!("{}", self.call_compare_base_error(other).unwrap());
}
unsafe {
fmpz_mod_poly_sub(
&mut self.poly,
&self.poly,
&other.poly,
self.modulus.get_fmpz_mod_ctx_struct(),
)
};
}
}
impl SubAssign<&PolyOverZ> for PolyOverZq {
fn sub_assign(&mut self, other: &PolyOverZ) {
let other = PolyOverZq::from((other, self.get_mod()));
self.sub_assign(&other);
}
}
arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, PolyOverZq, PolyOverZq);
arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, PolyOverZq, PolyOverZ);
impl Sub for &PolyOverZq {
type Output = PolyOverZq;
fn sub(self, other: Self) -> Self::Output {
self.sub_safe(other).unwrap()
}
}
arithmetic_trait_borrowed_to_owned!(Sub, sub, PolyOverZq, PolyOverZq, PolyOverZq);
arithmetic_trait_mixed_borrowed_owned!(Sub, sub, PolyOverZq, PolyOverZq, PolyOverZq);
impl Sub<&PolyOverZ> for &PolyOverZq {
type Output = PolyOverZq;
fn sub(self, other: &PolyOverZ) -> Self::Output {
let mut out = PolyOverZq::from(&self.modulus);
unsafe {
fmpz_mod_poly_sub(
&mut out.poly,
&self.poly,
&PolyOverZq::from((other, &self.modulus)).poly,
self.modulus.get_fmpz_mod_ctx_struct(),
);
}
out
}
}
arithmetic_trait_borrowed_to_owned!(Sub, sub, PolyOverZq, PolyOverZ, PolyOverZq);
arithmetic_trait_mixed_borrowed_owned!(Sub, sub, PolyOverZq, PolyOverZ, PolyOverZq);
impl Sub<&PolynomialRingZq> for &PolyOverZq {
type Output = PolynomialRingZq;
fn sub(self, other: &PolynomialRingZq) -> Self::Output {
let mut out = PolynomialRingZq::from((self, &other.modulus));
out -= other;
out
}
}
arithmetic_trait_borrowed_to_owned!(Sub, sub, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
arithmetic_trait_mixed_borrowed_owned!(Sub, sub, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
impl PolyOverZq {
pub fn sub_safe(&self, other: &Self) -> Result<PolyOverZq, MathError> {
if !self.compare_base(other) {
return Err(self.call_compare_base_error(other).unwrap());
}
let mut out = PolyOverZq::from_str(&format!("0 mod {}", self.modulus)).unwrap();
unsafe {
fmpz_mod_poly_sub(
&mut out.poly,
&self.poly,
&other.poly,
self.modulus.get_fmpz_mod_ctx_struct(),
);
}
Ok(out)
}
}
#[cfg(test)]
mod test_sub_assign {
use super::PolyOverZq;
use crate::integer::PolyOverZ;
use std::str::FromStr;
#[test]
fn correct_small() {
let mut a = PolyOverZq::from_str("3 6 2 -3 mod 7").unwrap();
let b = PolyOverZq::from_str("5 -1 -2 -5 -1 -2 mod 7").unwrap();
let cmp = PolyOverZq::from_str("5 0 4 2 1 2 mod 7").unwrap();
a -= b;
assert_eq!(cmp, a);
}
#[test]
fn correct_large() {
let mut a = PolyOverZq::from_str(&format!(
"3 {} {} {} mod {}",
u32::MAX,
i32::MIN,
i32::MAX,
u64::MAX
))
.unwrap();
let b = PolyOverZq::from_str(&format!("2 -{} -{} mod {}", u32::MAX, i32::MAX, u64::MAX))
.unwrap();
let cmp = PolyOverZq::from_str(&format!(
"3 {} -1 {} mod {}",
u64::from(u32::MAX) * 2,
i32::MAX,
u64::MAX
))
.unwrap();
a -= b;
assert_eq!(cmp, a);
}
#[test]
fn availability() {
let mut a = PolyOverZq::from_str("3 1 2 -3 mod 5").unwrap();
let b = PolyOverZq::from_str("3 -1 -2 3 mod 5").unwrap();
let c = PolyOverZ::from_str("2 -2 2").unwrap();
a -= &b;
a -= b;
a -= &c;
a -= c;
}
#[test]
#[should_panic]
fn mismatching_moduli() {
let mut a: PolyOverZq = PolyOverZq::from_str("3 -5 4 1 mod 7").unwrap();
let b: PolyOverZq = PolyOverZq::from_str("3 -5 4 1 mod 8").unwrap();
a -= b;
}
}
#[cfg(test)]
mod test_sub {
use super::PolyOverZq;
use std::str::FromStr;
#[test]
fn sub() {
let a: PolyOverZq = PolyOverZq::from_str("3 2 4 6 mod 7").unwrap();
let b: PolyOverZq = PolyOverZq::from_str("3 -5 5 1 mod 7").unwrap();
let c: PolyOverZq = a - b;
assert_eq!(c, PolyOverZq::from_str("3 0 6 5 mod 7").unwrap());
}
#[test]
fn sub_borrow() {
let a: PolyOverZq = PolyOverZq::from_str("3 2 4 6 mod 7").unwrap();
let b: PolyOverZq = PolyOverZq::from_str("3 -5 5 1 mod 7").unwrap();
let c: PolyOverZq = &a - &b;
assert_eq!(c, PolyOverZq::from_str("3 0 6 5 mod 7").unwrap());
}
#[test]
fn sub_first_borrowed() {
let a: PolyOverZq = PolyOverZq::from_str("3 2 4 6 mod 7").unwrap();
let b: PolyOverZq = PolyOverZq::from_str("3 -5 5 1 mod 7").unwrap();
let c: PolyOverZq = a - b;
assert_eq!(c, PolyOverZq::from_str("3 0 6 5 mod 7").unwrap());
}
#[test]
fn sub_second_borrowed() {
let a: PolyOverZq = PolyOverZq::from_str("3 2 4 6 mod 7").unwrap();
let b: PolyOverZq = PolyOverZq::from_str("3 -5 5 1 mod 7").unwrap();
let c: PolyOverZq = a - b;
assert_eq!(c, PolyOverZq::from_str("3 0 6 5 mod 7").unwrap());
}
#[test]
fn sub_reduce() {
let a: PolyOverZq = PolyOverZq::from_str("3 2 4 1 mod 7").unwrap();
let b: PolyOverZq = PolyOverZq::from_str("3 -5 4 -6 mod 7").unwrap();
let c: PolyOverZq = a - b;
assert_eq!(c, PolyOverZq::from_str("0 mod 7").unwrap());
}
#[test]
fn sub_large_numbers() {
let a: PolyOverZq = PolyOverZq::from_str(&format!(
"3 -{} 4 {} mod {}",
u64::MAX,
i64::MIN,
u64::MAX - 58
))
.unwrap();
let b: PolyOverZq = PolyOverZq::from_str(&format!(
"3 {} 5 {} mod {}",
i64::MIN,
i64::MIN,
u64::MAX - 58
))
.unwrap();
let c: PolyOverZq = a - b;
assert_eq!(
c,
PolyOverZq::from_str(&format!(
"2 {} -1 mod {}",
i128::from(i64::MAX) - 57,
u64::MAX - 58
))
.unwrap()
);
}
#[test]
#[should_panic]
fn sub_mismatching_modulus() {
let a: PolyOverZq = PolyOverZq::from_str("3 2 4 6 mod 9").unwrap();
let b: PolyOverZq = PolyOverZq::from_str("3 -5 5 1 mod 7").unwrap();
let _c: PolyOverZq = a - b;
}
#[test]
fn sub_safe_is_err() {
let a: PolyOverZq = PolyOverZq::from_str("3 2 4 6 mod 9").unwrap();
let b: PolyOverZq = PolyOverZq::from_str("3 -5 5 1 mod 7").unwrap();
assert!(&a.sub_safe(&b).is_err());
}
}
#[cfg(test)]
mod test_mul_poly_over_z {
use super::PolyOverZq;
use crate::integer::PolyOverZ;
use std::str::FromStr;
#[test]
fn borrowed_correctness() {
let poly_1 = PolyOverZq::from_str(&format!("1 {} mod {}", i64::MAX, u64::MAX)).unwrap();
let poly_2 = PolyOverZ::from_str("2 1 2").unwrap();
let poly_cmp =
PolyOverZq::from_str(&format!("2 {} -2 mod {}", i64::MAX as u64 - 1, u64::MAX))
.unwrap();
let poly_1 = &poly_1 - &poly_2;
assert_eq!(poly_cmp, poly_1);
}
#[test]
fn availability() {
let poly = PolyOverZq::from_str("3 1 2 3 mod 17").unwrap();
let z = PolyOverZ::from(2);
_ = poly.clone() - z.clone();
_ = &poly - &z;
_ = &poly - z.clone();
_ = poly.clone() - &z;
}
}
#[cfg(test)]
mod test_sub_poly_ring_zq {
use super::PolynomialRingZq;
use crate::integer_mod_q::PolyOverZq;
use std::str::FromStr;
#[test]
fn borrowed_correctness() {
let poly_1 =
PolynomialRingZq::from_str(&format!("2 2 {} / 4 1 2 3 1 mod {}", i64::MAX, u64::MAX))
.unwrap();
let poly_2 = PolynomialRingZq::from_str(&format!(
"2 -1 -{} / 4 1 2 3 1 mod {}",
i64::MAX as u64 - 2,
u64::MAX
))
.unwrap();
let poly = PolyOverZq::from_str(&format!("2 1 2 mod {}", u64::MAX)).unwrap();
let poly_1 = &poly - &poly_1;
assert_eq!(poly_2, poly_1);
}
#[test]
fn availability() {
let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 1 mod 17").unwrap();
let zq = PolyOverZq::from((2, 17));
_ = zq.clone() - poly.clone();
_ = &zq - &poly;
_ = zq.clone() - &poly;
_ = &zq - poly.clone();
}
#[test]
#[should_panic]
fn different_moduli_panic() {
let poly = PolynomialRingZq::from_str("3 1 2 3 / 4 1 2 3 4 mod 17").unwrap();
let zq = PolyOverZq::from((2, 16));
_ = &zq - &poly;
}
}