use alloc::vec::Vec;
use core::fmt;
use core::ops::{Add, Div, Mul, Neg, Sub};
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Poly<T> {
coeffs: Vec<T>,
}
fn top_nonzero<T: Default + PartialEq>(v: &[T]) -> Option<usize> {
v.iter().rposition(|c| *c != T::default())
}
impl<T: Clone + Default + PartialEq> Poly<T> {
pub fn new(mut coeffs: Vec<T>) -> Poly<T> {
match top_nonzero(&coeffs) {
Some(i) => coeffs.truncate(i + 1),
None => coeffs.clear(),
}
Poly { coeffs }
}
pub fn zero() -> Poly<T> {
Poly { coeffs: Vec::new() }
}
pub fn constant(c: T) -> Poly<T> {
Poly::new(alloc::vec![c])
}
pub fn monomial(c: T, degree: usize) -> Poly<T> {
let mut v = Vec::with_capacity(degree + 1);
v.resize(degree, T::default());
v.push(c);
Poly::new(v)
}
#[inline]
pub fn coeffs(&self) -> &[T] {
&self.coeffs
}
#[inline]
pub fn is_zero(&self) -> bool {
self.coeffs.is_empty()
}
#[inline]
pub fn degree(&self) -> Option<usize> {
self.coeffs.len().checked_sub(1)
}
pub fn coeff(&self, i: usize) -> T {
self.coeffs.get(i).cloned().unwrap_or_default()
}
pub fn leading(&self) -> Option<&T> {
self.coeffs.last()
}
}
impl<T> Poly<T>
where
T: Clone + Default + PartialEq + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
{
pub fn add(&self, rhs: &Poly<T>) -> Poly<T> {
let n = self.coeffs.len().max(rhs.coeffs.len());
let mut out = Vec::with_capacity(n);
for i in 0..n {
out.push(self.coeff(i) + rhs.coeff(i));
}
Poly::new(out)
}
pub fn sub(&self, rhs: &Poly<T>) -> Poly<T> {
let n = self.coeffs.len().max(rhs.coeffs.len());
let mut out = Vec::with_capacity(n);
for i in 0..n {
out.push(self.coeff(i) - rhs.coeff(i));
}
Poly::new(out)
}
pub fn mul(&self, rhs: &Poly<T>) -> Poly<T> {
if self.is_zero() || rhs.is_zero() {
return Poly::zero();
}
let mut out = alloc::vec![T::default(); self.coeffs.len() + rhs.coeffs.len() - 1];
for (i, a) in self.coeffs.iter().enumerate() {
for (j, b) in rhs.coeffs.iter().enumerate() {
let prod = a.clone() * b.clone();
out[i + j] = out[i + j].clone() + prod;
}
}
Poly::new(out)
}
pub fn scalar_mul(&self, scalar: &T) -> Poly<T> {
Poly::new(
self.coeffs
.iter()
.map(|c| c.clone() * scalar.clone())
.collect(),
)
}
pub fn eval(&self, x: &T) -> T {
let mut acc = T::default();
for c in self.coeffs.iter().rev() {
acc = acc * x.clone() + c.clone();
}
acc
}
pub fn derivative(&self) -> Poly<T> {
if self.coeffs.len() < 2 {
return Poly::zero();
}
let mut out = Vec::with_capacity(self.coeffs.len() - 1);
for (i, c) in self.coeffs.iter().enumerate().skip(1) {
let mut acc = T::default();
for _ in 0..i {
acc = acc + c.clone();
}
out.push(acc);
}
Poly::new(out)
}
}
impl<T> Poly<T>
where
T: Clone
+ Default
+ PartialEq
+ Add<Output = T>
+ Sub<Output = T>
+ Mul<Output = T>
+ Neg<Output = T>,
{
pub fn neg(&self) -> Poly<T> {
Poly {
coeffs: self.coeffs.iter().map(|c| -c.clone()).collect(),
}
}
}
impl<T> Poly<T>
where
T: Clone
+ Default
+ PartialEq
+ Add<Output = T>
+ Sub<Output = T>
+ Mul<Output = T>
+ Div<Output = T>,
{
pub fn div_rem(&self, divisor: &Poly<T>) -> (Poly<T>, Poly<T>) {
let dd = divisor
.degree()
.expect("Poly::div_rem: division by zero polynomial");
let lead = divisor.leading().unwrap().clone();
let mut rem = self.coeffs.clone();
let mut quot = alloc::vec![T::default(); self.coeffs.len().saturating_sub(dd)];
while let Some(rd) = top_nonzero(&rem) {
if rd < dd {
break;
}
let coef = rem[rd].clone() / lead.clone();
let shift = rd - dd;
for (i, dc) in divisor.coeffs.iter().enumerate() {
rem[shift + i] = rem[shift + i].clone() - coef.clone() * dc.clone();
}
quot[shift] = coef;
}
(Poly::new(quot), Poly::new(rem))
}
pub fn rem(&self, divisor: &Poly<T>) -> Poly<T> {
self.div_rem(divisor).1
}
pub fn monic(&self) -> Poly<T> {
match self.leading() {
None => Poly::zero(),
Some(lead) => {
let inv_lead = lead.clone();
Poly::new(
self.coeffs
.iter()
.map(|c| c.clone() / inv_lead.clone())
.collect(),
)
}
}
}
pub fn gcd(&self, other: &Poly<T>) -> Poly<T> {
let mut a = self.clone();
let mut b = other.clone();
while !b.is_zero() {
let r = a.rem(&b);
a = b;
b = r;
}
a.monic()
}
}
impl<T: fmt::Display + Clone + Default + PartialEq> fmt::Display for Poly<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_zero() {
return f.write_str("0");
}
let mut first = true;
for (i, c) in self.coeffs.iter().enumerate().rev() {
if *c == T::default() {
continue;
}
if !first {
f.write_str(" + ")?;
}
first = false;
match i {
0 => write!(f, "{c}")?,
1 => write!(f, "{c}·x")?,
_ => write!(f, "{c}·x^{i}")?,
}
}
Ok(())
}
}
macro_rules! poly_binop {
($tr:ident, $m:ident, $atr:ident, $am:ident) => {
impl<T> core::ops::$tr for Poly<T>
where
T: Clone + Default + PartialEq + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
{
type Output = Poly<T>;
#[inline]
fn $m(self, rhs: Poly<T>) -> Poly<T> {
Poly::$m(&self, &rhs)
}
}
impl<T> core::ops::$tr<&Poly<T>> for &Poly<T>
where
T: Clone + Default + PartialEq + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
{
type Output = Poly<T>;
#[inline]
fn $m(self, rhs: &Poly<T>) -> Poly<T> {
Poly::$m(self, rhs)
}
}
impl<T> core::ops::$atr for Poly<T>
where
T: Clone + Default + PartialEq + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
{
#[inline]
fn $am(&mut self, rhs: Poly<T>) {
*self = Poly::$m(self, &rhs);
}
}
};
}
poly_binop!(Add, add, AddAssign, add_assign);
poly_binop!(Sub, sub, SubAssign, sub_assign);
poly_binop!(Mul, mul, MulAssign, mul_assign);