use crate::integer::Integer;
use crate::integer_vector::arithmetic::scalar_mul::{
integers_mul_scalar_assign, integers_mul_scalar_to_out,
};
use crate::natural::InnerNatural::Small;
use crate::natural::{LIMB_MAX_QUARTER, Natural, WIDTH_MINUS_2};
use crate::platform::{Limb, SignedDoubleLimb, SignedLimb};
use alloc::vec::Vec;
use core::fmt::Debug;
use core::ops::{AddAssign, MulAssign, SubAssign};
use malachite_base::num::arithmetic::traits::{
AddMulAssign, DivExactAssign, Pow, Square, SubMulAssign,
};
use malachite_base::num::basic::traits::{One, Zero};
use malachite_base::num::conversion::traits::{ExactFrom, WrappingFrom};
crate_test_trait! {
PolynomialCoefficient:
Clone
+ Debug
+ Default
+ Zero
+ One
+ Eq
+ From<u64>
+ for<'a> AddAssign<&'a Self>
+ for<'a> SubAssign<&'a Self>
+ for<'a> MulAssign<&'a Self>
+ for<'a> DivExactAssign<&'a Self>
+ for<'a> AddMulAssign<&'a Self, &'a Self>
+ for<'a> SubMulAssign<&'a Self, &'a Self>
+ ExactFrom<SignedLimb>
+ ExactFrom<SignedDoubleLimb>
{
fn is_zero(&self) -> bool;
fn is_negative(&self) -> bool;
fn unsigned_abs_ref(&self) -> &Natural;
fn from_sign_and_abs(sign: bool, abs: Natural) -> Self;
fn negate(self) -> Self;
fn double_assign(&mut self);
fn add_ref(&self, other: &Self) -> Self;
fn mul_ref(&self, other: &Self) -> Self;
fn square_ref(&self) -> Self;
fn pow_ref(&self, e: u64) -> Self;
fn vec_mul_scalar_to_out(out: &mut [Self], xs: &[Self], c: &Self);
fn vec_mul_scalar_assign(xs: &mut [Self], c: &Self);
}}
impl PolynomialCoefficient for Integer {
#[inline]
fn is_zero(&self) -> bool {
*self == 0u32
}
#[inline]
fn is_negative(&self) -> bool {
!self.sign
}
#[inline]
fn unsigned_abs_ref(&self) -> &Natural {
&self.abs
}
#[inline]
fn from_sign_and_abs(sign: bool, abs: Natural) -> Self {
Self::from_sign_and_abs(sign, abs)
}
#[inline]
fn negate(self) -> Self {
-self
}
#[inline]
fn double_assign(&mut self) {
*self <<= 1u32;
}
#[inline]
fn add_ref(&self, other: &Self) -> Self {
self + other
}
#[inline]
fn mul_ref(&self, other: &Self) -> Self {
self * other
}
#[inline]
fn square_ref(&self) -> Self {
self.square()
}
#[inline]
fn pow_ref(&self, e: u64) -> Self {
self.pow(e)
}
#[inline]
fn vec_mul_scalar_to_out(out: &mut [Self], xs: &[Self], c: &Self) {
integers_mul_scalar_to_out(out, xs, c);
}
#[inline]
fn vec_mul_scalar_assign(xs: &mut [Self], c: &Self) {
integers_mul_scalar_assign(xs, c);
}
}
impl PolynomialCoefficient for Natural {
#[inline]
fn is_zero(&self) -> bool {
*self == 0u32
}
#[inline]
fn is_negative(&self) -> bool {
false
}
#[inline]
fn unsigned_abs_ref(&self) -> &Natural {
self
}
#[inline]
fn from_sign_and_abs(sign: bool, abs: Natural) -> Self {
assert!(
sign || abs == 0u32,
"a Natural coefficient cannot be negative"
);
abs
}
#[inline]
fn negate(self) -> Self {
assert_eq!(self, 0u32, "a Natural coefficient cannot be negative");
self
}
#[inline]
fn double_assign(&mut self) {
*self <<= 1u32;
}
#[inline]
fn add_ref(&self, other: &Self) -> Self {
self + other
}
#[inline]
fn mul_ref(&self, other: &Self) -> Self {
self * other
}
#[inline]
fn square_ref(&self) -> Self {
self.square()
}
#[inline]
fn pow_ref(&self, e: u64) -> Self {
self.pow(e)
}
fn vec_mul_scalar_to_out(out: &mut [Self], xs: &[Self], c: &Self) {
let xs = &xs[..out.len()];
match *c {
Self(Small(0)) => out.fill(Self::ZERO),
Self(Small(1)) => out.clone_from_slice(xs),
_ => {
for (o, x) in out.iter_mut().zip(xs) {
*o = x * c;
}
}
}
}
fn vec_mul_scalar_assign(xs: &mut [Self], c: &Self) {
match *c {
Self(Small(0)) => xs.fill(Self::ZERO),
Self(Small(1)) => {}
_ => {
for x in xs {
*x *= c;
}
}
}
}
}
pub(crate) fn trim_coefficients<C: PolynomialCoefficient>(xs: &mut Vec<C>) {
while xs.last().is_some_and(PolynomialCoefficient::is_zero) {
xs.pop();
}
}
pub(crate) fn truncate_coefficients<C: PolynomialCoefficient>(xs: &mut Vec<C>, len: u64) {
if let Ok(len) = usize::try_from(len)
&& len < xs.len()
{
xs.truncate(len);
trim_coefficients(xs);
}
}
pub(crate) const COEFF_MAX: Limb = LIMB_MAX_QUARTER;
pub(crate) const SMALL_FMPZ_BITCOUNT_MAX: u64 = WIDTH_MINUS_2;
pub(crate) fn small_value<C: PolynomialCoefficient>(x: &C) -> Option<SignedLimb> {
match *x.unsigned_abs_ref() {
Natural(Small(small)) if small <= COEFF_MAX => {
let value = SignedLimb::wrapping_from(small);
Some(if x.is_negative() { -value } else { value })
}
_ => None,
}
}
pub(crate) fn small_values<T: From<SignedLimb>, C: PolynomialCoefficient>(xs: &[C]) -> Vec<T> {
xs.iter()
.map(|x| T::from(small_value(x).unwrap()))
.collect()
}