From 82837b2f77490a86fdad2fc1bd9771931fb81d04 Mon Sep 17 00:00:00 2001 From: Ben Hamlin Date: Wed, 15 Feb 2023 08:06:58 -0800 Subject: [PATCH] Multilinear extension evaluation speedup (#603) * Reduce # multiplications in dense ml extension eval * Reduce # multiplications in sparse ml extension eval * Eliminate extra vector allocation in precompute_eq * Add entry to changelog on mul reduction in eval functions --- CHANGELOG.md | 2 ++ poly/src/evaluations/multivariate/multilinear/dense.rs | 4 +++- poly/src/evaluations/multivariate/multilinear/sparse.rs | 9 ++++----- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a734c6005..a39633574 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Pending +- (`ark-poly`) Reduce the number of field multiplications performed by `SparseMultilinearExtension::evaluate` and `DenseMultilinearExtension::evaluate` + ### Breaking changes ### Features diff --git a/poly/src/evaluations/multivariate/multilinear/dense.rs b/poly/src/evaluations/multivariate/multilinear/dense.rs index d2efa8a8d..e4525899a 100644 --- a/poly/src/evaluations/multivariate/multilinear/dense.rs +++ b/poly/src/evaluations/multivariate/multilinear/dense.rs @@ -119,7 +119,9 @@ impl MultilinearExtension for DenseMultilinearExtension { for i in 1..dim + 1 { let r = partial_point[i - 1]; for b in 0..(1 << (nv - i)) { - poly[b] = poly[b << 1] * (F::one() - r) + poly[(b << 1) + 1] * r; + let left = poly[b << 1]; + let right = poly[(b << 1) + 1]; + poly[b] = left + r * (right - left); } } Self::from_evaluations_slice(nv - dim, &poly[..(1 << (nv - dim))]) diff --git a/poly/src/evaluations/multivariate/multilinear/sparse.rs b/poly/src/evaluations/multivariate/multilinear/sparse.rs index 68b4726d2..f4f8040ca 100644 --- a/poly/src/evaluations/multivariate/multilinear/sparse.rs +++ b/poly/src/evaluations/multivariate/multilinear/sparse.rs @@ -102,15 +102,14 @@ impl SparseMultilinearExtension { /// utility: precompute f(x) = eq(g,x) fn precompute_eq(g: &[F]) -> Vec { let dim = g.len(); - let mut dp = Vec::with_capacity(1 << dim); - dp.resize(1 << dim, F::zero()); + let mut dp = vec![F::zero(); 1 << dim]; dp[0] = F::one() - g[0]; dp[1] = g[0]; for i in 1..dim { - let dp_prev = dp[0..(1 << i)].to_vec(); for b in 0..(1 << i) { - dp[b] = dp_prev[b] * (F::one() - g[i]); - dp[b + (1 << i)] = dp_prev[b] * g[i]; + let prev = dp[b]; + dp[b + (1 << i)] = prev * g[i]; + dp[b] = prev - dp[b + (1 << i)]; } } dp