Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Move log deriv lookup accum to library #3226

Merged
merged 1 commit into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,100 @@ void compute_logderivative_inverse(Polynomials& polynomials,
FF::batch_invert(inverse_polynomial);
}

/**
* @brief Compute generic log-derivative lookup subrelation accumulation
* @details The generic log-derivative lookup relation consistes of two subrelations. The first demonstrates that the
* inverse polynomial I, defined via I_i = 1/[(read_term_i) * (write_term_i)], has been computed correctly. The second
* establishes the correctness of the lookups themselves based on the log-derivative lookup argument. Note that the
* latter subrelation is "linearly dependent" in the sense that it establishes that a sum across all rows of the
* exectution trace is zero, rather than that some expression holds independently at each row. Accordingly, this
* subrelation is not multiplied by a scaling factor at each accumulation step. The subrelation expressions are
* respectively:
*
* I_i * (read_term_i) * (write_term_i) - 1 = 0
*
* \sum_{i=0}^{n-1} [q_{logderiv_lookup} * I_i * write_term_i + read_count_i * I_i * read_term_i] = 0
*
* The explicit expressions for read_term and write_term are dependent upon the particular structure of the lookup being
* performed and methods for computing them must be defined in the corresponding relation class.
*
* @tparam FF
* @tparam Relation
* @tparam ContainerOverSubrelations
* @tparam AllEntities
* @tparam Parameters
* @param accumulator
* @param in
* @param params
* @param scaling_factor
*/
template <typename FF, typename Relation, typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
void accumulate_logderivative_lookup_subrelation_contributions(ContainerOverSubrelations& accumulator,
const AllEntities& in,
const Parameters& params,
const FF& scaling_factor)
{
constexpr size_t READ_TERMS = Relation::READ_TERMS;
constexpr size_t WRITE_TERMS = Relation::WRITE_TERMS;

auto lookup_relation = Relation();

using Accumulator = typename std::tuple_element_t<0, ContainerOverSubrelations>;
using View = typename Accumulator::View;

auto lookup_inverses = View(in.lookup_inverses);

constexpr size_t NUM_TOTAL_TERMS = READ_TERMS + WRITE_TERMS;
std::array<Accumulator, NUM_TOTAL_TERMS> lookup_terms;
std::array<Accumulator, NUM_TOTAL_TERMS> denominator_accumulator;

// The lookup relation = \sum_j (1 / read_term[j]) - \sum_k (read_counts[k] / write_term[k])
// To get the inverses (1 / read_term[i]), (1 / write_term[i]), we have a commitment to the product of all inverses
// i.e. lookup_inverse = \prod_j (1 / read_term[j]) * \prod_k (1 / write_term[k])
// The purpose of this next section is to derive individual inverse terms using `lookup_inverses`
// i.e. (1 / read_term[i]) = lookup_inverse * \prod_{j /ne i} (read_term[j]) * \prod_k (write_term[k])
// (1 / write_term[i]) = lookup_inverse * \prod_j (read_term[j]) * \prod_{k ne i} (write_term[k])
barretenberg::constexpr_for<0, READ_TERMS, 1>(
[&]<size_t i>() { lookup_terms[i] = lookup_relation.template compute_read_term<Accumulator, i>(in, params); });
barretenberg::constexpr_for<0, WRITE_TERMS, 1>([&]<size_t i>() {
lookup_terms[i + READ_TERMS] = lookup_relation.template compute_write_term<Accumulator, i>(in, params);
});

barretenberg::constexpr_for<0, NUM_TOTAL_TERMS, 1>(
[&]<size_t i>() { denominator_accumulator[i] = lookup_terms[i]; });

barretenberg::constexpr_for<0, NUM_TOTAL_TERMS - 1, 1>(
[&]<size_t i>() { denominator_accumulator[i + 1] *= denominator_accumulator[i]; });

auto inverse_accumulator = Accumulator(lookup_inverses); // denominator_accumulator[NUM_TOTAL_TERMS - 1];

const auto inverse_exists = lookup_relation.template compute_inverse_exists<Accumulator>(in);

std::get<0>(accumulator) +=
(denominator_accumulator[NUM_TOTAL_TERMS - 1] * lookup_inverses - inverse_exists) * scaling_factor;

// After this algo, total degree of denominator_accumulator = NUM_TOTAL_TERMS
for (size_t i = 0; i < NUM_TOTAL_TERMS - 1; ++i) {
denominator_accumulator[NUM_TOTAL_TERMS - 1 - i] =
denominator_accumulator[NUM_TOTAL_TERMS - 2 - i] * inverse_accumulator;
inverse_accumulator = inverse_accumulator * lookup_terms[NUM_TOTAL_TERMS - 1 - i];
}
denominator_accumulator[0] = inverse_accumulator;

// each predicate is degree-1
// degree of relation at this point = NUM_TOTAL_TERMS + 1
barretenberg::constexpr_for<0, READ_TERMS, 1>([&]<size_t i>() {
std::get<1>(accumulator) +=
lookup_relation.template compute_read_term_predicate<Accumulator, i>(in) * denominator_accumulator[i];
});

// each predicate is degree-1, `lookup_read_counts` is degree-1
// degree of relation = NUM_TOTAL_TERMS + 2
barretenberg::constexpr_for<0, WRITE_TERMS, 1>([&]<size_t i>() {
const auto p = lookup_relation.template compute_write_term_predicate<Accumulator, i>(in);
const auto lookup_read_count = View(in.template lookup_read_counts<i>());
std::get<1>(accumulator) -= p * (denominator_accumulator[i + READ_TERMS] * lookup_read_count);
});
}

} // namespace proof_system::honk::lookup_library
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "barretenberg/flavor/ecc_vm.hpp"
#include "barretenberg/flavor/relation_definitions_fwd.hpp"
#include "barretenberg/honk/proof_system/lookup_library.hpp"
#include "ecc_msm_relation.hpp"

namespace proof_system::honk::sumcheck {
Expand All @@ -24,62 +25,8 @@ void ECCVMLookupRelationBase<FF>::accumulate(ContainerOverSubrelations& accumula
const Parameters& params,
[[maybe_unused]] const FF& scaling_factor)
{
using Accumulator = typename std::tuple_element_t<0, ContainerOverSubrelations>;
using View = typename Accumulator::View;

auto lookup_inverses = View(in.lookup_inverses);

constexpr size_t NUM_TOTAL_TERMS = READ_TERMS + WRITE_TERMS;
std::array<Accumulator, NUM_TOTAL_TERMS> lookup_terms;
std::array<Accumulator, NUM_TOTAL_TERMS> denominator_accumulator;

// The lookup relation = \sum_j (1 / read_term[j]) - \sum_k (read_counts[k] / write_term[k])
// To get the inverses (1 / read_term[i]), (1 / write_term[i]), we have a commitment to the product of all inverses
// i.e. lookup_inverse = \prod_j (1 / read_term[j]) * \prod_k (1 / write_term[k])
// The purpose of this next section is to derive individual inverse terms using `lookup_inverses`
// i.e. (1 / read_term[i]) = lookup_inverse * \prod_{j /ne i} (read_term[j]) * \prod_k (write_term[k])
// (1 / write_term[i]) = lookup_inverse * \prod_j (read_term[j]) * \prod_{k ne i} (write_term[k])
barretenberg::constexpr_for<0, READ_TERMS, 1>(
[&]<size_t i>() { lookup_terms[i] = compute_read_term<Accumulator, i>(in, params); });
barretenberg::constexpr_for<0, WRITE_TERMS, 1>(
[&]<size_t i>() { lookup_terms[i + READ_TERMS] = compute_write_term<Accumulator, i>(in, params); });

barretenberg::constexpr_for<0, NUM_TOTAL_TERMS, 1>(
[&]<size_t i>() { denominator_accumulator[i] = lookup_terms[i]; });

barretenberg::constexpr_for<0, NUM_TOTAL_TERMS - 1, 1>(
[&]<size_t i>() { denominator_accumulator[i + 1] *= denominator_accumulator[i]; });

auto inverse_accumulator = Accumulator(lookup_inverses); // denominator_accumulator[NUM_TOTAL_TERMS - 1];

const auto row_has_write = View(in.precompute_select);
const auto row_has_read = View(in.msm_add) + View(in.msm_skew);
const auto inverse_exists = row_has_write + row_has_read - (row_has_write * row_has_read);

std::get<0>(accumulator) +=
(denominator_accumulator[NUM_TOTAL_TERMS - 1] * lookup_inverses - inverse_exists) * scaling_factor;

// After this algo, total degree of denominator_accumulator = NUM_TOTAL_TERMA
for (size_t i = 0; i < NUM_TOTAL_TERMS - 1; ++i) {
denominator_accumulator[NUM_TOTAL_TERMS - 1 - i] =
denominator_accumulator[NUM_TOTAL_TERMS - 2 - i] * inverse_accumulator;
inverse_accumulator = inverse_accumulator * lookup_terms[NUM_TOTAL_TERMS - 1 - i];
}
denominator_accumulator[0] = inverse_accumulator;

// each predicate is degree-1
// degree of relation at this point = NUM_TOTAL_TERMS + 1
barretenberg::constexpr_for<0, READ_TERMS, 1>([&]<size_t i>() {
std::get<1>(accumulator) += compute_read_term_predicate<Accumulator, i>(in) * denominator_accumulator[i];
});

// each predicate is degree-1, `lookup_read_counts` is degree-1
// degree of relation = NUM_TOTAL_TERMS + 2 = 6 + 2
barretenberg::constexpr_for<0, WRITE_TERMS, 1>([&]<size_t i>() {
const auto p = compute_write_term_predicate<Accumulator, i>(in);
const auto lookup_read_count = View(in.template lookup_read_counts<i>());
std::get<1>(accumulator) -= p * (denominator_accumulator[i + READ_TERMS] * lookup_read_count);
});
lookup_library::accumulate_logderivative_lookup_subrelation_contributions<FF, ECCVMLookupRelationBase<FF>>(
accumulator, in, params, scaling_factor);
}

template class ECCVMLookupRelationBase<barretenberg::fr>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ template <typename FF_> class ECCVMLookupRelationBase {
return (row.msm_add == 1) || (row.msm_skew == 1) || (row.precompute_select == 1);
}

template <typename Accumulator, typename AllEntities>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the last component that needed to be "genericized" in order for the accumulate logic to be fully generic

static Accumulator compute_inverse_exists(const AllEntities& in)
{
using View = typename Accumulator::View;

const auto row_has_write = View(in.precompute_select);
const auto row_has_read = View(in.msm_add) + View(in.msm_skew);
return row_has_write + row_has_read - (row_has_write * row_has_read);
}

template <typename Accumulator, size_t read_index, typename AllEntities>
static Accumulator compute_read_term_predicate(const AllEntities& in)

Expand Down Expand Up @@ -209,7 +219,7 @@ template <typename FF_> class ECCVMLookupRelationBase {
static void accumulate(ContainerOverSubrelations& accumulator,
const AllEntities& in,
const Parameters& params,
const FF& /*unused*/);
const FF& scaling_factor);
};

template <typename FF> using ECCVMLookupRelation = Relation<ECCVMLookupRelationBase<FF>>;
Expand Down