From 70f78df52e27ef4c7139b17babfb8597cfca6cf6 Mon Sep 17 00:00:00 2001 From: Rumata888 Date: Wed, 24 Apr 2024 14:56:02 +0000 Subject: [PATCH] Different strategy --- .../src/barretenberg/eccvm/eccvm_flavor.hpp | 6 + .../barretenberg/polynomials/univariate.hpp | 188 ++++++++++-------- .../protogalaxy/protogalaxy_prover.hpp | 52 ++--- .../relations/nested_containers.hpp | 24 ++- .../barretenberg/relations/relation_types.hpp | 29 +-- .../goblin_ultra_flavor.hpp | 7 + .../stdlib_circuit_builders/ultra_flavor.hpp | 6 + .../sumcheck/instance/instances.hpp | 6 +- .../goblin_translator_flavor.hpp | 6 + .../barretenberg/vm/generated/avm_flavor.hpp | 6 + 10 files changed, 177 insertions(+), 153 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp index c3c26a6ef701..3e315bf0d9a1 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp @@ -401,6 +401,12 @@ class ECCVMFlavor { * @brief A container for univariates used during sumcheck. */ template using ProverUnivariates = AllEntities>; + /** + * @brief A container for univariates used during Protogalaxy folding and sumcheck. + * @details During folding and sumcheck, the prover evaluates the relations on these univariates. + */ + template + using OptimisedProverUnivariates = AllEntities>; /** * @brief A container for univariates produced during the hot loop in sumcheck. diff --git a/barretenberg/cpp/src/barretenberg/polynomials/univariate.hpp b/barretenberg/cpp/src/barretenberg/polynomials/univariate.hpp index 4bab8790d053..edbb358a95c8 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/univariate.hpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/univariate.hpp @@ -13,17 +13,17 @@ namespace bb { * of the data in those univariates. We do that by taking a view of those elements and then, as needed, using this to * populate new containers. */ -template class UnivariateView; +template class UnivariateView; /** * @brief A univariate polynomial represented by its values on {domain_start, domain_start + 1,..., domain_end - 1}. For * memory efficiency purposes, we store the evaluations in an array starting from 0 and make the mapping to the right * domain under the hood. */ -template class Univariate { +template class Univariate { public: static constexpr size_t LENGTH = domain_end - domain_start; - using View = UnivariateView; + using View = UnivariateView; using value_type = Fr; // used to get the type of the elements consistently with std::array @@ -50,7 +50,7 @@ template class Univariate } } // Construct Univariate from UnivariateView - explicit Univariate(UnivariateView in) + explicit Univariate(UnivariateView in) : evaluations{} { for (size_t i = 0; i < in.evaluations.size(); ++i) { @@ -77,7 +77,7 @@ template class Univariate static Univariate get_random() { - auto output = Univariate(); + auto output = Univariate(); for (size_t i = 0; i != LENGTH; ++i) { output.value_at(i) = Fr::random_element(); } @@ -86,7 +86,7 @@ template class Univariate static Univariate zero() { - auto output = Univariate(); + auto output = Univariate(); for (size_t i = 0; i != LENGTH; ++i) { output.value_at(i) = Fr::zero(); } @@ -100,21 +100,25 @@ template class Univariate Univariate& operator+=(const Univariate& other) { - for (size_t i = 0; i < LENGTH; ++i) { + evaluations[0] += other.evaluations[0]; + for (size_t i = skip_count + 1; i < LENGTH; ++i) { evaluations[i] += other.evaluations[i]; } return *this; } Univariate& operator-=(const Univariate& other) { - for (size_t i = 0; i < LENGTH; ++i) { + evaluations[0] -= other.evaluations[0]; + for (size_t i = skip_count + 1; i < LENGTH; ++i) { + evaluations[i] -= other.evaluations[i]; } return *this; } Univariate& operator*=(const Univariate& other) { - for (size_t i = 0; i < LENGTH; ++i) { + evaluations[0] *= other.evaluations[0]; + for (size_t i = skip_count + 1; i < LENGTH; ++i) { evaluations[i] *= other.evaluations[i]; } return *this; @@ -135,8 +139,12 @@ template class Univariate Univariate operator-() const { Univariate res(*this); + size_t i = 0; for (auto& eval : res.evaluations) { - eval = -eval; + if (i == 0 || i >= (skip_count + 1)) { + eval = -eval; + } + i++; } return res; } @@ -151,23 +159,35 @@ template class Univariate // Operations between Univariate and scalar Univariate& operator+=(const Fr& scalar) { + size_t i = 0; for (auto& eval : evaluations) { - eval += scalar; + if (i == 0 || i >= (skip_count + 1)) { + eval += scalar; + } + i++; } return *this; } Univariate& operator-=(const Fr& scalar) { + size_t i = 0; for (auto& eval : evaluations) { - eval -= scalar; + if (i == 0 || i >= (skip_count + 1)) { + eval -= scalar; + } + i++; } return *this; } Univariate& operator*=(const Fr& scalar) { + size_t i = 0; for (auto& eval : evaluations) { - eval *= scalar; + if (i == 0 || i >= (skip_count + 1)) { + eval *= scalar; + } + i++; } return *this; } @@ -194,45 +214,48 @@ template class Univariate } // Operations between Univariate and UnivariateView - Univariate& operator+=(const UnivariateView& view) + Univariate& operator+=(const UnivariateView& view) { - for (size_t i = 0; i < LENGTH; ++i) { + evaluations[0] += view.evaluations[0]; + for (size_t i = skip_count + 1; i < LENGTH; ++i) { evaluations[i] += view.evaluations[i]; } return *this; } - Univariate& operator-=(const UnivariateView& view) + Univariate& operator-=(const UnivariateView& view) { - for (size_t i = 0; i < LENGTH; ++i) { + evaluations[0] -= view.evaluations[0]; + for (size_t i = skip_count + 1; i < LENGTH; ++i) { evaluations[i] -= view.evaluations[i]; } return *this; } - Univariate& operator*=(const UnivariateView& view) + Univariate& operator*=(const UnivariateView& view) { - for (size_t i = 0; i < LENGTH; ++i) { + evaluations[0] *= view.evaluations[0]; + for (size_t i = skip_count + 1; i < LENGTH; ++i) { evaluations[i] *= view.evaluations[i]; } return *this; } - Univariate operator+(const UnivariateView& view) const + Univariate operator+(const UnivariateView& view) const { Univariate res(*this); res += view; return res; } - Univariate operator-(const UnivariateView& view) const + Univariate operator-(const UnivariateView& view) const { Univariate res(*this); res -= view; return res; } - Univariate operator*(const UnivariateView& view) const + Univariate operator*(const UnivariateView& view) const { Univariate res(*this); res *= view; @@ -256,29 +279,31 @@ template class Univariate } /** - * @brief Given a univariate f represented by {f(domain_start), ..., f(domain_end - 1)}, compute the evaluations - * {f(domain_end),..., f(extended_domain_end -1)} and return the Univariate represented by {f(domain_start),..., - * f(extended_domain_end -1)} + * @brief Given a univariate f represented by {f(domain_start), ..., f(domain_end - 1)}, compute the + * evaluations {f(domain_end),..., f(extended_domain_end -1)} and return the Univariate represented by + * {f(domain_start),..., f(extended_domain_end -1)} * - * @details Write v_i = f(x_i) on a the domain {x_{domain_start}, ..., x_{domain_end-1}}. To efficiently compute the - * needed values of f, we use the barycentric formula + * @details Write v_i = f(x_i) on a the domain {x_{domain_start}, ..., x_{domain_end-1}}. To efficiently + * compute the needed values of f, we use the barycentric formula * - f(x) = B(x) Σ_{i=domain_start}^{domain_end-1} v_i / (d_i*(x-x_i)) * where * - B(x) = Π_{i=domain_start}^{domain_end-1} (x-x_i) - * - d_i = Π_{j ∈ {domain_start, ..., domain_end-1}, j≠i} (x_i-x_j) for i ∈ {domain_start, ..., domain_end-1} + * - d_i = Π_{j ∈ {domain_start, ..., domain_end-1}, j≠i} (x_i-x_j) for i ∈ {domain_start, ..., + * domain_end-1} * - * When the domain size is two, extending f = v0(1-X) + v1X to a new value involves just one addition and a - * subtraction: setting Δ = v1-v0, the values of f(X) are f(0)=v0, f(1)= v0 + Δ, v2 = f(1) + Δ, v3 = f(2) + Δ... + * When the domain size is two, extending f = v0(1-X) + v1X to a new value involves just one addition + * and a subtraction: setting Δ = v1-v0, the values of f(X) are f(0)=v0, f(1)= v0 + Δ, v2 = f(1) + Δ, v3 + * = f(2) + Δ... * */ template - Univariate extend_to() const + Univariate extend_to() const { - const size_t EXTENDED_LENGTH = EXTENDED_DOMAIN_END - domain_start + NUM_SKIPPED_INDICES; + const size_t EXTENDED_LENGTH = EXTENDED_DOMAIN_END - domain_start; using Data = BarycentricData; static_assert(EXTENDED_LENGTH >= LENGTH); - Univariate result; + Univariate result; std::copy(evaluations.begin(), evaluations.end(), result.evaluations.begin()); @@ -315,8 +340,8 @@ template class Univariate // a*1 + b*1 + c*1 + d = f(1) // a*2^3 + b*2^2 + c*2 + d = f(2) // a*3^3 + b*3^2 + c*3 + d = f(3) - // These equations can be rewritten as a matrix equation M * [a, b, c, d] = [f(0), f(1), f(2), f(3)], where - // M is: + // These equations can be rewritten as a matrix equation M * [a, b, c, d] = [f(0), f(1), f(2), + // f(3)], where M is: // 0, 0, 0, 1 // 1, 1, 1, 1 // 2^3, 2^2, 2, 1 @@ -326,9 +351,9 @@ template class Univariate // 1, -5/2, 2, -1/2 // -11/6, 3, -3/2, 1/3 // 1, 0, 0, 0 - // To compute these values, we can multiply everything by 6 and multiply by inverse_six at the end for each - // coefficient The resulting computation here does 18 field adds, 6 subtracts, 3 muls to compute a, b, c, - // and d. + // To compute these values, we can multiply everything by 6 and multiply by inverse_six at the + // end for each coefficient The resulting computation here does 18 field adds, 6 subtracts, 3 + // muls to compute a, b, c, and d. Fr zero_times_3 = value_at(0) + value_at(0) + value_at(0); Fr zero_times_6 = zero_times_3 + zero_times_3; Fr zero_times_12 = zero_times_6 + zero_times_6; @@ -381,16 +406,7 @@ template class Univariate result.value_at(k) *= Data::full_numerator_values[k]; } } - if constexpr (NUM_SKIPPED_INDICES == 0) { - return result; - } - Univariate optimised_result; - optimised_result.value_at(0) = result.value_at(0); - - std::copy(std::next(result.evaluations.begin(), 1 + NUM_SKIPPED_INDICES), - result.evaluations.end(), - std::next(optimised_result.evaluations.begin(), 1)); - return optimised_result; + return result; } /** @@ -407,8 +423,8 @@ template class Univariate full_numerator_value *= u - i; } - // build set of domain size-many denominator inverses 1/(d_i*(x_k - x_j)). will multiply against each of - // these (rather than to divide by something) for each barycentric evaluation + // build set of domain size-many denominator inverses 1/(d_i*(x_k - x_j)). will multiply against + // each of these (rather than to divide by something) for each barycentric evaluation std::array denominator_inverses; for (size_t i = 0; i != LENGTH; ++i) { Fr inv = Data::lagrange_denominators[i]; @@ -451,7 +467,7 @@ inline void write(B& it, Univariate const& univari write(it, univariate.evaluations); } -template class UnivariateView { +template class UnivariateView { public: static constexpr size_t LENGTH = domain_end - domain_start; std::span evaluations; @@ -461,77 +477,84 @@ template class Univariate const Fr& value_at(size_t i) const { return evaluations[i]; }; template - explicit UnivariateView(const Univariate& univariate_in) + explicit UnivariateView(const Univariate& univariate_in) : evaluations(std::span(univariate_in.evaluations.data(), LENGTH)){}; - Univariate operator+(const UnivariateView& other) const + Univariate operator+(const UnivariateView& other) const { - Univariate res(*this); + Univariate res(*this); res += other; return res; } - Univariate operator-(const UnivariateView& other) const + Univariate operator-(const UnivariateView& other) const { - Univariate res(*this); + Univariate res(*this); res -= other; return res; } - Univariate operator-() const + Univariate operator-() const { - Univariate res(*this); + Univariate res(*this); + size_t i = 0; for (auto& eval : res.evaluations) { - eval = -eval; + if (i == 0 || i >= (skip_count + 1)) { + eval = -eval; + } + i++; } return res; } - Univariate operator*(const UnivariateView& other) const + Univariate operator*(const UnivariateView& other) const { - Univariate res(*this); + Univariate res(*this); res *= other; return res; } - Univariate operator*(const Univariate& other) const + Univariate operator*( + const Univariate& other) const { - Univariate res(*this); + Univariate res(*this); res *= other; return res; } - Univariate operator+(const Univariate& other) const + Univariate operator+( + const Univariate& other) const { - Univariate res(*this); + Univariate res(*this); res += other; return res; } - Univariate operator+(const Fr& other) const + Univariate operator+(const Fr& other) const { - Univariate res(*this); + Univariate res(*this); res += other; return res; } - Univariate operator-(const Fr& other) const + Univariate operator-(const Fr& other) const { - Univariate res(*this); + Univariate res(*this); res -= other; return res; } - Univariate operator*(const Fr& other) const + Univariate operator*(const Fr& other) const { - Univariate res(*this); + Univariate res(*this); res *= other; return res; } - Univariate operator-(const Univariate& other) const + Univariate operator-( + const Univariate& other) const { - Univariate res(*this); + Univariate res(*this); res -= other; return res; } @@ -554,8 +577,8 @@ template class Univariate }; /** - * @brief Create a sub-array of `elements` at the indices given in the template pack `Is`, converting them to the new - * type T. + * @brief Create a sub-array of `elements` at the indices given in the template pack `Is`, converting them + * to the new type T. * * @tparam T type to convert to * @tparam U type to convert from @@ -563,8 +586,8 @@ template class Univariate * @tparam Is list of indices we want in the returned array. When the second argument is called with * `std::make_index_sequence`, these will be `0, 1, ..., N-1`. * @param elements array to convert from - * @return std::array result array s.t. result[i] = T(elements[Is[i]]). By default, Is[i] = i when - * called with `std::make_index_sequence`. + * @return std::array result array s.t. result[i] = T(elements[Is[i]]). By default, Is[i] + * = i when called with `std::make_index_sequence`. */ template std::array array_to_array_aux(const std::array& elements, std::index_sequence) @@ -576,11 +599,12 @@ std::array array_to_array_aux(const std::array& elements * @brief Given an std::array, returns an std::array, by calling the (explicit) constructor T(U). * * @details https://stackoverflow.com/a/32175958 - * The main use case is to convert an array of `Univariate` into `UnivariateView`. The main use case would be to let - * Sumcheck decide the required degree of the relation evaluation, rather than hardcoding it inside the relation. The - * `_aux` version could also be used to create an array of only the polynomials required by the relation, and it could - * help us implement the optimization where we extend each edge only up to the maximum degree that is required over all - * relations (for example, `L_LAST` only needs degree 3). + * The main use case is to convert an array of `Univariate` into `UnivariateView`. The main use case would + * be to let Sumcheck decide the required degree of the relation evaluation, rather than hardcoding it + * inside the relation. The + * `_aux` version could also be used to create an array of only the polynomials required by the relation, + * and it could help us implement the optimization where we extend each edge only up to the maximum degree + * that is required over all relations (for example, `L_LAST` only needs degree 3). * * @tparam T Output type * @tparam U Input type (deduced from `elements`) diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp index 7c3d96ebaa59..84b6ca8b23e7 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp @@ -50,7 +50,10 @@ template class ProtoGalaxyProver_ { // obtained by composing a relation with folded instance + relation parameters . using ExtendedUnivariate = Univariate; using OptimisedExtendedUnivariate = - Univariate; + Univariate; // Represents the total length of the combiner univariate, obtained by combining the already folded relations with // the folded relation batching challenge. using ExtendedUnivariateWithRandomization = @@ -58,7 +61,7 @@ template class ProtoGalaxyProver_ { (Flavor::MAX_TOTAL_RELATION_LENGTH - 1 + ProverInstances::NUM - 1) * (ProverInstances::NUM - 1) + 1>; using ExtendedUnivariates = typename Flavor::template ProverUnivariates; using OptimisedExtendedUnivariates = - typename Flavor::template ProverUnivariates; + typename Flavor::template OptimisedProverUnivariates; using TupleOfTuplesOfUnivariates = typename Flavor::template ProtogalaxyTupleOfTuplesOfUnivariates; @@ -287,32 +290,14 @@ template class ProtoGalaxyProver_ { * (i.e., compute additional evaluations at adjacent domain values) as needed. * @todo TODO(https://github.com/AztecProtocol/barretenberg/issues/751) Optimize memory */ - void extend_univariates(ExtendedUnivariates& extended_univariates, + template + void extend_univariates(OptimisedExtendedUnivariates& extended_univariates, const ProverInstances& instances, const size_t row_idx) { - auto base_univariates = instances.row_to_univariates(row_idx); + auto base_univariates = instances.template row_to_univariates(row_idx); for (auto [extended_univariate, base_univariate] : zip_view(extended_univariates.get_all(), base_univariates)) { - extended_univariate = base_univariate.template extend_to(); - } - } - - /** - * @brief Prepare a univariate polynomial for relation execution in one step of the main loop in folded instance - * construction. - * @details For a fixed prover polynomial index, extract that polynomial from each instance in Instances. From each - * polynomial, extract the value at row_idx. Use these values to create a univariate polynomial, and then extend - * (i.e., compute additional evaluations at adjacent domain values) as needed. - * @todo TODO(https://github.com/AztecProtocol/barretenberg/issues/751) Optimize memory - */ - void optimised_extend_univariates(OptimisedExtendedUnivariates& extended_univariates, - const ProverInstances& instances, - const size_t row_idx) - { - auto base_univariates = instances.row_to_univariates(row_idx); - for (auto [extended_univariate, base_univariate] : zip_view(extended_univariates.get_all(), base_univariates)) { - extended_univariate = - base_univariate.template extend_to(); + extended_univariate = base_univariate.template extend_to(); } } @@ -371,7 +356,7 @@ template class ProtoGalaxyProver_ { for (size_t idx = start; idx < end; idx++) { // No need to initialise extended_univariates to 0, it's assigned to - optimised_extend_univariates(extended_univariates[thread_idx], instances, idx); + extend_univariates(extended_univariates[thread_idx], instances, idx); FF pow_challenge = pow_betas[idx]; @@ -391,31 +376,24 @@ template class ProtoGalaxyProver_ { for (auto& accumulators : thread_univariate_accumulators) { Utils::add_nested_tuples(optimised_univariate_accumulators, accumulators); } - deoptimise_univariates(optimised_univariate_accumulators, univariate_accumulators); + zero_skipped_indices(optimised_univariate_accumulators); // Batch the univariate contributions from each sub-relation to obtain the round univariate return batch_over_relations(univariate_accumulators, instances.alphas); } - static void deoptimise_univariates(OptimisedTupleOfTuplesOfUnivariates& optimised_univariate_accumulators, - TupleOfTuplesOfUnivariates& univariate_accumulators + static void zero_skipped_indices(OptimisedTupleOfTuplesOfUnivariates& optimised_univariate_accumulators ) { auto deoptimise = [&](auto& element) { - auto& optimised_element = std::get(std::get(optimised_univariate_accumulators)); - static_assert(std::remove_reference_t::LENGTH + (ProverInstances::NUM - 1) == - std::remove_reference_t::LENGTH); - element.evaluations[0] = optimised_element.evaluations[0]; + // auto& optimised_element = std::get(std::get(optimised_univariate_accumulators)); for (size_t i = 1; i < ProverInstances::NUM; i++) { element.evaluations[i] = FF(0); } - for (size_t i = 1; i < std::remove_reference_t::LENGTH; i++) { - element.evaluations[i + ProverInstances::NUM - 1] = optimised_element.evaluations[i]; - } - info("Element ", outer_idx, ".", inner_idx, "[", ":", "] = ", element); + // info("Element ", outer_idx, ".", inner_idx, "[", ":", "] = ", element); }; - Utils::template apply_to_tuple_of_tuples<0, 0>(univariate_accumulators, deoptimise); + Utils::template apply_to_tuple_of_tuples<0, 0>(optimised_univariate_accumulators, deoptimise); } static ExtendedUnivariateWithRandomization batch_over_relations(TupleOfTuplesOfUnivariates& univariate_accumulators, diff --git a/barretenberg/cpp/src/barretenberg/relations/nested_containers.hpp b/barretenberg/cpp/src/barretenberg/relations/nested_containers.hpp index 46f2d2463035..36a522eb1618 100644 --- a/barretenberg/cpp/src/barretenberg/relations/nested_containers.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/nested_containers.hpp @@ -10,30 +10,42 @@ namespace bb { * * @details Credit: https://stackoverflow.com/a/60440611 */ -template