Skip to content

Commit

Permalink
refactor: Move log deriv lookup accum to library (#3226)
Browse files Browse the repository at this point in the history
The logic for accumulating the log-derivative lookup relation
subrelation contributions is generic and can be reused. It was
previously implemented in the `accumulate` method of the eccvm lookup
relation. This work moves the logic to an existing lookup library in
preparation for reuse by the databus log-deriv lookup relation.
  • Loading branch information
ledwards2225 authored Nov 3, 2023
1 parent e4a0c4a commit 189d1bb
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 57 deletions.
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>
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

0 comments on commit 189d1bb

Please sign in to comment.