Skip to content

Commit faa2f88

Browse files
authored
Sparse poly implement poly (#117)
* Make SparsePolynomial implement Polynomial
1 parent d7ad758 commit faa2f88

File tree

7 files changed

+369
-53
lines changed

7 files changed

+369
-53
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
- #106 (ark-ff, ark-ec) Add `Zeroize` trait bound to `Field, ProjectiveGroup, AffineGroup` traits.
1515
- #108 (ark-ff) Add `extension_degree()` method to `Field`.
1616
- #110 (ark-ec) Change the trait bound on the scalar for `mul`, from (essentially) `Into<BigInt>` to `AsRef<[u64]>`
17+
- #117 (ark-poly) Make the univariate `SparsePolynomial` implement `Polynomial`. Make this change
18+
by replacing `sparse_poly.evaluate(pt)` to `sparse_poly.evaluate(&pt)`.
1719

1820
### Features
1921
- #20 (ark-poly) Add structs/traits for multivariate polynomials
@@ -32,6 +34,7 @@
3234
- #115 (ark-poly) Add parallel implementation to operations on `Evaluations`.
3335
- #115 (ark-ff) Add parallel implementation of `batch_inversion`.
3436
- #122 (ark-poly) Add infrastructure for benchmarking `FFT`s.
37+
3538
### Bug fixes
3639
- #36 (ark-ec) In Short-Weierstrass curves, include an infinity bit in `ToConstraintField`.
3740
- #107 (ark-serialize) Fix handling of `(de)serialize_uncompressed/unchecked` in various impls of `CanonicalSerialize/Deserialize`.

poly/src/domain/general.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ impl<F: FftField> Iterator for GeneralElements<F> {
137137

138138
#[cfg(test)]
139139
mod tests {
140+
use crate::polynomial::Polynomial;
140141
use crate::{EvaluationDomain, GeneralEvaluationDomain};
141142
use ark_ff::{test_rng, Zero};
142143
use ark_test_curves::bls12_381::Fr;
@@ -152,7 +153,7 @@ mod tests {
152153
for _ in 0..100 {
153154
let point = rng.gen();
154155
assert_eq!(
155-
z.evaluate(point),
156+
z.evaluate(&point),
156157
domain.evaluate_vanishing_polynomial(point)
157158
)
158159
}
@@ -164,7 +165,7 @@ mod tests {
164165
for _ in 0..100 {
165166
let point = rng.gen();
166167
assert_eq!(
167-
z.evaluate(point),
168+
z.evaluate(&point),
168169
domain.evaluate_vanishing_polynomial(point)
169170
)
170171
}
@@ -177,7 +178,7 @@ mod tests {
177178
let domain = GeneralEvaluationDomain::<Fr>::new(coeffs).unwrap();
178179
let z = domain.vanishing_polynomial();
179180
for point in domain.elements() {
180-
assert!(z.evaluate(point).is_zero())
181+
assert!(z.evaluate(&point).is_zero())
181182
}
182183
}
183184
}

poly/src/domain/mixed_radix.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ pub(crate) fn serial_mixed_radix_fft<T: DomainCoeff<F>, F: FftField>(
398398

399399
#[cfg(test)]
400400
mod tests {
401+
use crate::polynomial::Polynomial;
401402
use crate::{EvaluationDomain, MixedRadixEvaluationDomain};
402403
use ark_ff::{test_rng, Field, Zero};
403404
use ark_test_curves::mnt4_753::Fq as Fr;
@@ -410,9 +411,9 @@ mod tests {
410411
let domain = MixedRadixEvaluationDomain::<Fr>::new(coeffs).unwrap();
411412
let z = domain.vanishing_polynomial();
412413
for _ in 0..100 {
413-
let point = rng.gen();
414+
let point: Fr = rng.gen();
414415
assert_eq!(
415-
z.evaluate(point),
416+
z.evaluate(&point),
416417
domain.evaluate_vanishing_polynomial(point)
417418
)
418419
}
@@ -425,7 +426,7 @@ mod tests {
425426
let domain = MixedRadixEvaluationDomain::<Fr>::new(coeffs).unwrap();
426427
let z = domain.vanishing_polynomial();
427428
for point in domain.elements() {
428-
assert!(z.evaluate(point).is_zero())
429+
assert!(z.evaluate(&point).is_zero())
429430
}
430431
}
431432
}

poly/src/domain/radix2.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,14 @@ impl<F: FftField> EvaluationDomain<F> for Radix2EvaluationDomain<F> {
212212
}
213213
}
214214

215+
// This implements the Cooley-Turkey FFT, derived from libfqfft
216+
// The libfqfft implementation uses pseudocode from [CLRS 2n Ed, pp. 864].
215217
pub(crate) fn serial_radix2_fft<T: DomainCoeff<F>, F: FftField>(a: &mut [T], omega: F, log_n: u32) {
216218
let n =
217219
u32::try_from(a.len()).expect("cannot perform FFTs larger on vectors of len > (1 << 32)");
218220
assert_eq!(n, 1 << log_n);
219221

222+
// swap coefficients in place
220223
for k in 0..n {
221224
let rk = bitreverse(k, log_n);
222225
if k < rk {
@@ -225,11 +228,13 @@ pub(crate) fn serial_radix2_fft<T: DomainCoeff<F>, F: FftField>(a: &mut [T], ome
225228
}
226229

227230
let mut m = 1;
228-
for _ in 0..log_n {
231+
for _i in 1..=log_n {
232+
// w_m is 2^i-th root of unity
229233
let w_m = omega.pow(&[(n / (2 * m)) as u64]);
230234

231235
let mut k = 0;
232236
while k < n {
237+
// w = w_m^j at the start of every loop iteration
233238
let mut w = F::one();
234239
for j in 0..m {
235240
let mut t = a[(k + j + m) as usize];
@@ -251,6 +256,7 @@ pub(crate) fn serial_radix2_fft<T: DomainCoeff<F>, F: FftField>(a: &mut [T], ome
251256
#[cfg(test)]
252257
mod tests {
253258
use crate::domain::Vec;
259+
use crate::polynomial::Polynomial;
254260
use crate::{EvaluationDomain, Radix2EvaluationDomain};
255261
use ark_ff::{test_rng, Field, One, UniformRand, Zero};
256262
use ark_test_curves::bls12_381::Fr;
@@ -263,9 +269,9 @@ mod tests {
263269
let domain = Radix2EvaluationDomain::<Fr>::new(coeffs).unwrap();
264270
let z = domain.vanishing_polynomial();
265271
for _ in 0..100 {
266-
let point = rng.gen();
272+
let point: Fr = rng.gen();
267273
assert_eq!(
268-
z.evaluate(point),
274+
z.evaluate(&point),
269275
domain.evaluate_vanishing_polynomial(point)
270276
)
271277
}
@@ -278,7 +284,7 @@ mod tests {
278284
let domain = Radix2EvaluationDomain::<Fr>::new(coeffs).unwrap();
279285
let z = domain.vanishing_polynomial();
280286
for point in domain.elements() {
281-
assert!(z.evaluate(point).is_zero())
287+
assert!(z.evaluate(&point).is_zero())
282288
}
283289
}
284290
}

poly/src/polynomial/univariate/dense.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,23 @@ mod tests {
499499
assert_eq!(res1, -res2, "p2 - p1 = -(p1 - p2)");
500500
}
501501

502+
#[test]
503+
fn polynomial_additive_identity() {
504+
// Test adding polynomials with its negative equals 0
505+
let mut rng = test_rng();
506+
for degree in 0..70 {
507+
let poly = DensePolynomial::<Fr>::rand(degree, &mut rng);
508+
let neg = -poly.clone();
509+
assert!((poly + neg).is_zero());
510+
511+
// Test with SubAssign trait
512+
let poly = DensePolynomial::<Fr>::rand(degree, &mut rng);
513+
let mut result = poly.clone();
514+
result -= &poly;
515+
assert!(result.is_zero());
516+
}
517+
}
518+
502519
#[test]
503520
fn divide_polynomials_fixed() {
504521
let dividend = DensePolynomial::from_coefficients_slice(&[

poly/src/polynomial/univariate/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,11 @@ impl<'a, F: 'a + FftField> DenseOrSparsePolynomial<'a, F> {
145145
fn eval_over_domain_helper<D: EvaluationDomain<F>>(self, domain: D) -> Evaluations<F, D> {
146146
match self {
147147
SPolynomial(Cow::Borrowed(s)) => {
148-
let evals = domain.elements().map(|elem| s.evaluate(elem)).collect();
148+
let evals = domain.elements().map(|elem| s.evaluate(&elem)).collect();
149149
Evaluations::from_vec_and_domain(evals, domain)
150150
}
151151
SPolynomial(Cow::Owned(s)) => {
152-
let evals = domain.elements().map(|elem| s.evaluate(elem)).collect();
152+
let evals = domain.elements().map(|elem| s.evaluate(&elem)).collect();
153153
Evaluations::from_vec_and_domain(evals, domain)
154154
}
155155
DPolynomial(Cow::Borrowed(d)) => {

0 commit comments

Comments
 (0)