Skip to content

Commit c37fa3d

Browse files
committed
Merge branch 'master' into release-0.5-alpha
2 parents 5e538a8 + e107556 commit c37fa3d

File tree

11 files changed

+185
-41
lines changed

11 files changed

+185
-41
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- [\#772](https://github.com/arkworks-rs/algebra/pull/772) (`ark-ff`) Implementation of `mul` method for `BigInteger`.
66
- [\#794](https://github.com/arkworks-rs/algebra/pull/794) (`ark-ff`) Fix `wasm` compilation.
77
- [\#837](https://github.com/arkworks-rs/algebra/pull/837) (`ark-serialize`) Fix array deserialization panic.
8+
- [\#845](https://github.com/arkworks-rs/algebra/pull/845) (`Algebra`) Implementation of `mul` method for `DenseMultilinearExtension<F> * F`.
89

910
### Breaking changes
1011

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@ arrayvec = { version = "0.7", default-features = false }
5656
criterion = "0.5.0"
5757
educe = "0.6.0"
5858
digest = { version = "0.10", default-features = false }
59-
hashbrown = { version = "0.14", default-features = false, features = ["inline-more", "allocator-api2"] }
59+
hashbrown = { version = "0.15", default-features = false, features = ["inline-more", "allocator-api2"] }
6060
hex = "0.4"
6161
itertools = { version = "0.13", default-features = false }
62-
libtest-mimic = "0.7.0"
62+
libtest-mimic = "0.8.1"
6363
paste = "1.0"
6464
rayon = "1"
6565
serde = "1.0"

curves/bn254/src/curves/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ impl BnConfig for Config {
1919
/// `x` is positive.
2020
const X_IS_NEGATIVE: bool = false;
2121
const ATE_LOOP_COUNT: &'static [i8] = &[
22-
0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0,
23-
0, 1, 1, 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, 0, 0, 1, 1, 0,
24-
-1, 0, 0, 1, 0, 1, 1,
22+
0, 0, 0, 1, 0, 1, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, 0, 1, 0, -1, 0, 0, 0,
23+
0, -1, 0, 0, 1, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 1, 0, -1, 0, 0, 0, -1, 0,
24+
-1, 0, 0, 0, 1, 0, 1, 1,
2525
];
2626

2727
const TWIST_MUL_BY_Q_X: Fq2 = Fq2::new(

ff/src/fields/models/cubic_extension.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::{
22
fields::{Field, PrimeField},
3-
AdditiveGroup, LegendreSymbol, One, SqrtPrecomputation, ToConstraintField, UniformRand, Zero,
3+
AdditiveGroup, FftField, LegendreSymbol, One, SqrtPrecomputation, ToConstraintField,
4+
UniformRand, Zero,
45
};
56
use ark_serialize::{
67
CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
@@ -770,3 +771,28 @@ mod cube_ext_tests {
770771
}
771772
}
772773
}
774+
775+
impl<P: CubicExtConfig> FftField for CubicExtField<P>
776+
where
777+
P::BaseField: FftField,
778+
{
779+
const GENERATOR: Self = Self::new(
780+
P::BaseField::GENERATOR,
781+
P::BaseField::ZERO,
782+
P::BaseField::ZERO,
783+
);
784+
const TWO_ADICITY: u32 = P::BaseField::TWO_ADICITY;
785+
const TWO_ADIC_ROOT_OF_UNITY: Self = Self::new(
786+
P::BaseField::TWO_ADIC_ROOT_OF_UNITY,
787+
P::BaseField::ZERO,
788+
P::BaseField::ZERO,
789+
);
790+
const SMALL_SUBGROUP_BASE: Option<u32> = P::BaseField::SMALL_SUBGROUP_BASE;
791+
const SMALL_SUBGROUP_BASE_ADICITY: Option<u32> = P::BaseField::SMALL_SUBGROUP_BASE_ADICITY;
792+
const LARGE_SUBGROUP_ROOT_OF_UNITY: Option<Self> =
793+
if let Some(x) = P::BaseField::LARGE_SUBGROUP_ROOT_OF_UNITY {
794+
Some(Self::new(x, P::BaseField::ZERO, P::BaseField::ZERO))
795+
} else {
796+
None
797+
};
798+
}

ff/src/fields/models/fp3.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ impl<P: Fp3Config> CubicExtConfig for Fp3ConfigWrapper<P> {
3939
type FrobCoeff = P::Fp;
4040

4141
const DEGREE_OVER_BASE_PRIME_FIELD: usize = 3;
42-
4342
const NONRESIDUE: Self::BaseField = P::NONRESIDUE;
4443

4544
const SQRT_PRECOMP: Option<SqrtPrecomputation<CubicExtField<Self>>> =

ff/src/fields/models/quadratic_extension.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
biginteger::BigInteger,
33
fields::{Field, LegendreSymbol, PrimeField},
4-
AdditiveGroup, One, SqrtPrecomputation, ToConstraintField, UniformRand, Zero,
4+
AdditiveGroup, FftField, One, SqrtPrecomputation, ToConstraintField, UniformRand, Zero,
55
};
66
use ark_serialize::{
77
CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
@@ -825,3 +825,21 @@ mod quad_ext_tests {
825825
}
826826
}
827827
}
828+
829+
impl<P: QuadExtConfig> FftField for QuadExtField<P>
830+
where
831+
P::BaseField: FftField,
832+
{
833+
const GENERATOR: Self = Self::new(P::BaseField::GENERATOR, P::BaseField::ZERO);
834+
const TWO_ADICITY: u32 = P::BaseField::TWO_ADICITY;
835+
const TWO_ADIC_ROOT_OF_UNITY: Self =
836+
Self::new(P::BaseField::TWO_ADIC_ROOT_OF_UNITY, P::BaseField::ZERO);
837+
const SMALL_SUBGROUP_BASE: Option<u32> = P::BaseField::SMALL_SUBGROUP_BASE;
838+
const SMALL_SUBGROUP_BASE_ADICITY: Option<u32> = P::BaseField::SMALL_SUBGROUP_BASE_ADICITY;
839+
const LARGE_SUBGROUP_ROOT_OF_UNITY: Option<Self> =
840+
if let Some(x) = P::BaseField::LARGE_SUBGROUP_ROOT_OF_UNITY {
841+
Some(Self::new(x, P::BaseField::ZERO))
842+
} else {
843+
None
844+
};
845+
}

poly/benches/fft.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use criterion::{criterion_group, criterion_main, Bencher, BenchmarkId, Criterion
1212

1313
// degree bounds to benchmark on
1414
// e.g. degree bound of 2^{15}, means we do an FFT for a degree (2^{15} - 1) polynomial
15-
const BENCHMARK_MIN_DEGREE: usize = 1 << 15;
15+
const BENCHMARK_MIN_DEGREE: usize = 1 << 4;
1616
const BENCHMARK_MAX_DEGREE_BLS12_381: usize = 1 << 22;
1717
const BENCHMARK_MAX_DEGREE_MNT6_753: usize = 1 << 17;
1818
const BENCHMARK_LOG_INTERVAL_DEGREE: usize = 1;

poly/src/domain/radix2/fft.rs

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -224,23 +224,33 @@ impl<F: FftField> Radix2EvaluationDomain<F> {
224224
max_threads: usize,
225225
gap: usize,
226226
) {
227-
cfg_chunks_mut!(xi, chunk_size).for_each(|cxi| {
228-
let (lo, hi) = cxi.split_at_mut(gap);
229-
// If the chunk is sufficiently big that parallelism helps,
230-
// we parallelize the butterfly operation within the chunk.
231-
232-
if gap > MIN_GAP_SIZE_FOR_PARALLELISATION && num_chunks < max_threads {
233-
cfg_iter_mut!(lo)
234-
.zip(hi)
235-
.zip(cfg_iter!(roots).step_by(step))
236-
.for_each(g);
237-
} else {
227+
if xi.len() <= MIN_INPUT_SIZE_FOR_PARALLELIZATION {
228+
xi.chunks_mut(chunk_size).for_each(|cxi| {
229+
let (lo, hi) = cxi.split_at_mut(gap);
238230
lo.iter_mut()
239231
.zip(hi)
240232
.zip(roots.iter().step_by(step))
241233
.for_each(g);
242-
}
243-
});
234+
});
235+
} else {
236+
cfg_chunks_mut!(xi, chunk_size).for_each(|cxi| {
237+
let (lo, hi) = cxi.split_at_mut(gap);
238+
// If the chunk is sufficiently big that parallelism helps,
239+
// we parallelize the butterfly operation within the chunk.
240+
241+
if gap > MIN_GAP_SIZE_FOR_PARALLELIZATION && num_chunks < max_threads {
242+
cfg_iter_mut!(lo)
243+
.zip(hi)
244+
.zip(cfg_iter!(roots).step_by(step))
245+
.for_each(g);
246+
} else {
247+
lo.iter_mut()
248+
.zip(hi)
249+
.zip(roots.iter().step_by(step))
250+
.for_each(g);
251+
}
252+
});
253+
}
244254
}
245255

246256
fn io_helper<T: DomainCoeff<F>>(&self, xi: &mut [T], root: F) {
@@ -349,7 +359,11 @@ const MIN_NUM_CHUNKS_FOR_COMPACTION: usize = 1 << 7;
349359

350360
/// The minimum size of a chunk at which parallelization of `butterfly`s is
351361
/// beneficial. This value was chosen empirically.
352-
const MIN_GAP_SIZE_FOR_PARALLELISATION: usize = 1 << 10;
362+
const MIN_GAP_SIZE_FOR_PARALLELIZATION: usize = 1 << 10;
363+
364+
/// The minimum size of a chunk at which parallelization of `butterfly`s is
365+
/// beneficial. This value was chosen empirically.
366+
const MIN_INPUT_SIZE_FOR_PARALLELIZATION: usize = 1 << 10;
353367

354368
// minimum size at which to parallelize.
355369
#[cfg(feature = "parallel")]

poly/src/evaluations/multivariate/multilinear/dense.rs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use ark_std::{
1111
fmt::Formatter,
1212
iter::IntoIterator,
1313
log2,
14-
ops::{Add, AddAssign, Index, Neg, Sub, SubAssign},
14+
ops::{Add, AddAssign, Index, Mul, MulAssign, Neg, Sub, SubAssign},
1515
rand::Rng,
1616
slice::{Iter, IterMut},
1717
vec::*,
@@ -331,6 +331,44 @@ impl<'a, F: Field> SubAssign<&'a DenseMultilinearExtension<F>> for DenseMultilin
331331
}
332332
}
333333

334+
impl<F: Field> Mul<F> for DenseMultilinearExtension<F> {
335+
type Output = DenseMultilinearExtension<F>;
336+
337+
fn mul(self, scalar: F) -> Self::Output {
338+
&self * &scalar
339+
}
340+
}
341+
342+
impl<'a, 'b, F: Field> Mul<&'a F> for &'b DenseMultilinearExtension<F> {
343+
type Output = DenseMultilinearExtension<F>;
344+
345+
fn mul(self, scalar: &'a F) -> Self::Output {
346+
if scalar.is_zero() {
347+
return DenseMultilinearExtension::zero();
348+
} else if scalar.is_one() {
349+
return self.clone();
350+
}
351+
let result: Vec<F> = self.evaluations.iter().map(|&x| x * scalar).collect();
352+
353+
DenseMultilinearExtension {
354+
num_vars: self.num_vars,
355+
evaluations: result,
356+
}
357+
}
358+
}
359+
360+
impl<F: Field> MulAssign<F> for DenseMultilinearExtension<F> {
361+
fn mul_assign(&mut self, scalar: F) {
362+
*self = &*self * &scalar
363+
}
364+
}
365+
366+
impl<'a, F: Field> MulAssign<&'a F> for DenseMultilinearExtension<F> {
367+
fn mul_assign(&mut self, scalar: &'a F) {
368+
*self = &*self * scalar
369+
}
370+
}
371+
334372
impl<F: Field> fmt::Debug for DenseMultilinearExtension<F> {
335373
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
336374
write!(f, "DenseML(nv = {}, evaluations = [", self.num_vars)?;
@@ -394,7 +432,7 @@ impl<F: Field> Polynomial<F> for DenseMultilinearExtension<F> {
394432
#[cfg(test)]
395433
mod tests {
396434
use crate::{DenseMultilinearExtension, MultilinearExtension, Polynomial};
397-
use ark_ff::{Field, Zero};
435+
use ark_ff::{Field, One, Zero};
398436
use ark_std::{ops::Neg, test_rng, vec::*, UniformRand};
399437
use ark_test_curves::bls12_381::Fr;
400438

@@ -471,6 +509,7 @@ mod tests {
471509
const NV: usize = 10;
472510
let mut rng = test_rng();
473511
for _ in 0..20 {
512+
let scalar = Fr::rand(&mut rng);
474513
let point: Vec<_> = (0..NV).map(|_| Fr::rand(&mut rng)).collect();
475514
let poly1 = DenseMultilinearExtension::rand(NV, &mut rng);
476515
let poly2 = DenseMultilinearExtension::rand(NV, &mut rng);
@@ -482,6 +521,8 @@ mod tests {
482521
assert_eq!((&poly1 - &poly2).evaluate(&point), v1 - v2);
483522
// test negate
484523
assert_eq!(poly1.clone().neg().evaluate(&point), -v1);
524+
// test mul poly by scalar
525+
assert_eq!((&poly1 * &scalar).evaluate(&point), v1 * scalar);
485526
// test add assign
486527
{
487528
let mut poly1 = poly1.clone();
@@ -515,6 +556,16 @@ mod tests {
515556
assert_eq!(zero.evaluate(&point), scalar * v1);
516557
}
517558
}
559+
// test mul_assign for poly * scalar
560+
{
561+
let mut poly1_cloned = poly1.clone();
562+
poly1_cloned *= Fr::one();
563+
assert_eq!(poly1_cloned.evaluate(&point), v1);
564+
poly1_cloned *= scalar;
565+
assert_eq!(poly1_cloned.evaluate(&point), v1 * scalar);
566+
poly1_cloned *= Fr::zero();
567+
assert_eq!(poly1_cloned, DenseMultilinearExtension::zero());
568+
}
518569
}
519570
}
520571

poly/src/polynomial/univariate/dense.rs

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,12 @@ impl<F: FftField> DensePolynomial<F> {
170170
pub fn divide_by_vanishing_poly<D: EvaluationDomain<F>>(
171171
&self,
172172
domain: D,
173-
) -> Option<(DensePolynomial<F>, DensePolynomial<F>)> {
173+
) -> (DensePolynomial<F>, DensePolynomial<F>) {
174174
let domain_size = domain.size();
175175

176176
if self.coeffs.len() < domain_size {
177177
// If degree(self) < len(Domain), then the quotient is zero, and the entire polynomial is the remainder
178-
Some((DensePolynomial::<F>::zero(), self.clone()))
178+
(DensePolynomial::<F>::zero(), self.clone())
179179
} else {
180180
// Compute the quotient
181181
//
@@ -211,7 +211,7 @@ impl<F: FftField> DensePolynomial<F> {
211211

212212
let quotient = DensePolynomial::<F>::from_coefficients_vec(quotient_vec);
213213
let remainder = DensePolynomial::<F>::from_coefficients_vec(remainder_vec);
214-
Some((quotient, remainder))
214+
(quotient, remainder)
215215
}
216216
}
217217
}
@@ -285,14 +285,6 @@ impl<F: Field> DerefMut for DensePolynomial<F> {
285285
}
286286
}
287287

288-
impl<F: Field> Add for DensePolynomial<F> {
289-
type Output = DensePolynomial<F>;
290-
291-
fn add(self, other: DensePolynomial<F>) -> Self {
292-
&self + &other
293-
}
294-
}
295-
296288
impl<'a, 'b, F: Field> Add<&'a DensePolynomial<F>> for &'b DensePolynomial<F> {
297289
type Output = DensePolynomial<F>;
298290

@@ -601,6 +593,15 @@ impl<'b, F: Field> Mul<F> for &'b DensePolynomial<F> {
601593
}
602594
}
603595

596+
impl<F: Field> Mul<F> for DensePolynomial<F> {
597+
type Output = DensePolynomial<F>;
598+
599+
#[inline]
600+
fn mul(self, elem: F) -> DensePolynomial<F> {
601+
&self * elem
602+
}
603+
}
604+
604605
/// Performs O(nlogn) multiplication of polynomials if F is smooth.
605606
impl<'a, 'b, F: FftField> Mul<&'a DensePolynomial<F>> for &'b DensePolynomial<F> {
606607
type Output = DensePolynomial<F>;
@@ -620,6 +621,37 @@ impl<'a, 'b, F: FftField> Mul<&'a DensePolynomial<F>> for &'b DensePolynomial<F>
620621
}
621622
}
622623

624+
macro_rules! impl_op {
625+
($trait:ident, $method:ident, $field_bound:ident) => {
626+
impl<F: $field_bound> $trait<DensePolynomial<F>> for DensePolynomial<F> {
627+
type Output = DensePolynomial<F>;
628+
629+
#[inline]
630+
fn $method(self, other: DensePolynomial<F>) -> DensePolynomial<F> {
631+
(&self).$method(&other)
632+
}
633+
}
634+
635+
impl<'a, F: $field_bound> $trait<&'a DensePolynomial<F>> for DensePolynomial<F> {
636+
type Output = DensePolynomial<F>;
637+
638+
#[inline]
639+
fn $method(self, other: &'a DensePolynomial<F>) -> DensePolynomial<F> {
640+
(&self).$method(other)
641+
}
642+
}
643+
644+
impl<'a, F: $field_bound> $trait<DensePolynomial<F>> for &'a DensePolynomial<F> {
645+
type Output = DensePolynomial<F>;
646+
647+
#[inline]
648+
fn $method(self, other: DensePolynomial<F>) -> DensePolynomial<F> {
649+
self.$method(&other)
650+
}
651+
}
652+
};
653+
}
654+
623655
impl<F: Field> Zero for DensePolynomial<F> {
624656
/// Returns the zero polynomial.
625657
fn zero() -> Self {
@@ -632,6 +664,11 @@ impl<F: Field> Zero for DensePolynomial<F> {
632664
}
633665
}
634666

667+
impl_op!(Add, add, Field);
668+
impl_op!(Sub, sub, Field);
669+
impl_op!(Mul, mul, FftField);
670+
impl_op!(Div, div, Field);
671+
635672
#[cfg(test)]
636673
mod tests {
637674
use crate::{polynomial::univariate::*, GeneralEvaluationDomain};
@@ -899,7 +936,7 @@ mod tests {
899936
let domain = GeneralEvaluationDomain::new(1 << size).unwrap();
900937
for degree in 0..12 {
901938
let p = DensePolynomial::<Fr>::rand(degree * 100, rng);
902-
let (quotient, remainder) = p.divide_by_vanishing_poly(domain).unwrap();
939+
let (quotient, remainder) = p.divide_by_vanishing_poly(domain);
903940
let p_recovered = quotient.mul_by_vanishing_poly(domain) + remainder;
904941
assert_eq!(p, p_recovered);
905942
}

0 commit comments

Comments
 (0)