use super::super::PolyOverZ;
use crate::integer::Z;
use crate::integer_mod_q::{PolyOverZq, Zq};
use crate::macros::arithmetics::{
arithmetic_assign_between_types, arithmetic_assign_trait_borrowed_to_owned,
arithmetic_trait_borrowed_to_owned, arithmetic_trait_mixed_borrowed_owned,
arithmetic_trait_reverse,
};
use crate::macros::for_others::implement_for_others;
use crate::rational::{PolyOverQ, Q};
use flint_sys::fmpq_poly::fmpq_poly_scalar_mul_fmpq;
use flint_sys::fmpz_mod_poly::fmpz_mod_poly_scalar_mul_fmpz;
use flint_sys::fmpz_poly::{
fmpz_poly_scalar_mul_fmpz, fmpz_poly_scalar_mul_si, fmpz_poly_scalar_mul_ui,
};
use std::ops::{Mul, MulAssign};
impl Mul<&Z> for &PolyOverZ {
type Output = PolyOverZ;
fn mul(self, scalar: &Z) -> Self::Output {
let mut out = PolyOverZ::default();
unsafe {
fmpz_poly_scalar_mul_fmpz(&mut out.poly, &self.poly, &scalar.value);
}
out
}
}
arithmetic_trait_reverse!(Mul, mul, Z, PolyOverZ, PolyOverZ);
arithmetic_trait_borrowed_to_owned!(Mul, mul, PolyOverZ, Z, PolyOverZ);
arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, PolyOverZ, PolyOverZ);
arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZ, Z, PolyOverZ);
arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, PolyOverZ, PolyOverZ);
implement_for_others!(Z, PolyOverZ, PolyOverZ, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64);
impl Mul<&Zq> for &PolyOverZ {
type Output = PolyOverZq;
fn mul(self, scalar: &Zq) -> PolyOverZq {
let mut out = PolyOverZq::from(&scalar.modulus);
unsafe {
fmpz_mod_poly_scalar_mul_fmpz(
&mut out.poly,
&PolyOverZq::from((self, &scalar.modulus)).poly,
&scalar.value.value,
out.modulus.get_fmpz_mod_ctx_struct(),
)
}
out
}
}
arithmetic_trait_reverse!(Mul, mul, Zq, PolyOverZ, PolyOverZq);
arithmetic_trait_borrowed_to_owned!(Mul, mul, PolyOverZ, Zq, PolyOverZq);
arithmetic_trait_borrowed_to_owned!(Mul, mul, Zq, PolyOverZ, PolyOverZq);
arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZ, Zq, PolyOverZq);
arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Zq, PolyOverZ, PolyOverZq);
impl Mul<&Q> for &PolyOverZ {
type Output = PolyOverQ;
fn mul(self, scalar: &Q) -> PolyOverQ {
let mut out = PolyOverQ::default();
unsafe {
fmpq_poly_scalar_mul_fmpq(&mut out.poly, &PolyOverQ::from(self).poly, &scalar.value);
}
out
}
}
arithmetic_trait_reverse!(Mul, mul, Q, PolyOverZ, PolyOverQ);
arithmetic_trait_borrowed_to_owned!(Mul, mul, PolyOverZ, Q, PolyOverQ);
arithmetic_trait_borrowed_to_owned!(Mul, mul, Q, PolyOverZ, PolyOverQ);
arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZ, Q, PolyOverQ);
arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Q, PolyOverZ, PolyOverQ);
implement_for_others!(Q, PolyOverZ, PolyOverQ, Mul Scalar for f32 f64);
impl MulAssign<&Z> for PolyOverZ {
fn mul_assign(&mut self, scalar: &Z) {
unsafe { fmpz_poly_scalar_mul_fmpz(&mut self.poly, &self.poly, &scalar.value) };
}
}
impl MulAssign<i64> for PolyOverZ {
fn mul_assign(&mut self, scalar: i64) {
unsafe { fmpz_poly_scalar_mul_si(&mut self.poly, &self.poly, scalar) };
}
}
impl MulAssign<u64> for PolyOverZ {
fn mul_assign(&mut self, scalar: u64) {
unsafe { fmpz_poly_scalar_mul_ui(&mut self.poly, &self.poly, scalar) };
}
}
arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, PolyOverZ, Z);
arithmetic_assign_between_types!(MulAssign, mul_assign, PolyOverZ, i64, i32 i16 i8);
arithmetic_assign_between_types!(MulAssign, mul_assign, PolyOverZ, u64, u32 u16 u8);
#[cfg(test)]
mod test_mul_z {
use super::PolyOverZ;
use crate::integer::Z;
use std::str::FromStr;
#[test]
fn borrowed_correctness() {
let poly_1 = PolyOverZ::from_str(&format!("3 1 2 {}", i64::MAX)).unwrap();
let poly_2 = poly_1.clone();
let poly_3 = PolyOverZ::from_str(&format!("3 2 4 {}", (i64::MAX as u64) * 2)).unwrap();
let integer = Z::from(2);
let poly_1 = &poly_1 * &integer;
let poly_2 = &integer * &poly_2;
assert_eq!(poly_3, poly_1);
assert_eq!(poly_3, poly_2);
}
#[test]
fn availability() {
let poly = PolyOverZ::from_str("3 1 2 3").unwrap();
let z = Z::from(2);
_ = poly.clone() * z.clone();
_ = poly.clone() * 2i8;
_ = poly.clone() * 2u8;
_ = poly.clone() * 2i16;
_ = poly.clone() * 2u16;
_ = poly.clone() * 2i32;
_ = poly.clone() * 2u32;
_ = poly.clone() * 2i64;
_ = poly.clone() * 2u64;
_ = z.clone() * poly.clone();
_ = 2i8 * poly.clone();
_ = 2u64 * poly.clone();
_ = &poly * &z;
_ = &z * &poly;
_ = &poly * z.clone();
_ = z.clone() * &poly;
_ = poly.clone() * &z;
_ = &z * poly.clone();
_ = &poly * 2i8;
_ = 2i8 * &poly;
}
}
#[cfg(test)]
mod test_mul_zq {
use super::PolyOverZ;
use crate::integer_mod_q::{PolyOverZq, Zq};
use std::str::FromStr;
#[test]
fn borrowed_correctness() {
let poly_1 = PolyOverZ::from_str(&format!("3 1 2 {}", i64::MAX)).unwrap();
let poly_2 = poly_1.clone();
let poly_3 = PolyOverZq::from_str(&format!(
"3 2 4 {} mod {}",
(i64::MAX as u64) * 2,
u64::MAX
))
.unwrap();
let integer = Zq::from((2, u64::MAX));
let poly_1 = &poly_1 * &integer;
let poly_2 = &integer * &poly_2;
assert_eq!(poly_3, poly_1);
assert_eq!(poly_3, poly_2);
}
#[test]
fn availability() {
let poly = PolyOverZ::from_str("3 1 2 3").unwrap();
let z = Zq::from((2, 17));
_ = poly.clone() * z.clone();
_ = z.clone() * poly.clone();
_ = &poly * &z;
_ = &z * &poly;
_ = &poly * z.clone();
_ = z.clone() * &poly;
_ = &z * poly.clone();
_ = poly.clone() * &z;
}
}
#[cfg(test)]
mod test_mul_assign {
use crate::integer::{PolyOverZ, Z};
use std::str::FromStr;
#[test]
fn correct_small() {
let mut a = PolyOverZ::from_str("3 1 2 -3").unwrap();
let b = Z::from(2);
let c = Z::ZERO;
a *= &b;
assert_eq!(PolyOverZ::from_str("3 2 4 -6").unwrap(), a);
a *= &c;
assert_eq!(PolyOverZ::from(0), a);
}
#[test]
fn correct_large() {
let mut a = PolyOverZ::from_str("2 2 -1").unwrap();
let b = i32::MAX;
let cmp = PolyOverZ::from_str(&format!(
"2 {} {}",
i32::MAX as i64 * 2,
-(i32::MAX as i64)
))
.unwrap();
a *= b;
assert_eq!(cmp, a);
}
#[test]
fn availability() {
let mut a = PolyOverZ::from_str("3 1 2 -3").unwrap();
let b = Z::from(2);
a *= &b;
a *= b;
a *= 1_u8;
a *= 1_u16;
a *= 1_u32;
a *= 1_u64;
a *= 1_i8;
a *= 1_i16;
a *= 1_i32;
a *= 1_i64;
}
}
#[cfg(test)]
mod test_mul_q {
use super::PolyOverZ;
use crate::rational::{PolyOverQ, Q};
use std::str::FromStr;
#[test]
fn borrowed_correctness() {
let poly_1 = PolyOverZ::from_str(&format!("3 1 2 {}", (i64::MAX as u64) * 2)).unwrap();
let poly_2 = poly_1.clone();
let poly_3 = PolyOverQ::from_str(&format!("3 1/2 1 {}", i64::MAX)).unwrap();
let rational = Q::from((1, 2));
let poly_1 = &poly_1 * &rational;
let poly_2 = &rational * &poly_2;
assert_eq!(poly_3, poly_1);
assert_eq!(poly_3, poly_2);
}
#[test]
fn availability() {
let poly = PolyOverZ::from_str("3 1 2 3").unwrap();
let q = Q::from((1, 2));
_ = poly.clone() * q.clone();
_ = q.clone() * poly.clone();
_ = &poly * &q;
_ = &q * &poly;
_ = &poly * q.clone();
_ = q.clone() * &poly;
_ = &q * poly.clone();
_ = poly.clone() * &q;
_ = &poly * 1.0f32;
_ = &poly * 1.0f64;
}
}