-
Notifications
You must be signed in to change notification settings - Fork 219
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
87 changed files
with
3,351 additions
and
697 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,91 @@ | ||
//! Modules for working with univariate or multivariate polynomials. | ||
use crate::Vec; | ||
use algebra_core::Field; | ||
use core::{ | ||
fmt::Debug, | ||
hash::Hash, | ||
ops::{AddAssign, Index, SubAssign}, | ||
}; | ||
use rand::Rng; | ||
|
||
pub mod multivariate; | ||
pub mod univariate; | ||
|
||
/// Describes the common interface for univariate and multivariate polynomials | ||
pub trait Polynomial<F: Field>: | ||
Sized | ||
+ Clone | ||
+ Debug | ||
+ Default | ||
+ Hash | ||
+ PartialEq | ||
+ Eq | ||
+ Send | ||
+ Sync | ||
+ for<'a> AddAssign<&'a Self> | ||
+ for<'a> AddAssign<(F, &'a Self)> | ||
+ for<'a> SubAssign<&'a Self> | ||
{ | ||
/// The domain of the polynomial. | ||
type Domain: Sized + Clone + Ord + Debug; | ||
|
||
/// Returns the zero polynomial. | ||
fn zero() -> Self; | ||
|
||
/// Checks if the given polynomial is zero. | ||
fn is_zero(&self) -> bool; | ||
|
||
/// Returns the total degree of the polynomial | ||
fn degree(&self) -> usize; | ||
|
||
/// Evaluates `self` at the given `point` in `Self::Domain`. | ||
fn evaluate(&self, point: &Self::Domain) -> F; | ||
|
||
/// If `num_vars` is `None`, outputs a polynomial a univariate polynomial | ||
/// of degree `d` where each coefficient is sampled uniformly at random. | ||
/// | ||
/// If `num_vars` is `Some(l)`, outputs an `l`-variate polynomial which | ||
/// is the sum of `l` `d`-degree univariate polynomials where each coefficient | ||
/// is sampled uniformly at random. | ||
fn rand<R: Rng>(d: usize, num_vars: Option<usize>, rng: &mut R) -> Self; | ||
|
||
/// Sample a random point from `Self::Domain`. | ||
fn rand_domain_point<R: Rng>(domain_size: Option<usize>, rng: &mut R) -> Self::Domain; | ||
} | ||
|
||
/// Describes the interface for univariate polynomials | ||
pub trait UVPolynomial<F: Field>: Polynomial<F> { | ||
/// Constructs a new polynomial from a list of coefficients. | ||
fn from_coefficients_slice(coeffs: &[F]) -> Self; | ||
|
||
/// Constructs a new polynomial from a list of coefficients. | ||
fn from_coefficients_vec(coeffs: Vec<F>) -> Self; | ||
|
||
/// Returns the coefficients of `self` | ||
fn coeffs(&self) -> &[F]; | ||
} | ||
|
||
/// Describes the interface for univariate polynomials | ||
pub trait MVPolynomial<F: Field>: Polynomial<F> | ||
where | ||
Self::Domain: Index<usize, Output = F>, | ||
{ | ||
/// The type of the terms of `self` | ||
type Term: multivariate::Term; | ||
|
||
/// Constructs a new polynomial from a list of tuples of the form `(Self::Term, coeff)` | ||
fn from_coefficients_slice(num_vars: usize, terms: &[(Self::Term, F)]) -> Self; | ||
|
||
/// Constructs a new polynomial from a list of tuples of the form `(Self::Term, coeff)` | ||
fn from_coefficients_vec(num_vars: usize, terms: Vec<(Self::Term, F)>) -> Self; | ||
|
||
/// Returns the terms of a `self` as a list of tuples of the form `(Self::Term, coeff)` | ||
fn terms(&self) -> &[(Self::Term, F)]; | ||
|
||
/// Given some point `z`, compute the quotients `w_i(X)` s.t | ||
/// | ||
/// `p(X) - p(z) = (X_1-z_1)*w_1(X) + (X_2-z_2)*w_2(X) + ... + (X_l-z_l)*w_l(X)` | ||
/// | ||
/// These quotients can always be found with no remainder. | ||
fn divide_at_point(&self, point: &Self::Domain) -> Vec<Self>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,145 @@ | ||
//! Work with multivariate polynomials. | ||
//! Work with sparse multivariate polynomials. | ||
use crate::Vec; | ||
use algebra_core::Field; | ||
use core::{ | ||
cmp::Ordering, | ||
fmt::{Debug, Error, Formatter}, | ||
hash::Hash, | ||
ops::Deref, | ||
}; | ||
|
||
mod sparse; | ||
#[cfg(feature = "parallel")] | ||
use rayon::prelude::*; | ||
|
||
pub use sparse::PolyVars; | ||
mod sparse; | ||
pub use sparse::SparsePolynomial; | ||
|
||
/// Describes the interface for a term of a multivariate polynomial. | ||
pub trait Term: | ||
Clone + PartialOrd + Ord + PartialEq + Eq + Hash + Default + Debug + Deref + Send + Sync | ||
{ | ||
/// Create a new Term from a list of tuples of the form `(variable, power)` | ||
fn new(term: Vec<(usize, usize)>) -> Self; | ||
|
||
/// Returns the sum of all variable powers in `self` | ||
fn degree(&self) -> usize; | ||
|
||
/// Returns a list of variables in `self` | ||
fn vars(&self) -> Vec<usize>; | ||
|
||
/// Returns whether `self` is a constant | ||
fn is_constant(&self) -> bool; | ||
|
||
/// Evaluates `self` at the given `point` in the field. | ||
fn evaluate<F: Field>(&self, point: &[F]) -> F; | ||
} | ||
|
||
/// Stores a single term in a multivariate polynomial. Each element | ||
/// is of the form `(variable, power)`. | ||
#[derive(Clone, PartialOrd, PartialEq, Eq, Hash, Default)] | ||
pub struct SparseTerm(Vec<(usize, usize)>); | ||
|
||
impl SparseTerm { | ||
/// Sums the powers of any duplicated variables. Assumes `term` is sorted. | ||
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 { | ||
/// Create a new Term from a list of tuples of the form `(variable, power)` | ||
fn new(mut term: Vec<(usize, usize)>) -> Self { | ||
// Remove any terms with power 0 | ||
term.retain(|(_, pow)| *pow != 0); | ||
// If there are more than one variables, make sure they are | ||
// in order and combine any duplicates | ||
if term.len() > 1 { | ||
term.sort_by(|(v1, _), (v2, _)| v1.cmp(v2)); | ||
term = Self::combine(&term); | ||
} | ||
Self(term) | ||
} | ||
|
||
/// Returns the sum of all variable powers in `self` | ||
fn degree(&self) -> usize { | ||
self.iter().fold(0, |sum, acc| sum + acc.1) | ||
} | ||
|
||
/// Returns a list of variables in `self` | ||
fn vars(&self) -> Vec<usize> { | ||
self.iter().map(|(v, _)| *v).collect() | ||
} | ||
|
||
/// Returns whether `self` is a constant | ||
fn is_constant(&self) -> bool { | ||
self.len() == 0 | ||
} | ||
|
||
/// Evaluates `self` at the given `point` in the field. | ||
fn evaluate<F: Field>(&self, point: &[F]) -> F { | ||
cfg_into_iter!(self) | ||
.map(|var| { | ||
let term = point.get(var.0).unwrap(); | ||
term.pow(&[var.1 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 Ord for SparseTerm { | ||
/// Sort by total degree. If total degree is equal then ordering | ||
/// is given by exponent weight in lower-numbered variables | ||
/// ie. `x_1 > x_2`, `x_1^2 > x_1 * x_2`, etc. | ||
fn cmp(&self, other: &Self) -> Ordering { | ||
if self.degree() != other.degree() { | ||
self.degree().cmp(&other.degree()) | ||
} else { | ||
// Iterate through all variables and return the corresponding ordering | ||
// if they differ in variable numbering or power | ||
for (cur, other) in self.iter().zip(other.iter()) { | ||
if other.0 == cur.0 { | ||
if cur.1 != other.1 { | ||
return (cur.1).cmp(&other.1); | ||
} | ||
} else { | ||
return (other.0).cmp(&cur.0); | ||
} | ||
} | ||
Ordering::Equal | ||
} | ||
} | ||
} |
Oops, something went wrong.