#![cfg_attr(feature = "__internal_inject_debug", recursion_limit = "16")]
#![doc = include_str!("../README.md")]
mod sealed {
#[cfg(feature = "__internal_inject_debug")]
pub trait SizedExt: std::marker::Sized + std::fmt::Debug + std::fmt::Display {}
#[cfg(feature = "__internal_inject_debug")]
impl<T> SizedExt for T where T: std::marker::Sized + std::fmt::Debug + std::fmt::Display {}
#[cfg(not(feature = "__internal_inject_debug"))]
pub use std::marker::Sized;
#[cfg(feature = "__internal_inject_debug")]
pub use SizedExt as Sized;
}
use num_traits::{One, Zero};
use ring_algorithm::{gcd, RingNormalize};
use sealed::Sized;
use std::fmt;
use std::ops::{AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign};
mod ops;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Polynomial<T> {
coeff: Vec<T>,
}
impl<T: crate::Sized> Polynomial<T> {
fn len(&self) -> usize {
self.coeff.len()
}
pub fn deg(&self) -> Option<usize> {
if self.coeff.is_empty() {
None
} else {
Some(self.len() - 1)
}
}
pub fn lc(&self) -> Option<&T> {
self.deg().map(|d| &self.coeff[d])
}
pub fn coeffs(&self) -> &[T] {
&self.coeff
}
}
impl<M: crate::Sized + Zero> Polynomial<M> {
fn trim_zero(&mut self) {
let len = self
.coeff
.iter()
.rposition(|x| !x.is_zero())
.map(|pos| pos + 1)
.unwrap_or(0);
self.coeff.truncate(len);
}
pub fn new(coeff: Vec<M>) -> Self {
let mut poly = Self { coeff };
poly.trim_zero();
poly
}
fn extend(&mut self, len: usize) {
if self.len() < len {
self.coeff.resize_with(len, M::zero);
}
}
pub fn from_monomial(coefficent: M, degree: usize) -> Self {
let coeff = if coefficent.is_zero() {
Vec::new()
} else {
let mut coeff = Vec::with_capacity(degree + 1);
for _ in 0..degree {
coeff.push(M::zero());
}
coeff.push(coefficent);
coeff
};
Self { coeff }
}
}
#[macro_export]
macro_rules! polynomial {
($($x:expr),*) => {
Polynomial::new(vec![$($x), *])
}
}
impl<R> fmt::Display for Polynomial<R>
where
R: PartialEq + fmt::Display + Zero + One,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let vec = &self.coeff;
if vec.is_empty() {
return write!(f, "0");
}
let mut is_first = true;
for (i, c) in vec.iter().enumerate().rev() {
if c.is_zero() {
continue;
}
if is_first {
is_first = false;
} else {
write!(f, "+")?;
}
if c.is_one() {
match i {
0 => write!(f, "1")?,
1 => write!(f, "x")?,
_ => write!(f, "x^{i}")?,
}
} else {
match i {
0 => write!(f, "{c}")?,
1 => write!(f, "{c}*x")?,
_ => write!(f, "{c}*x^{i}")?,
}
}
}
Ok(())
}
}
impl<R: Sized> Polynomial<R> {
pub fn eval<'a>(&self, x: &'a R) -> R
where
R: Sized + Zero + for<'x> AddAssign<&'x R> + MulAssign<&'a R>,
{
let mut sum = R::zero();
for coeff in self.coeff.iter().rev() {
sum *= x;
sum += coeff;
}
sum
}
#[must_use]
pub fn derivative(&self) -> Self
where
R: Sized + Zero + One + for<'x> AddAssign<&'x R> + for<'x> From<<&'x R as Mul>::Output>,
for<'x> &'x R: Mul,
{
let n = self.coeff.len();
let n = if n > 0 { n - 1 } else { 0 };
let mut coeff = Vec::with_capacity(n);
let mut i = R::one();
for c in self.coeff.iter().skip(1) {
coeff.push(R::from(&i * c));
i += &R::one();
}
Polynomial::new(coeff)
}
pub fn pseudo_division(&mut self, other: &Self) -> (R, Self)
where
R: Sized
+ Clone
+ Zero
+ One
+ for<'x> AddAssign<&'x R>
+ for<'x> MulAssign<&'x R>
+ for<'x> From<<&'x R as Sub>::Output>
+ for<'x> From<<&'x R as Mul>::Output>,
for<'x> &'x R: Sub + Mul,
{
let g_deg = other.deg().expect("Division by zero");
let f_deg = self.deg();
if f_deg < other.deg() {
return (R::one(), Self::zero());
}
let f_deg = f_deg.unwrap();
debug_assert!(f_deg >= g_deg);
let k = f_deg - g_deg + 1;
let lc = other.lc().unwrap();
let mut coeff = vec![R::zero(); k];
let mut scale = R::one();
while self.deg() >= other.deg() {
let d = self.deg().unwrap() - g_deg;
let c = self.lc().unwrap().clone();
for i in 0..other.len() - 1 {
self.coeff[i + d] =
R::from(&R::from(lc * &self.coeff[i + d]) - &R::from(&c * &other.coeff[i]));
}
for i in 0..d {
self.coeff[i] *= lc;
}
self.coeff.pop(); self.trim_zero();
for c_i in coeff.iter_mut().skip(d + 1) {
*c_i *= lc;
}
coeff[d] = c;
scale *= lc;
}
(scale, Self { coeff })
}
pub fn resultant(mut self, other: Self) -> R
where
R: Sized
+ Clone
+ Zero
+ One
+ for<'x> AddAssign<&'x R>
+ for<'x> MulAssign<&'x R>
+ Neg<Output = R>
+ for<'x> From<<&'x R as Sub>::Output>
+ for<'x> From<<&'x R as Mul>::Output>
+ for<'x> From<<&'x R as Div>::Output>,
for<'x> &'x R: Sub + Mul + Div,
{
let f_deg = self.deg();
let g_deg = other.deg();
match (f_deg, g_deg) {
(Some(0), Some(0)) => R::one(),
(Some(0), None) => R::one(),
(None, Some(0)) => R::one(),
(None, None) => R::zero(),
(None, Some(_)) => R::zero(),
(Some(_), None) => R::zero(),
(Some(0), Some(m)) => {
ring_algorithm::power::<R, u64>(self.lc().unwrap().clone(), m as u64)
}
(Some(n), Some(0)) => {
ring_algorithm::power::<R, u64>(other.lc().unwrap().clone(), n as u64)
}
(Some(n), Some(m)) => {
debug_assert!(n >= 1);
debug_assert!(m >= 1);
let (scale, _) = self.pseudo_division(&other);
if let Some(l) = self.deg() {
let sign = if n * m % 2 == 0 { R::one() } else { -R::one() };
let mul = ring_algorithm::power::<R, u64>(
other.lc().unwrap().clone(),
(n - l) as u64,
);
let div = ring_algorithm::power::<R, u64>(scale, m as u64);
R::from(&(other.resultant(self) * sign * mul) / &div)
} else {
R::zero()
}
}
}
}
pub fn primitive_part_mut(&mut self)
where
R: Sized
+ Clone
+ Zero
+ for<'x> DivAssign<&'x R>
+ RingNormalize
+ for<'x> From<<&'x R as Rem>::Output>,
for<'x> &'x R: Rem,
{
if self.deg().is_none() {
return;
}
let mut g = self.coeff[0].clone();
for c in &self.coeff[1..] {
g = gcd::<R>(g, c.clone());
}
g.normalize_mut();
*self /= &g;
}
}
impl<K: Sized> Polynomial<K> {
pub fn monic(&mut self)
where
K: Clone + for<'x> DivAssign<&'x K>,
{
if let Some(lc) = self.lc() {
let lc = lc.clone();
*self /= &lc;
}
}
pub fn division(&mut self, other: &Self) -> Self
where
K: Sized
+ Clone
+ Zero
+ for<'x> AddAssign<&'x K>
+ for<'x> SubAssign<&'x K>
+ for<'x> MulAssign<&'x K>
+ for<'x> DivAssign<&'x K>,
{
let g_deg = other.deg().expect("Division by zero");
if self.deg() < other.deg() {
return Self::zero();
}
let lc = other.lc().unwrap();
let mut coeff = vec![K::zero(); self.len() - other.len() + 1];
while self.deg() >= other.deg() {
let d = self.deg().unwrap() - g_deg;
let mut c = self.lc().unwrap().clone();
c /= lc;
for i in 0..other.len() - 1 {
let mut c = c.clone();
c *= &other.coeff[i];
self.coeff[i + d] -= &c;
}
self.coeff.pop(); self.trim_zero();
coeff[d] = c;
}
Self { coeff }
}
#[must_use]
pub fn square_free(&self) -> Self
where
K: Sized
+ Clone
+ Zero
+ One
+ for<'x> AddAssign<&'x K>
+ for<'x> SubAssign<&'x K>
+ for<'x> MulAssign<&'x K>
+ for<'x> DivAssign<&'x K>
+ for<'x> From<<&'x K as Mul>::Output>
+ for<'x> From<<&'x K as Div>::Output>,
for<'x> &'x K: Mul + Div,
{
let d = self.derivative().into_normalize();
let f = ring_algorithm::gcd::<Self>(self.clone(), d).into_normalize();
(self / &f).into_normalize()
}
}