use ark_ff::Field;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError};
use ark_std::{
cmp::Ordering,
fmt::{Debug, Error, Formatter},
hash::Hash,
io::{Read, Write},
ops::Deref,
vec::Vec,
};
#[cfg(feature = "parallel")]
use rayon::prelude::*;
mod sparse;
pub use sparse::SparsePolynomial;
pub trait Term:
Clone
+ PartialOrd
+ Ord
+ PartialEq
+ Eq
+ Hash
+ Default
+ Debug
+ Deref<Target = [(usize, usize)]>
+ Send
+ Sync
+ CanonicalSerialize
+ CanonicalDeserialize
{
fn new(term: Vec<(usize, usize)>) -> Self;
fn degree(&self) -> usize;
fn vars(&self) -> Vec<usize>;
fn powers(&self) -> Vec<usize>;
fn is_constant(&self) -> bool;
fn evaluate<F: Field>(&self, p: &[F]) -> F;
}
#[derive(Clone, PartialEq, Eq, Hash, Default, CanonicalSerialize, CanonicalDeserialize)]
pub struct SparseTerm(Vec<(usize, usize)>);
impl SparseTerm {
fn combine(term: &[(usize, usize)]) -> Vec<(usize, usize)> {
let mut term_dedup: Vec<(usize, usize)> = Vec::new();
for (var, pow) in term {
match term_dedup.last_mut() {
Some(prev) => {
if prev.0 == *var {
prev.1 += pow;
continue;
}
}
_ => {}
};
term_dedup.push((*var, *pow));
}
term_dedup
}
}
impl Term for SparseTerm {
fn new(mut term: Vec<(usize, usize)>) -> Self {
term.retain(|(_, pow)| *pow != 0);
if term.len() > 1 {
term.sort_by(|(v1, _), (v2, _)| v1.cmp(v2));
term = Self::combine(&term);
}
Self(term)
}
fn degree(&self) -> usize {
self.iter().fold(0, |sum, acc| sum + acc.1)
}
fn vars(&self) -> Vec<usize> {
self.iter().map(|(v, _)| *v).collect()
}
fn powers(&self) -> Vec<usize> {
self.iter().map(|(_, p)| *p).collect()
}
fn is_constant(&self) -> bool {
self.len() == 0
}
fn evaluate<F: Field>(&self, point: &[F]) -> F {
cfg_into_iter!(self)
.map(|(var, power)| point[*var].pow(&[*power as u64]))
.product()
}
}
impl Debug for SparseTerm {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
for variable in self.iter() {
if variable.1 == 1 {
write!(f, " * x_{}", variable.0)?;
} else {
write!(f, " * x_{}^{}", variable.0, variable.1)?;
}
}
Ok(())
}
}
impl Deref for SparseTerm {
type Target = [(usize, usize)];
fn deref(&self) -> &[(usize, usize)] {
&self.0
}
}
impl PartialOrd for SparseTerm {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
if self.degree() != other.degree() {
Some(self.degree().cmp(&other.degree()))
} else {
for (cur, other) in self.iter().zip(other.iter()) {
if other.0 == cur.0 {
if cur.1 != other.1 {
return Some((cur.1).cmp(&other.1));
}
} else {
return Some((other.0).cmp(&cur.0));
}
}
Some(Ordering::Equal)
}
}
}
impl Ord for SparseTerm {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap()
}
}