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: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
5// =====================
6
7#pragma once
8
12
13#include <span>
14#include <typeinfo>
15
16namespace bb {
17
39template <typename FF, typename Relation, typename Polynomials, bool UseMultithreading = false>
40void compute_logderivative_inverse(Polynomials& polynomials, auto& relation_parameters, const size_t circuit_size)
41{
42 using Accumulator = typename Relation::ValueAccumulator0;
43 constexpr size_t READ_TERMS = Relation::READ_TERMS;
44 constexpr size_t WRITE_TERMS = Relation::WRITE_TERMS;
45
46 auto& inverse_polynomial = Relation::get_inverse_polynomial(polynomials);
47 const size_t offset = inverse_polynomial.start_index();
48 const auto compute_inverses = [&](size_t start, size_t end) {
49 for (size_t i = start; i < end; ++i) {
50 // TODO(https://github.com/AztecProtocol/barretenberg/issues/940): avoid get_row if possible.
51 auto row = polynomials.get_row(i + offset);
52 bool has_inverse = Relation::operation_exists_at_row(row);
53 if (!has_inverse) {
54 continue;
55 }
56 FF denominator = 1;
57 bb::constexpr_for<0, READ_TERMS, 1>([&]<size_t read_index> {
58 auto denominator_term =
59 Relation::template compute_read_term<Accumulator, read_index>(row, relation_parameters);
60 denominator *= denominator_term;
61 });
62 bb::constexpr_for<0, WRITE_TERMS, 1>([&]<size_t write_index> {
63 auto denominator_term =
64 Relation::template compute_write_term<Accumulator, write_index>(row, relation_parameters);
65 denominator *= denominator_term;
66 });
67 inverse_polynomial.at(i) = denominator;
68 }
69 FF* ffstart = &inverse_polynomial.coeffs()[start];
70 std::span<FF> to_invert(ffstart, end - start);
71 // Compute inverse polynomial I in place by inverting the product at each row
72 // Note: zeroes are ignored as they are not used anyway
73 FF::batch_invert(to_invert);
74 };
75 if constexpr (UseMultithreading) {
76 const size_t min_iterations_per_thread = 128;
77 size_t num_threads = bb::calculate_num_threads_pow2(inverse_polynomial.size(), min_iterations_per_thread);
78 const size_t rows_per_thread = inverse_polynomial.size() / num_threads;
79 parallel_for(num_threads, [&](size_t thread_idx) {
80 const size_t start = thread_idx * rows_per_thread;
81 const size_t end = (thread_idx == num_threads - 1) ? circuit_size : (thread_idx + 1) * rows_per_thread;
82 compute_inverses(start, end);
83 });
84 } else {
85 {
86 compute_inverses(0, inverse_polynomial.size());
87 }
88 }
89}
90
118template <typename FF, typename Relation, typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
119void accumulate_logderivative_lookup_subrelation_contributions(ContainerOverSubrelations& accumulator,
120 const AllEntities& in,
121 const Parameters& params,
122 const FF& scaling_factor)
123{
124 constexpr size_t READ_TERMS = Relation::READ_TERMS;
125 constexpr size_t WRITE_TERMS = Relation::WRITE_TERMS;
126
127 using Accumulator = typename std::tuple_element_t<0, ContainerOverSubrelations>;
128 using View = typename Accumulator::View;
129
130 auto lookup_inverses = View(Relation::get_inverse_polynomial(in));
131
132 constexpr size_t NUM_TOTAL_TERMS = READ_TERMS + WRITE_TERMS;
134 std::array<Accumulator, NUM_TOTAL_TERMS> denominator_accumulator;
135
136 // The lookup relation = \sum_j (1 / read_term[j]) - \sum_k (read_counts[k] / write_term[k])
137 // To get the inverses (1 / read_term[i]), (1 / write_term[i]), we have a commitment to the product of all inverses
138 // i.e. lookup_inverse = \prod_j (1 / read_term[j]) * \prod_k (1 / write_term[k])
139 // The purpose of this next section is to derive individual inverse terms using `lookup_inverses`
140 // i.e. (1 / read_term[i]) = lookup_inverse * \prod_{j /ne i} (read_term[j]) * \prod_k (write_term[k])
141 // (1 / write_term[i]) = lookup_inverse * \prod_j (read_term[j]) * \prod_{k ne i} (write_term[k])
142 bb::constexpr_for<0, READ_TERMS, 1>(
143 [&]<size_t i>() { lookup_terms[i] = Relation::template compute_read_term<Accumulator, i>(in, params); });
144 bb::constexpr_for<0, WRITE_TERMS, 1>([&]<size_t i>() {
145 lookup_terms[i + READ_TERMS] = Relation::template compute_write_term<Accumulator, i>(in, params);
146 });
147
148 bb::constexpr_for<0, NUM_TOTAL_TERMS, 1>([&]<size_t i>() { denominator_accumulator[i] = lookup_terms[i]; });
149
150 bb::constexpr_for<0, NUM_TOTAL_TERMS - 1, 1>(
151 [&]<size_t i>() { denominator_accumulator[i + 1] *= denominator_accumulator[i]; });
152
153 auto inverse_accumulator = Accumulator(lookup_inverses); // denominator_accumulator[NUM_TOTAL_TERMS - 1];
154
155 const auto inverse_exists = Relation::template compute_inverse_exists<Accumulator>(in);
156
157 // Note: the lookup_inverses are computed so that the value is 0 if !inverse_exists
158 std::get<0>(accumulator) +=
159 (denominator_accumulator[NUM_TOTAL_TERMS - 1] * lookup_inverses - inverse_exists) * scaling_factor;
160
161 // After this algo, total degree of denominator_accumulator = NUM_TOTAL_TERMS
162 for (size_t i = 0; i < NUM_TOTAL_TERMS - 1; ++i) {
163 denominator_accumulator[NUM_TOTAL_TERMS - 1 - i] =
164 denominator_accumulator[NUM_TOTAL_TERMS - 2 - i] * inverse_accumulator;
165 inverse_accumulator = inverse_accumulator * lookup_terms[NUM_TOTAL_TERMS - 1 - i];
166 }
167 denominator_accumulator[0] = inverse_accumulator;
168
169 // each predicate is degree-1
170 // degree of relation at this point = NUM_TOTAL_TERMS + 1
171 bb::constexpr_for<0, READ_TERMS, 1>([&]<size_t i>() {
172 std::get<1>(accumulator) +=
173 Relation::template compute_read_term_predicate<Accumulator, i>(in) * denominator_accumulator[i];
174 });
175
176 // each predicate is degree-1, `lookup_read_counts` is degree-1
177 // degree of relation = NUM_TOTAL_TERMS + 2
178 bb::constexpr_for<0, WRITE_TERMS, 1>([&]<size_t i>() {
179 const auto p = Relation::template compute_write_term_predicate<Accumulator, i>(in);
180 const auto lookup_read_count = Relation::template lookup_read_counts<Accumulator, i>(in);
181 std::get<1>(accumulator) -= p * (denominator_accumulator[i + READ_TERMS] * lookup_read_count);
182 });
183}
184
214template <typename FF, typename Relation, typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
215void accumulate_logderivative_permutation_subrelation_contributions(ContainerOverSubrelations& accumulator,
216 const AllEntities& in,
217 const Parameters& params,
218 const FF& scaling_factor)
219{
220 constexpr size_t READ_TERMS = Relation::READ_TERMS;
221 constexpr size_t WRITE_TERMS = Relation::WRITE_TERMS;
222
223 // For now we only do simple permutations over tuples with 1 read and 1 write term
224 static_assert(READ_TERMS == 1);
225 static_assert(WRITE_TERMS == 1);
226
227 using Accumulator = typename std::tuple_element_t<0, ContainerOverSubrelations>;
228 using View = typename Accumulator::View;
229
230 auto permutation_inverses = View(Relation::get_inverse_polynomial(in));
231
232 constexpr size_t NUM_TOTAL_TERMS = 2;
234 std::array<Accumulator, NUM_TOTAL_TERMS> denominator_accumulator;
235
236 // The permutation relation = 1 / read_term - 1 / write_term
237 // To get the inverses (1 / read_term), (1 / write_term), we have a commitment to the product ofinver ses
238 // i.e. permutation_inverses = (1 / read_term) * (1 / write_term)
239 // The purpose of this next section is to derive individual inverse terms using `permutation_inverses`
240 // i.e. (1 / read_term) = permutation_inverses * write_term
241 // (1 / write_term) = permutation_inverses * read_term
242 permutation_terms[0] = Relation::template compute_read_term<Accumulator, 0>(in, params);
243 permutation_terms[1] = Relation::template compute_write_term<Accumulator, 0>(in, params);
244
245 bb::constexpr_for<0, NUM_TOTAL_TERMS, 1>([&]<size_t i>() { denominator_accumulator[i] = permutation_terms[i]; });
246
247 bb::constexpr_for<0, NUM_TOTAL_TERMS - 1, 1>(
248 [&]<size_t i>() { denominator_accumulator[i + 1] *= denominator_accumulator[i]; });
249
250 auto inverse_accumulator = Accumulator(permutation_inverses); // denominator_accumulator[NUM_TOTAL_TERMS - 1];
251
252 const auto inverse_exists = Relation::template compute_inverse_exists<Accumulator>(in);
253
254 // Note: the lookup_inverses are computed so that the value is 0 if !inverse_exists
255 std::get<0>(accumulator) +=
256 (denominator_accumulator[NUM_TOTAL_TERMS - 1] * permutation_inverses - inverse_exists) * scaling_factor;
257
258 // After this algo, total degree of denominator_accumulator = NUM_TOTAL_TERMS
259 for (size_t i = 0; i < NUM_TOTAL_TERMS - 1; ++i) {
260 denominator_accumulator[NUM_TOTAL_TERMS - 1 - i] =
261 denominator_accumulator[NUM_TOTAL_TERMS - 2 - i] * inverse_accumulator;
262 inverse_accumulator = inverse_accumulator * permutation_terms[NUM_TOTAL_TERMS - 1 - i];
263 }
264 denominator_accumulator[0] = inverse_accumulator;
265
266 // each predicate is degree-1
267 // degree of relation at this point = NUM_TOTAL_TERMS + 1
268 std::get<1>(accumulator) +=
269 Relation::template compute_read_term_predicate<Accumulator, 0>(in) * denominator_accumulator[0];
270
271 // each predicate is degree-1
272 // degree of relation = NUM_TOTAL_TERMS + 1
273 std::get<1>(accumulator) -=
274 Relation::template compute_write_term_predicate<Accumulator, 0>(in) * denominator_accumulator[1];
275}
276
277} // namespace bb
std::tuple_element_t< 0, SumcheckArrayOfValuesOverSubrelations > ValueAccumulator0
ssize_t offset
Definition engine.cpp:36
Entry point for Barretenberg command-line interface.
void accumulate_logderivative_lookup_subrelation_contributions(ContainerOverSubrelations &accumulator, const AllEntities &in, const Parameters &params, const FF &scaling_factor)
Compute generic log-derivative lookup subrelation accumulation.
typename Flavor::FF FF
void compute_logderivative_inverse(Polynomials &polynomials, auto &relation_parameters, const size_t circuit_size)
Compute the inverse polynomial I(X) required for logderivative lookupsdetails Inverse may be defined ...
void accumulate_logderivative_permutation_subrelation_contributions(ContainerOverSubrelations &accumulator, const AllEntities &in, const Parameters &params, const FF &scaling_factor)
Compute generic log-derivative set permutation subrelation accumulation.
constexpr void constexpr_for(F &&f)
Implements a loop using a compile-time iterator. Requires c++20. Implementation (and description) fro...
size_t calculate_num_threads_pow2(size_t num_iterations, size_t min_iterations_per_thread)
calculates number of threads to create based on minimum iterations per thread, guaranteed power of 2
Definition thread.cpp:215
void parallel_for(size_t num_iterations, const std::function< void(size_t)> &func)
Definition thread.cpp:72
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static void batch_invert(std::span< field > coeffs) noexcept