From d1799aeccb328582fabed25811e756bf0453216c Mon Sep 17 00:00:00 2001 From: Innokentii Sennovskii Date: Wed, 13 Mar 2024 14:21:30 +0000 Subject: [PATCH] feat: Parallelize linearly dependent contribution in PG (#4742) Closes https://github.com/AztecProtocol/barretenberg/issues/856. Changes accumulating the linearly dependent contribution to be non-serial in protogalaxy, by incorporating its accumulation in the parallel loop --- .../protogalaxy/protogalaxy.test.cpp | 18 +++--- .../protogalaxy/protogalaxy_prover.hpp | 60 +++++++++++-------- .../protogalaxy_recursive_verifier.test.cpp | 13 +--- 3 files changed, 47 insertions(+), 44 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp index db3c0ff3ff9..c8c9c76f18f 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp @@ -41,7 +41,7 @@ template class ProtoGalaxyTests : public testing::Test { static void construct_circuit(Builder& builder) { if constexpr (IsGoblinFlavor) { - GoblinMockCircuits::construct_arithmetic_circuit(builder); + GoblinMockCircuits::construct_arithmetic_circuit(builder, 200); GoblinMockCircuits::construct_goblin_ecc_op_circuit(builder); } else { @@ -109,8 +109,8 @@ template class ProtoGalaxyTests : public testing::Test { /** * @brief For a valid circuit, ensures that computing the value of the full UH/UGH relation at each row in its - * execution trace (with the contribution of the linearly dependent one added tot he first row, in case of Goblin) - * will be 0. + * execution trace (with the contribution of the linearly dependent one added tot he first row, in case of + * Goblin) will be 0. * */ static void test_full_honk_evaluations_valid_circuit() @@ -143,8 +143,8 @@ template class ProtoGalaxyTests : public testing::Test { } /** - * @brief Check the coefficients of the perturbator computed from dummy \vec{β}, \vec{δ} and f_i(ω) will be the same - * as if computed manually. + * @brief Check the coefficients of the perturbator computed from dummy \vec{β}, \vec{δ} and f_i(ω) will be the + * same as if computed manually. * */ static void test_pertubator_coefficients() @@ -213,8 +213,8 @@ template class ProtoGalaxyTests : public testing::Test { } /** - * @brief Manually compute the expected evaluations of the combiner quotient, given evaluations of the combiner and - * check them against the evaluations returned by the function. + * @brief Manually compute the expected evaluations of the combiner quotient, given evaluations of the combiner + * and check them against the evaluations returned by the function. * */ static void test_combiner_quotient() @@ -246,8 +246,8 @@ template class ProtoGalaxyTests : public testing::Test { } /** - * @brief For two dummy instances with their relation parameter η set, check that combining them in a univariate, - * barycentrially extended to the desired number of evaluations, is performed correctly. + * @brief For two dummy instances with their relation parameter η set, check that combining them in a + * univariate, barycentrially extended to the desired number of evaluations, is performed correctly. * */ static void test_combine_relation_parameters() diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp index 73407b99a7c..bb4be8dbb3d 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp @@ -149,31 +149,43 @@ template class ProtoGalaxyProver_ { auto instance_size = instance_polynomials.get_polynomial_size(); std::vector full_honk_evaluations(instance_size); std::vector linearly_dependent_contributions(instance_size); - parallel_for(instance_size, [&](size_t row) { - auto row_evaluations = instance_polynomials.get_row(row); - RelationEvaluations relation_evaluations; - Utils::zero_elements(relation_evaluations); - - // Note that the evaluations are accumulated with the gate separation challenge - // being 1 at this stage, as this specific randomness is added later through the - // power polynomial univariate specific to ProtoGalaxy - Utils::template accumulate_relation_evaluations<>( - row_evaluations, relation_evaluations, relation_parameters, FF(1)); - - auto output = FF(0); - auto running_challenge = FF(1); - - // Sum relation evaluations, batched by their corresponding relation separator challenge, to - // get the value of the full honk relation at a specific row - linearly_dependent_contributions[row] = 0; - Utils::scale_and_batch_elements( - relation_evaluations, alpha, running_challenge, output, linearly_dependent_contributions[row]); - full_honk_evaluations[row] = output; +#ifndef NO_MULTITHREADING + std::mutex evaluation_mutex; +#endif + auto linearly_dependent_contribution_accumulator = FF(0); + run_loop_in_parallel(instance_size, [&](size_t start_row, size_t end_row) { + auto thread_accumulator = FF(0); + for (size_t row = start_row; row < end_row; row++) { + auto row_evaluations = instance_polynomials.get_row(row); + RelationEvaluations relation_evaluations; + Utils::zero_elements(relation_evaluations); + + // Note that the evaluations are accumulated with the gate separation challenge + // being 1 at this stage, as this specific randomness is added later through the + // power polynomial univariate specific to ProtoGalaxy + Utils::template accumulate_relation_evaluations<>( + row_evaluations, relation_evaluations, relation_parameters, FF(1)); + + auto output = FF(0); + auto running_challenge = FF(1); + + // Sum relation evaluations, batched by their corresponding relation separator challenge, to + // get the value of the full honk relation at a specific row + auto linearly_dependent_contribution = FF(0); + Utils::scale_and_batch_elements( + relation_evaluations, alpha, running_challenge, output, linearly_dependent_contribution); + thread_accumulator += linearly_dependent_contribution; + + full_honk_evaluations[row] = output; + } + { +#ifndef NO_MULTITHREADING + std::unique_lock evaluation_lock(evaluation_mutex); +#endif + linearly_dependent_contribution_accumulator += thread_accumulator; + } }); - - for (FF& linearly_dependent_contribution : linearly_dependent_contributions) { - full_honk_evaluations[0] += linearly_dependent_contribution; - } + full_honk_evaluations[0] += linearly_dependent_contribution_accumulator; return full_honk_evaluations; } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp index 4563f3d34c9..f7f766565c9 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp @@ -232,8 +232,8 @@ template class ProtoGalaxyRecursiveTests : public tes * make sure the verifer circuits pass check_circuit(). Ensure that the algorithm of the recursive and native * verifiers are identical by checking the manifests */ - // TODO(https://github.com/AztecProtocol/barretenberg/issues/844): Fold the recursive folding verifier in tests once - // we can fold instances of different sizes. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/844): Fold the recursive folding verifier in + // tests once we can fold instances of different sizes. static void test_full_protogalaxy_recursive() { // Create two arbitrary circuits for the first round of folding @@ -298,15 +298,6 @@ template class ProtoGalaxyRecursiveTests : public tes pairing_points[0].get_value(), pairing_points[1].get_value()); EXPECT_EQ(native_result, recursive_result); - // Ensure that the underlying native and recursive decider verification algorithms agree by ensuring - // the manifests produced are the same. - auto recursive_decider_manifest = decider_verifier.transcript->get_manifest(); - auto native_decider_manifest = native_decider_verifier.transcript->get_manifest(); - for (size_t i = 0; i < recursive_decider_manifest.size(); ++i) { - EXPECT_EQ(recursive_decider_manifest[i], native_decider_manifest[i]); - } - - // Construct and verify a proof of the recursive decider verifier circuit { auto instance = std::make_shared(decider_circuit); Prover prover(instance);