mod sealed {
pub trait SizedExt: std::marker::Sized + std::fmt::Debug + std::fmt::Display {}
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 modulo_n_tools::{add_mod, mul_mod, sub_mod};
use num_traits::{One, Zero};
use ring_algorithm::{modulo_inverse, RingNormalize};
use sealed::Sized;
use std::fmt::Debug;
use std::ops::{Add, AddAssign, Div, Mul, Neg, Rem, Sub, SubAssign};
mod ops;
#[derive(Clone, Debug)]
pub struct PolynomialOverP<T> {
coef: Vec<T>,
prime: T,
}
impl<T: Sized> PartialEq for PolynomialOverP<T>
where
T: Clone + Eq + Zero,
for<'x> &'x T: Sub<Output = T> + Rem<Output = T>,
{
fn eq(&self, other: &Self) -> bool {
if self.prime != other.prime {
return false;
}
if self.coef.len() != other.coef.len() {
return false;
}
for (v, w) in self.coef.iter().zip(other.coef.iter()) {
if !(&(v - w) % &self.prime).is_zero() {
return false;
}
}
true
}
}
impl<T: Sized> Eq for PolynomialOverP<T>
where
T: Clone + Eq + Zero,
for<'x> &'x T: Sub<Output = T> + Rem<Output = T>,
{
}
impl<T: Sized> PolynomialOverP<T> {
fn len(&self) -> usize {
self.coef.len()
}
pub fn deg(&self) -> Option<usize> {
if self.coef.is_empty() {
None
} else {
Some(self.len() - 1)
}
}
pub fn lc(&self) -> Option<&T> {
self.deg().map(|d| &self.coef[d])
}
pub fn coefs(self) -> Vec<T> {
self.coef
}
pub fn prime_ref(&self) -> &T {
&self.prime
}
fn trim_zero(&mut self)
where
T: Zero,
{
let len = self
.coef
.iter()
.rposition(|x| !x.is_zero())
.map(|pos| pos + 1)
.unwrap_or(0);
self.coef.truncate(len);
}
fn extend(&mut self, len: usize)
where
T: Zero,
{
if self.len() < len {
self.coef.resize_with(len, T::zero);
}
}
pub fn new(coef: Vec<T>, prime: T) -> Self
where
T: Zero,
for<'x> &'x T: Rem<Output = T>,
{
let mut poly = Self {
coef: coef.into_iter().map(|x| &x % &prime).collect(),
prime,
};
poly.trim_zero();
poly
}
pub fn from_monomial(coefficent: T, degree: usize, prime: T) -> Self
where
T: Zero,
{
let coef = if coefficent.is_zero() {
Vec::new()
} else {
let mut coef = Vec::with_capacity(degree + 1);
for _ in 0..degree {
coef.push(T::zero());
}
coef.push(coefficent);
coef
};
Self { coef, prime }
}
fn add_assign_ref(&mut self, other: &Self)
where
T: Clone + Ord + Zero + for<'x> AddAssign<&'x T> + for<'x> SubAssign<&'x T>,
for<'x> &'x T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> + Rem<Output = T>,
{
if self.is_zero() {
*self = other.clone();
return;
} else if other.is_zero() {
return;
}
let len = self.len();
self.extend(other.len());
let prime = self.prime.clone();
self.coef
.iter_mut()
.zip(other.coef.iter())
.for_each(|(l, r)| {
*l = add_mod::<T>(&*l, r, &prime);
});
if len == other.len() {
self.trim_zero()
}
}
fn neg_impl(self) -> Self
where
T: Clone + Neg<Output = T>,
{
Self {
coef: self.coef.into_iter().map(|v| -v).collect(),
prime: self.prime,
}
}
fn neg_ref(&self) -> Self
where
T: Clone,
for<'x> &'x T: Neg<Output = T>,
{
Self {
coef: self.coef.iter().map(|v| -v).collect(),
prime: self.prime.clone(),
}
}
fn sub_assign_ref(&mut self, other: &Self)
where
T: Clone + Ord + Zero + for<'x> AddAssign<&'x T> + for<'x> SubAssign<&'x T>,
for<'x> &'x T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> + Rem<Output = T>,
{
if self.is_zero() {
*self = -other;
return;
} else if other.is_zero() {
return;
}
let len = self.len();
self.extend(other.len());
let prime = self.prime.clone();
self.coef
.iter_mut()
.zip(other.coef.iter())
.for_each(|(l, r)| *l = sub_mod::<T>(&*l, r, &prime));
if len == other.len() {
self.trim_zero()
}
}
fn mul_impl(&self, other: &Self) -> Self
where
T: Sized + Clone + Ord + Zero + for<'x> AddAssign<&'x T> + for<'x> SubAssign<&'x T>,
for<'x> &'x T:
Add<Output = T> + Sub<Output = T> + Neg<Output = T> + Mul<Output = T> + Rem<Output = T>,
{
if self.is_zero() || other.is_zero() {
let prime = if self.prime.is_zero() {
other.prime.clone()
} else {
self.prime.clone()
};
return Self::new(Vec::new(), prime);
}
let mut coef = vec![T::zero(); self.len() + other.len() - 1];
let prime = self.prime.clone();
self.coef
.iter()
.enumerate()
.for_each(|(i, c)| mul_aux::<T>(&mut coef[i..], c, &other.coef, &prime));
Self {
coef,
prime: self.prime.clone(),
}
}
pub fn one(prime: T) -> Self
where
T: One,
{
Self {
coef: vec![T::one()],
prime,
}
}
pub fn eval<'a>(&self, x: &'a T) -> T
where
T: Sized + Clone + Zero,
for<'x> &'x T: Add<Output = T> + Mul<Output = T> + Rem<Output = T>,
{
if self.coef.is_empty() {
return T::zero();
}
let mut sum = self.lc().unwrap().clone();
for i in (0..self.len() - 1).rev() {
sum = &(&(&sum * x) + &self.coef[i]) % &self.prime;
}
sum
}
#[must_use]
pub fn derivative(self) -> Self
where
T: Clone + Zero + for<'x> AddAssign<&'x T> + TryFrom<usize>,
for<'x> &'x T: Mul<Output = T> + Rem<Output = T>,
<T as TryFrom<usize>>::Error: Debug,
{
let Self { coef, prime } = self;
let coef = coef
.into_iter()
.enumerate()
.skip(1)
.map(|(i, c)| mul_mod::<T>(&T::try_from(i).unwrap(), &c, &prime))
.collect();
PolynomialOverP::<T>::new(coef, prime)
}
pub fn monic(&mut self)
where
T: Clone + Eq + Zero + One + RingNormalize,
for<'x> &'x T:
Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T> + Rem<Output = T>,
{
if let Some(lc) = self.lc() {
let prime = self.prime.clone();
let lc_inv = modulo_inverse::<T>(lc.clone(), prime.clone()).unwrap();
self.coef
.iter_mut()
.for_each(|v| *v = mul_mod::<T>(&*v, &lc_inv, &prime));
}
}
#[allow(unknown_lints, clippy::return_self_not_must_use)]
pub fn division(&mut self, other: &Self) -> Self
where
T: Clone
+ Ord
+ Eq
+ Zero
+ One
+ for<'x> AddAssign<&'x T>
+ for<'x> SubAssign<&'x T>
+ RingNormalize,
for<'x> &'x T:
Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T> + Rem<Output = T>,
{
let g_deg = other.deg().expect("Division by zero");
if self.deg() < other.deg() {
let prime = if self.prime.is_zero() {
other.prime.clone()
} else {
self.prime.clone()
};
return Self::new(Vec::new(), prime);
}
let prime = self.prime.clone();
let lc_inv = modulo_inverse::<T>(other.lc().unwrap().clone(), prime.clone()).unwrap();
let mut coef = vec![T::zero(); self.len() - other.len() + 1];
while self.deg() >= other.deg() {
let d = self.deg().unwrap() - g_deg;
let c = mul_mod::<T>(self.lc().unwrap(), &lc_inv, &prime);
for i in 0..other.len() - 1 {
self.coef[i + d] = &(&self.coef[i + d] - &(&c * &other.coef[i])) % ′
}
self.coef.pop(); self.trim_zero();
coef[d] = c;
}
Self {
coef,
prime: self.prime.clone(),
}
}
pub fn pth_root(mut self) -> Option<Self>
where
T: Clone + Eq + Zero + TryFrom<usize> + TryInto<usize>,
for<'x> &'x T: Rem<Output = T>,
usize: std::convert::TryFrom<T>,
<T as TryFrom<usize>>::Error: Debug,
{
let b = self
.coef
.iter()
.enumerate()
.all(|(i, c)| (&T::try_from(i).unwrap() % &self.prime).is_zero() || c.is_zero());
if !b {
return None;
}
let n = self.coef.len();
let p = match usize::try_from(self.prime.clone()) {
Ok(x) => x,
Err(_) => return None,
};
let mut i = 1;
let mut j = p;
while j < n {
let (c1, c2) = self.coef.split_at_mut(j);
std::mem::swap(&mut c1[i], &mut c2[0]);
i += 1;
j += p;
}
self.coef.truncate(i);
Some(Self::new(self.coef, self.prime))
}
pub fn to_positive(&mut self)
where
T: Zero + Ord + for<'x> AddAssign<&'x T>,
{
let z = T::zero();
let p = &self.prime;
self.coef.iter_mut().for_each(|x| {
if *x < z {
*x += p;
}
});
}
}
fn mul_aux<T>(sum: &mut [T], coef: &T, vec: &[T], prime: &T)
where
T: Sized + Clone + Ord + Zero + for<'x> AddAssign<&'x T> + for<'x> SubAssign<&'x T>,
for<'x> &'x T: Add<Output = T> + Neg<Output = T> + Mul<Output = T> + Rem<Output = T>,
{
sum.iter_mut()
.zip(vec.iter())
.for_each(|(l, r)| *l = &(&(coef * r) + &*l) % prime);
}
impl<T> std::fmt::Display for PolynomialOverP<T>
where
T: std::cmp::Eq + std::fmt::Display + Zero + One,
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let vec = &self.coef;
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, "{}*x", c)?,
_ => write!(f, "{}*x^{}", c, i)?,
}
}
}
Ok(())
}
}
impl<T> RingNormalize for PolynomialOverP<T>
where
T: Sized + Clone + Eq + Zero + One + RingNormalize,
for<'x> &'x T:
Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T> + Rem<Output = T>,
{
fn leading_unit(&self) -> Self {
if let Some(x) = self.lc() {
Self::from_monomial(x.clone(), 0, self.prime.clone())
} else {
Self::one(self.prime.clone())
}
}
fn normalize_mut(&mut self) {
self.monic();
}
}
impl<T> Zero for PolynomialOverP<T>
where
T: Sized + Clone + Ord + Zero + for<'x> AddAssign<&'x T> + for<'x> SubAssign<&'x T>,
for<'x> &'x T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> + Rem<Output = T>,
{
fn zero() -> Self {
Self {
coef: Vec::new(),
prime: T::zero(),
}
}
fn is_zero(&self) -> bool {
self.deg().is_none()
}
}