From 1cccd62f1123c02c482ae353264f2c00c8b197c2 Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 15 Jan 2025 06:41:50 +0100 Subject: [PATCH 1/4] Update arithmetic.rs --- halo2_proofs/src/arithmetic.rs | 57 ++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/halo2_proofs/src/arithmetic.rs b/halo2_proofs/src/arithmetic.rs index 76a40e71b..99aafe1d2 100644 --- a/halo2_proofs/src/arithmetic.rs +++ b/halo2_proofs/src/arithmetic.rs @@ -110,16 +110,34 @@ pub fn eval_polynomial(poly: &[F], point: F) -> F { /// This computes the inner product of two vectors `a` and `b`. /// /// This function will panic if the two vectors are not the same size. +/// For vectors smaller than 32 elements, it uses sequential computation for better performance. +/// For larger vectors, it switches to parallel computation using multiple threads. pub fn compute_inner_product(a: &[F], b: &[F]) -> F { - // TODO: parallelize? assert_eq!(a.len(), b.len()); - - let mut acc = F::ZERO; - for (a, b) in a.iter().zip(b.iter()) { - acc += (*a) * (*b); + + if a.len() < 32 { + // Use sequential computation for small vectors + let mut acc = F::ZERO; + for (a, b) in a.iter().zip(b.iter()) { + acc += (*a) * (*b); + } + return acc; } - acc + // Use parallel computation for large vectors + let mut products = vec![F::ZERO; a.len()]; + parallelize(&mut products, |products, chunk_size| { + for (((a, b), product), i) in a + .chunks(chunk_size) + .zip(b.chunks(chunk_size)) + .zip(products) + .zip(0..) + { + *product = a.iter().zip(b.iter()).fold(F::ZERO, |acc, (a, b)| acc + (*a) * (*b)); + } + }); + + products.iter().fold(F::ZERO, |acc, product| acc + *product) } /// Divides polynomial `a` in `X` by `X - b` with @@ -328,3 +346,30 @@ fn test_lagrange_interpolate() { } } } + +#[cfg(test)] +mod tests { + use super::*; + use rand_core::OsRng; + + #[test] + fn test_compute_inner_product() { + let rng = OsRng; + + // Test small vectors (sequential) + let a_small: Vec = (0..16).map(|_| Fp::random(rng)).collect(); + let b_small: Vec = (0..16).map(|_| Fp::random(rng)).collect(); + let result_small = compute_inner_product(&a_small, &b_small); + let expected_small = a_small.iter().zip(b_small.iter()) + .fold(Fp::ZERO, |acc, (a, b)| acc + (*a) * (*b)); + assert_eq!(result_small, expected_small); + + // Test large vectors (parallel) + let a_large: Vec = (0..64).map(|_| Fp::random(rng)).collect(); + let b_large: Vec = (0..64).map(|_| Fp::random(rng)).collect(); + let result_large = compute_inner_product(&a_large, &b_large); + let expected_large = a_large.iter().zip(b_large.iter()) + .fold(Fp::ZERO, |acc, (a, b)| acc + (*a) * (*b)); + assert_eq!(result_large, expected_large); + } +} From 39ff2d385068707d4dd7241a09bac133ff62846c Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 15 Jan 2025 10:06:11 +0100 Subject: [PATCH 2/4] Update arithmetic.rs From ec627e2a644ee888f47346cd86c695381d48174a Mon Sep 17 00:00:00 2001 From: crStiv Date: Thu, 16 Jan 2025 02:03:50 +0100 Subject: [PATCH 3/4] Update arithmetic.rs --- halo2_proofs/src/arithmetic.rs | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/halo2_proofs/src/arithmetic.rs b/halo2_proofs/src/arithmetic.rs index 99aafe1d2..f7a52cbd4 100644 --- a/halo2_proofs/src/arithmetic.rs +++ b/halo2_proofs/src/arithmetic.rs @@ -110,8 +110,6 @@ pub fn eval_polynomial(poly: &[F], point: F) -> F { /// This computes the inner product of two vectors `a` and `b`. /// /// This function will panic if the two vectors are not the same size. -/// For vectors smaller than 32 elements, it uses sequential computation for better performance. -/// For larger vectors, it switches to parallel computation using multiple threads. pub fn compute_inner_product(a: &[F], b: &[F]) -> F { assert_eq!(a.len(), b.len()); @@ -124,20 +122,9 @@ pub fn compute_inner_product(a: &[F], b: &[F]) -> F { return acc; } - // Use parallel computation for large vectors - let mut products = vec![F::ZERO; a.len()]; - parallelize(&mut products, |products, chunk_size| { - for (((a, b), product), i) in a - .chunks(chunk_size) - .zip(b.chunks(chunk_size)) - .zip(products) - .zip(0..) - { - *product = a.iter().zip(b.iter()).fold(F::ZERO, |acc, (a, b)| acc + (*a) * (*b)); - } - }); - - products.iter().fold(F::ZERO, |acc, product| acc + *product) + // Use parallel computation with rayon + use rayon::prelude::*; + a.par_iter().zip(b.par_iter()).map(|(a, b)| (*a) * (*b)).sum() } /// Divides polynomial `a` in `X` by `X - b` with From 5b8f36b615bd57510abb204c2b60407a2a2cefd6 Mon Sep 17 00:00:00 2001 From: crStiv Date: Thu, 16 Jan 2025 21:51:45 +0100 Subject: [PATCH 4/4] Update arithmetic.rs --- halo2_proofs/src/arithmetic.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/halo2_proofs/src/arithmetic.rs b/halo2_proofs/src/arithmetic.rs index f7a52cbd4..d38788548 100644 --- a/halo2_proofs/src/arithmetic.rs +++ b/halo2_proofs/src/arithmetic.rs @@ -8,6 +8,7 @@ use group::{ prime::PrimeCurveAffine, Curve, GroupOpsOwned, ScalarMulOwned, }; +use rayon::prelude::*; use halo2curves::msm::msm_best; pub use halo2curves::{CurveAffine, CurveExt}; @@ -110,6 +111,8 @@ pub fn eval_polynomial(poly: &[F], point: F) -> F { /// This computes the inner product of two vectors `a` and `b`. /// /// This function will panic if the two vectors are not the same size. +/// For vectors smaller than 32 elements, it uses sequential computation for better performance. +/// For larger vectors, it switches to parallel computation. pub fn compute_inner_product(a: &[F], b: &[F]) -> F { assert_eq!(a.len(), b.len()); @@ -122,9 +125,12 @@ pub fn compute_inner_product(a: &[F], b: &[F]) -> F { return acc; } - // Use parallel computation with rayon - use rayon::prelude::*; - a.par_iter().zip(b.par_iter()).map(|(a, b)| (*a) * (*b)).sum() + // Use parallel computation + let mut result = F::ZERO; + parallelize(&mut [result], |results, _| { + results[0] = a.iter().zip(b.iter()).fold(F::ZERO, |acc, (a, b)| acc + (*a) * (*b)); + }); + result } /// Divides polynomial `a` in `X` by `X - b` with