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
15
16#include <span>
17#include <typeinfo>
18
19namespace bb {
20
32template <typename FF, typename Relation, typename Polynomials, bool UseMultithreading = false>
33void compute_logderivative_inverse(Polynomials& polynomials, auto& relation_parameters, const size_t circuit_size)
34{
35 using Accumulator = typename Relation::ValueAccumulator0;
36 constexpr size_t NUM_LOOKUP_TERMS = Relation::NUM_LOOKUP_TERMS;
37 constexpr size_t NUM_TABLE_TERMS = Relation::NUM_TABLE_TERMS;
38
39 auto& inverse_polynomial = Relation::get_inverse_polynomial(polynomials);
40 const size_t offset = inverse_polynomial.start_index();
41 const auto compute_inverses = [&](size_t start, size_t end) {
42 for (size_t i = start; i < end; ++i) {
43 // TODO(https://github.com/AztecProtocol/barretenberg/issues/940): avoid get_row if possible.
44 auto row = polynomials.get_row(i + offset);
45 bool has_inverse = Relation::operation_exists_at_row(row);
46 if (!has_inverse) {
47 continue;
48 }
49 FF denominator = 1;
50 bb::constexpr_for<0, NUM_LOOKUP_TERMS, 1>([&]<size_t lookup_index> {
51 auto denominator_term =
52 Relation::template compute_lookup_term<Accumulator, lookup_index>(row, relation_parameters);
53 denominator *= denominator_term;
54 });
55 bb::constexpr_for<0, NUM_TABLE_TERMS, 1>([&]<size_t table_index> {
56 auto denominator_term =
57 Relation::template compute_table_term<Accumulator, table_index>(row, relation_parameters);
58 denominator *= denominator_term;
59 });
60 inverse_polynomial.at(i) = denominator;
61 }
62 FF* ffstart = &inverse_polynomial.coeffs()[start];
63 std::span<FF> to_invert(ffstart, end - start);
64 // Compute inverse polynomial I in place by inverting the product at each row
65 // Note: zeroes are ignored as they are not used anyway
66 FF::batch_invert(to_invert);
67 };
68 if constexpr (UseMultithreading) {
69 parallel_for([&](const ThreadChunk& chunk) {
70 auto range = chunk.range(circuit_size);
71 if (!range.empty()) {
72 size_t start = *range.begin();
73 size_t end = start + range.size();
74 compute_inverses(start, end);
75 }
76 });
77 } else {
78 compute_inverses(0, inverse_polynomial.size());
79 }
80}
81
96template <typename FF,
97 typename Relation,
98 typename ContainerOverSubrelations,
99 typename AllEntities,
100 typename Parameters,
101 bool IsPermutation>
102void _accumulate_logderivative_subrelation_contributions(ContainerOverSubrelations& accumulator,
103 const AllEntities& in,
104 const Parameters& params,
105 const FF& scaling_factor)
106{
107 constexpr size_t NUM_LOOKUP_TERMS = Relation::NUM_LOOKUP_TERMS;
108 constexpr size_t NUM_TABLE_TERMS = Relation::NUM_TABLE_TERMS;
109
110 using Accumulator = typename std::tuple_element_t<0, ContainerOverSubrelations>;
111 using View = typename Accumulator::View;
112
113 auto lookup_inverses = View(Relation::get_inverse_polynomial(in));
114
115 constexpr size_t NUM_TOTAL_TERMS = NUM_LOOKUP_TERMS + NUM_TABLE_TERMS;
117 std::array<Accumulator, NUM_TOTAL_TERMS> denominator_accumulator;
118
119 // The inverse polynomial gives us the product of all the inverses, i.e.
120 // lookup_inverse = \prod_j (1 / lookup_term[j]) * \prod_k (1 / table_term[k])
121 // To obtain the inverses 1 / lookup_term[i], 1 / table_term[i], we multiply lookup_inverse by the product of all
122 // terms except the one we want to invert. We perform this calculation via the following algorithm:
123 // 1) Compute the successive products of all lookup terms and table terms
124 // 2) Check that lookup_inverse is the inverse of the full product
125 // 3) Iteratively compute the inverses as follows:
126 // (lookup_term_1 * .. * lookup_term_(i-1)) * lookup_inverse * (lookup_term_(i+1) * .. * table_term_m)
127
128 // Collect all the terms in a single vector, first the lookup terms, then the table terms
129 bb::constexpr_for<0, NUM_LOOKUP_TERMS, 1>(
130 [&]<size_t i>() { lookup_terms[i] = Relation::template compute_lookup_term<Accumulator, i>(in, params); });
131 bb::constexpr_for<0, NUM_TABLE_TERMS, 1>([&]<size_t i>() {
132 lookup_terms[i + NUM_LOOKUP_TERMS] = Relation::template compute_table_term<Accumulator, i>(in, params);
133 });
134
135 // 1) Construct the successive products
136 bb::constexpr_for<0, NUM_TOTAL_TERMS, 1>([&]<size_t i>() { denominator_accumulator[i] = lookup_terms[i]; });
137 bb::constexpr_for<0, NUM_TOTAL_TERMS - 1, 1>(
138 [&]<size_t i>() { denominator_accumulator[i + 1] *= denominator_accumulator[i]; });
139
140 // 2) First subrelation: check that lookup_inverse is the inverse of the cumulative product if inverse_exists = 1
141 auto inverse_accumulator = Accumulator(lookup_inverses);
142 const auto inverse_exists = Relation::template compute_inverse_exists<Accumulator>(in);
143
144 std::get<0>(accumulator) +=
145 (denominator_accumulator[NUM_TOTAL_TERMS - 1] * lookup_inverses - inverse_exists) * scaling_factor;
146
147 // 3) Iteratively compute the single inverses
148 for (size_t i = NUM_TOTAL_TERMS - 1; i > 0; --i) {
149 // Take the cumulative product up to the previous index and multiply by the current inverse accumulator
150 denominator_accumulator[i] = denominator_accumulator[i - 1] * inverse_accumulator;
151 // Multiply the inverse accumulator by the current term to remove it from the product of the inverses
152 inverse_accumulator = inverse_accumulator * lookup_terms[i];
153 }
154 // Inverse accumulator is now equal to the inverse of the first lookup term
155 denominator_accumulator[0] = inverse_accumulator;
156
157 // Second subrelation
158 bb::constexpr_for<0, NUM_LOOKUP_TERMS, 1>([&]<size_t i>() {
159 std::get<1>(accumulator) +=
160 Relation::template get_lookup_term_predicate<Accumulator, i>(in) * denominator_accumulator[i];
161 });
162
163 bb::constexpr_for<0, NUM_TABLE_TERMS, 1>([&]<size_t i>() {
164 auto to_subtract = Relation::template get_table_term_predicate<Accumulator, i>(in) *
165 denominator_accumulator[i + NUM_LOOKUP_TERMS];
166 if constexpr (!IsPermutation) {
167 // If not a permutation, multiply by the read count
168 to_subtract *= Relation::template lookup_read_counts<Accumulator, i>(in);
169 }
170 std::get<1>(accumulator) -= to_subtract;
171 });
172}
173} // namespace bb
bb::field< bb::Bn254FrParams > FF
Definition field.cpp:24
std::tuple_element_t< 0, SumcheckArrayOfValuesOverSubrelations > ValueAccumulator0
ssize_t offset
Definition engine.cpp:52
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
void _accumulate_logderivative_subrelation_contributions(ContainerOverSubrelations &accumulator, const AllEntities &in, const Parameters &params, const FF &scaling_factor)
Unified implementation of log-derivative subrelation accumulation.
void compute_logderivative_inverse(Polynomials &polynomials, auto &relation_parameters, const size_t circuit_size)
Compute the inverse polynomial I(X) required for logderivative lookups.
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.