Skip to content

Commit

Permalink
Restructure polynomial/
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanleh committed Sep 20, 2020
1 parent d685507 commit d9bc3c9
Show file tree
Hide file tree
Showing 12 changed files with 308 additions and 312 deletions.
2 changes: 1 addition & 1 deletion ff-fft/src/domain/general.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ impl<F: FftField> EvaluationDomain<F> for GeneralEvaluationDomain<F> {
}

#[inline]
fn vanishing_polynomial(&self) -> crate::SparseUniPolynomial<F> {
fn vanishing_polynomial(&self) -> crate::univariate::SparsePolynomial<F> {
match self {
GeneralEvaluationDomain::Radix2(domain) => domain.vanishing_polynomial(),
GeneralEvaluationDomain::MixedRadix(domain) => domain.vanishing_polynomial(),
Expand Down
4 changes: 2 additions & 2 deletions ff-fft/src/domain/mixed_radix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,9 @@ impl<F: FftField> EvaluationDomain<F> for MixedRadixEvaluationDomain<F> {
}
}

fn vanishing_polynomial(&self) -> crate::SparseUniPolynomial<F> {
fn vanishing_polynomial(&self) -> crate::univariate::SparsePolynomial<F> {
let coeffs = vec![(0, -F::one()), (self.size(), F::one())];
crate::SparseUniPolynomial::from_coefficients_vec(coeffs)
crate::univariate::SparsePolynomial::from_coefficients_vec(coeffs)
}

/// This evaluates the vanishing polynomial for this domain at tau.
Expand Down
2 changes: 1 addition & 1 deletion ff-fft/src/domain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ pub trait EvaluationDomain<F: FftField>:
fn evaluate_all_lagrange_coefficients(&self, tau: F) -> Vec<F>;

/// Return the sparse vanishing polynomial.
fn vanishing_polynomial(&self) -> crate::SparseUniPolynomial<F>;
fn vanishing_polynomial(&self) -> crate::univariate::SparsePolynomial<F>;

/// This evaluates the vanishing polynomial for this domain at tau.
fn evaluate_vanishing_polynomial(&self, tau: F) -> F;
Expand Down
4 changes: 2 additions & 2 deletions ff-fft/src/domain/radix2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,9 @@ impl<F: FftField> EvaluationDomain<F> for Radix2EvaluationDomain<F> {
}
}

fn vanishing_polynomial(&self) -> crate::SparseUniPolynomial<F> {
fn vanishing_polynomial(&self) -> crate::univariate::SparsePolynomial<F> {
let coeffs = vec![(0, -F::one()), (self.size(), F::one())];
crate::SparseUniPolynomial::from_coefficients_vec(coeffs)
crate::univariate::SparsePolynomial::from_coefficients_vec(coeffs)
}

/// This evaluates the vanishing polynomial for this domain at tau.
Expand Down
10 changes: 5 additions & 5 deletions ff-fft/src/evaluations.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! A polynomial represented in evaluations form.
use crate::{DenseUniPolynomial, EvaluationDomain, GeneralEvaluationDomain, Vec};
use crate::{univariate::DensePolynomial, EvaluationDomain, GeneralEvaluationDomain, Vec};
use algebra_core::FftField;
use core::ops::{Add, AddAssign, Div, DivAssign, Index, Mul, MulAssign, Sub, SubAssign};

Expand All @@ -20,15 +20,15 @@ impl<F: FftField, D: EvaluationDomain<F>> Evaluations<F, D> {
}

/// Interpolate a polynomial from a list of evaluations
pub fn interpolate_by_ref(&self) -> DenseUniPolynomial<F> {
DenseUniPolynomial::from_coefficients_vec(self.domain.ifft(&self.evals))
pub fn interpolate_by_ref(&self) -> DensePolynomial<F> {
DensePolynomial::from_coefficients_vec(self.domain.ifft(&self.evals))
}

/// Interpolate a polynomial from a list of evaluations
pub fn interpolate(self) -> DenseUniPolynomial<F> {
pub fn interpolate(self) -> DensePolynomial<F> {
let Self { mut evals, domain } = self;
domain.ifft_in_place(&mut evals);
DenseUniPolynomial::from_coefficients_vec(evals)
DensePolynomial::from_coefficients_vec(evals)
}
}

Expand Down
5 changes: 1 addition & 4 deletions ff-fft/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,7 @@ pub use domain::{
EvaluationDomain, GeneralEvaluationDomain, MixedRadixEvaluationDomain, Radix2EvaluationDomain,
};
pub use evaluations::Evaluations;
pub use polynomial::{
DenseOrSparseUniPolynomial, DenseUniPolynomial, PolyVars, SparseMultiPolynomial,
SparseUniPolynomial,
};
pub use polynomial::{multivariate, univariate};

#[cfg(test)]
mod test;
172 changes: 3 additions & 169 deletions ff-fft/src/polynomial/mod.rs
Original file line number Diff line number Diff line change
@@ -1,170 +1,4 @@
//! Work with sparse and dense polynomials.
//! Modules for working with univariate or multivariate polynomials.
use crate::{Cow, EvaluationDomain, Evaluations, Vec};
use algebra_core::{FftField, Field};
use core::convert::TryInto;
use DenseOrSparseUniPolynomial::*;

mod multi_sparse;
mod uni_dense;
mod uni_sparse;

pub use multi_sparse::PolyVars;
pub use multi_sparse::SparseMultiPolynomial;
pub use uni_dense::DenseUniPolynomial;
pub use uni_sparse::SparseUniPolynomial;

/// Represents either a sparse polynomial or a dense one.
#[derive(Clone)]
pub enum DenseOrSparseUniPolynomial<'a, F: 'a + Field> {
/// Represents the case where `self` is a sparse polynomial
SPolynomial(Cow<'a, SparseUniPolynomial<F>>),
/// Represents the case where `self` is a dense polynomial
DPolynomial(Cow<'a, DenseUniPolynomial<F>>),
}

impl<'a, F: 'a + Field> From<DenseUniPolynomial<F>> for DenseOrSparseUniPolynomial<'a, F> {
fn from(other: DenseUniPolynomial<F>) -> Self {
DPolynomial(Cow::Owned(other))
}
}

impl<'a, F: 'a + Field> From<&'a DenseUniPolynomial<F>> for DenseOrSparseUniPolynomial<'a, F> {
fn from(other: &'a DenseUniPolynomial<F>) -> Self {
DPolynomial(Cow::Borrowed(other))
}
}

impl<'a, F: 'a + Field> From<SparseUniPolynomial<F>> for DenseOrSparseUniPolynomial<'a, F> {
fn from(other: SparseUniPolynomial<F>) -> Self {
SPolynomial(Cow::Owned(other))
}
}

impl<'a, F: Field> From<&'a SparseUniPolynomial<F>> for DenseOrSparseUniPolynomial<'a, F> {
fn from(other: &'a SparseUniPolynomial<F>) -> Self {
SPolynomial(Cow::Borrowed(other))
}
}

impl<'a, F: Field> Into<DenseUniPolynomial<F>> for DenseOrSparseUniPolynomial<'a, F> {
fn into(self) -> DenseUniPolynomial<F> {
match self {
DPolynomial(p) => p.into_owned(),
SPolynomial(p) => p.into_owned().into(),
}
}
}

impl<'a, F: 'a + Field> TryInto<SparseUniPolynomial<F>> for DenseOrSparseUniPolynomial<'a, F> {
type Error = ();

fn try_into(self) -> Result<SparseUniPolynomial<F>, ()> {
match self {
SPolynomial(p) => Ok(p.into_owned()),
_ => Err(()),
}
}
}

impl<'a, F: Field> DenseOrSparseUniPolynomial<'a, F> {
/// Checks if the given polynomial is zero.
pub fn is_zero(&self) -> bool {
match self {
SPolynomial(s) => s.is_zero(),
DPolynomial(d) => d.is_zero(),
}
}

/// Return the degree of `self.
pub fn degree(&self) -> usize {
match self {
SPolynomial(s) => s.degree(),
DPolynomial(d) => d.degree(),
}
}

#[inline]
fn leading_coefficient(&self) -> Option<&F> {
match self {
SPolynomial(p) => p.last().map(|(_, c)| c),
DPolynomial(p) => p.last(),
}
}

#[inline]
fn iter_with_index(&self) -> Vec<(usize, F)> {
match self {
SPolynomial(p) => p.to_vec(),
DPolynomial(p) => p.iter().cloned().enumerate().collect(),
}
}

/// Divide self by another (sparse or dense) polynomial, and returns the
/// quotient and remainder.
pub fn divide_with_q_and_r(
&self,
divisor: &Self,
) -> Option<(DenseUniPolynomial<F>, DenseUniPolynomial<F>)> {
if self.is_zero() {
Some((DenseUniPolynomial::zero(), DenseUniPolynomial::zero()))
} else if divisor.is_zero() {
panic!("Dividing by zero polynomial")
} else if self.degree() < divisor.degree() {
Some((DenseUniPolynomial::zero(), self.clone().into()))
} else {
// Now we know that self.degree() >= divisor.degree();
let mut quotient = vec![F::zero(); self.degree() - divisor.degree() + 1];
let mut remainder: DenseUniPolynomial<F> = self.clone().into();
// Can unwrap here because we know self is not zero.
let divisor_leading_inv = divisor.leading_coefficient().unwrap().inverse().unwrap();
while !remainder.is_zero() && remainder.degree() >= divisor.degree() {
let cur_q_coeff = *remainder.coeffs.last().unwrap() * &divisor_leading_inv;
let cur_q_degree = remainder.degree() - divisor.degree();
quotient[cur_q_degree] = cur_q_coeff;

for (i, div_coeff) in divisor.iter_with_index() {
remainder[cur_q_degree + i] -= &(cur_q_coeff * &div_coeff);
}
while let Some(true) = remainder.coeffs.last().map(|c| c.is_zero()) {
remainder.coeffs.pop();
}
}
Some((
DenseUniPolynomial::from_coefficients_vec(quotient),
remainder,
))
}
}
}
impl<'a, F: 'a + FftField> DenseOrSparseUniPolynomial<'a, F> {
/// Construct `Evaluations` by evaluating a polynomial over the domain
/// `domain`.
pub fn evaluate_over_domain<D: EvaluationDomain<F>>(
poly: impl Into<Self>,
domain: D,
) -> Evaluations<F, D> {
let poly = poly.into();
poly.eval_over_domain_helper(domain)
}

fn eval_over_domain_helper<D: EvaluationDomain<F>>(self, domain: D) -> Evaluations<F, D> {
match self {
SPolynomial(Cow::Borrowed(s)) => {
let evals = domain.elements().map(|elem| s.evaluate(elem)).collect();
Evaluations::from_vec_and_domain(evals, domain)
}
SPolynomial(Cow::Owned(s)) => {
let evals = domain.elements().map(|elem| s.evaluate(elem)).collect();
Evaluations::from_vec_and_domain(evals, domain)
}
DPolynomial(Cow::Borrowed(d)) => {
Evaluations::from_vec_and_domain(domain.fft(&d.coeffs), domain)
}
DPolynomial(Cow::Owned(mut d)) => {
domain.fft_in_place(&mut d.coeffs);
Evaluations::from_vec_and_domain(d.coeffs, domain)
}
}
}
}
pub mod multivariate;
pub mod univariate;
6 changes: 6 additions & 0 deletions ff-fft/src/polynomial/multivariate/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//! Work with multivariate polynomials.
mod sparse;

pub use sparse::PolyVars;
pub use sparse::SparsePolynomial;
Loading

0 comments on commit d9bc3c9

Please sign in to comment.