Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
logderivative_library.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Completed, auditors: [Federico], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7// Generic log-derivative utilities for lookups and permutations.
8// For the mathematical background, see relations/GENERIC_LOGUP_README.md
9
10#pragma once
11
16
17#include <span>
18#include <typeinfo>
19
20namespace bb {
21
33template <typename FF, typename Relation, typename Polynomials, bool UseMultithreading = false>
34void compute_logderivative_inverse(Polynomials& polynomials, auto& relation_parameters, const size_t start_index = 0)
35{
36 BB_BENCH_NAME("compute_logderivative_inverse");
37 using Accumulator = typename Relation::ValueAccumulator0;
38 constexpr size_t NUM_LOOKUP_TERMS = Relation::NUM_LOOKUP_TERMS;
39 constexpr size_t NUM_TABLE_TERMS = Relation::NUM_TABLE_TERMS;
40
41 auto& inverse_polynomial = Relation::get_inverse_polynomial(polynomials);
42 const size_t offset = std::max(inverse_polynomial.start_index(), start_index);
43 // Clamp to the polynomial's actual (non-virtual) data extent; beyond end_index() everything is virtual zero.
44 const size_t actual_size = inverse_polynomial.end_index() > offset ? inverse_polynomial.end_index() - offset : 0;
45 const auto compute_inverses = [&](size_t start, size_t end) {
46 for (size_t i = start; i < end; ++i) {
47 const size_t row_idx = i + offset;
48 // TODO(https://github.com/AztecProtocol/barretenberg/issues/940): avoid get_row if possible.
49 auto row = polynomials.get_row(row_idx);
50 bool has_inverse = Relation::operation_exists_at_row(row);
51 if (!has_inverse) {
52 continue;
53 }
54 FF denominator = 1;
55 bb::constexpr_for<0, NUM_LOOKUP_TERMS, 1>([&]<size_t lookup_index> {
56 auto denominator_term =
57 Relation::template compute_lookup_term<Accumulator, lookup_index>(row, relation_parameters);
58 denominator *= denominator_term;
59 });
60 bb::constexpr_for<0, NUM_TABLE_TERMS, 1>([&]<size_t table_index> {
61 auto denominator_term =
62 Relation::template compute_table_term<Accumulator, table_index>(row, relation_parameters);
63 denominator *= denominator_term;
64 });
65 inverse_polynomial.at(row_idx) = denominator;
66 }
67 if (start < end) {
68 FF* ffstart = &inverse_polynomial.data()[start + offset - inverse_polynomial.start_index()];
69 std::span<FF> to_invert(ffstart, end - start);
70 // Note: zeroes are ignored as they are not used anyway
71 FF::batch_invert(to_invert);
72 }
73 };
74 if constexpr (UseMultithreading) {
75 parallel_for([&](const ThreadChunk& chunk) {
76 BB_BENCH_TRACY_NAME("LogDerivative::compute_inverses");
77 auto range = chunk.range(actual_size);
78 if (!range.empty()) {
79 size_t start = *range.begin();
80 size_t end = start + range.size();
81 compute_inverses(start, end);
82 }
83 });
84 } else {
85 compute_inverses(0, actual_size);
86 }
87}
88
103template <typename FF,
104 typename Relation,
105 typename ContainerOverSubrelations,
106 typename AllEntities,
107 typename Parameters,
108 bool IsPermutation>
109void _accumulate_logderivative_subrelation_contributions(ContainerOverSubrelations& accumulator,
110 const AllEntities& in,
111 const Parameters& params,
112 const FF& scaling_factor)
113{
114 constexpr size_t NUM_LOOKUP_TERMS = Relation::NUM_LOOKUP_TERMS;
115 constexpr size_t NUM_TABLE_TERMS = Relation::NUM_TABLE_TERMS;
116
117 using Accumulator = typename std::tuple_element_t<0, ContainerOverSubrelations>;
118 using View = typename Accumulator::View;
119
120 auto lookup_inverses = View(Relation::get_inverse_polynomial(in));
121
122 constexpr size_t NUM_TOTAL_TERMS = NUM_LOOKUP_TERMS + NUM_TABLE_TERMS;
124 std::array<Accumulator, NUM_TOTAL_TERMS> denominator_accumulator;
125
126 // The inverse polynomial gives us the product of all the inverses, i.e.
127 // lookup_inverse = \prod_j (1 / lookup_term[j]) * \prod_k (1 / table_term[k])
128 // To obtain the inverses 1 / lookup_term[i], 1 / table_term[i], we multiply lookup_inverse by the product of all
129 // terms except the one we want to invert. We perform this calculation via the following algorithm:
130 // 1) Compute the successive products of all lookup terms and table terms
131 // 2) Check that lookup_inverse is the inverse of the full product
132 // 3) Iteratively compute the inverses as follows:
133 // (lookup_term_1 * .. * lookup_term_(i-1)) * lookup_inverse * (lookup_term_(i+1) * .. * table_term_m)
134
135 // Collect all the terms in a single vector, first the lookup terms, then the table terms
136 bb::constexpr_for<0, NUM_LOOKUP_TERMS, 1>(
137 [&]<size_t i>() { lookup_terms[i] = Relation::template compute_lookup_term<Accumulator, i>(in, params); });
138 bb::constexpr_for<0, NUM_TABLE_TERMS, 1>([&]<size_t i>() {
139 lookup_terms[i + NUM_LOOKUP_TERMS] = Relation::template compute_table_term<Accumulator, i>(in, params);
140 });
141
142 // 1) Construct the successive products
143 bb::constexpr_for<0, NUM_TOTAL_TERMS, 1>([&]<size_t i>() { denominator_accumulator[i] = lookup_terms[i]; });
144 bb::constexpr_for<0, NUM_TOTAL_TERMS - 1, 1>(
145 [&]<size_t i>() { denominator_accumulator[i + 1] *= denominator_accumulator[i]; });
146
147 // 2) First subrelation: check that lookup_inverse is the inverse of the cumulative product if inverse_exists = 1
148 auto inverse_accumulator = Accumulator(lookup_inverses);
149 const auto inverse_exists = Relation::template compute_inverse_exists<Accumulator>(in);
150
151 std::get<0>(accumulator) +=
152 (denominator_accumulator[NUM_TOTAL_TERMS - 1] * lookup_inverses - inverse_exists) * scaling_factor;
153
154 // 3) Iteratively compute the single inverses
155 for (size_t i = NUM_TOTAL_TERMS - 1; i > 0; --i) {
156 // Take the cumulative product up to the previous index and multiply by the current inverse accumulator
157 denominator_accumulator[i] = denominator_accumulator[i - 1] * inverse_accumulator;
158 // Multiply the inverse accumulator by the current term to remove it from the product of the inverses
159 inverse_accumulator = inverse_accumulator * lookup_terms[i];
160 }
161 // Inverse accumulator is now equal to the inverse of the first lookup term
162 denominator_accumulator[0] = inverse_accumulator;
163
164 // Second subrelation
165 bb::constexpr_for<0, NUM_LOOKUP_TERMS, 1>([&]<size_t i>() {
166 std::get<1>(accumulator) +=
167 Relation::template get_lookup_term_predicate<Accumulator, i>(in) * denominator_accumulator[i];
168 });
169
170 bb::constexpr_for<0, NUM_TABLE_TERMS, 1>([&]<size_t i>() {
171 auto to_subtract = Relation::template get_table_term_predicate<Accumulator, i>(in) *
172 denominator_accumulator[i + NUM_LOOKUP_TERMS];
173 if constexpr (!IsPermutation) {
174 // If not a permutation, multiply by the read count
175 to_subtract *= Relation::template lookup_read_counts<Accumulator, i>(in);
176 }
177 std::get<1>(accumulator) -= to_subtract;
178 });
179}
180} // namespace bb
bb::field< bb::Bn254FrParams > FF
Definition field.cpp:24
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
#define BB_BENCH_TRACY_NAME(name)
Definition bb_bench.hpp:256
std::tuple_element_t< 0, SumcheckArrayOfValuesOverSubrelations > ValueAccumulator0
ssize_t offset
Definition engine.cpp:62
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
void compute_logderivative_inverse(Polynomials &polynomials, auto &relation_parameters, const size_t start_index=0)
Compute the inverse polynomial I(X) required for logderivative lookups.
void _accumulate_logderivative_subrelation_contributions(ContainerOverSubrelations &accumulator, const AllEntities &in, const Parameters &params, const FF &scaling_factor)
Unified implementation of log-derivative subrelation accumulation.
constexpr void constexpr_for(F &&f)
Implements a loop using a compile-time iterator. Requires c++20. Implementation (and description) fro...
void parallel_for(size_t num_iterations, const std::function< void(size_t)> &func)
Definition thread.cpp:111
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
auto range(size_t size, size_t offset=0) const
Definition thread.hpp:152
static void batch_invert(C &coeffs) noexcept
Batch invert a collection of field elements using Montgomery's trick.