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 compute_inverses(0, inverse_polynomial.size());
86 }
87}
88
116template <typename FF, typename Relation, typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
117void accumulate_logderivative_lookup_subrelation_contributions(ContainerOverSubrelations& accumulator,
118 const AllEntities& in,
119 const Parameters& params,
120 const FF& scaling_factor)
121{
122 constexpr size_t READ_TERMS = Relation::READ_TERMS;
123 constexpr size_t WRITE_TERMS = Relation::WRITE_TERMS;
124
125 using Accumulator = typename std::tuple_element_t<0, ContainerOverSubrelations>;
126 using View = typename Accumulator::View;
127
128 auto lookup_inverses = View(Relation::get_inverse_polynomial(in));
129
130 constexpr size_t NUM_TOTAL_TERMS = READ_TERMS + WRITE_TERMS;
132 std::array<Accumulator, NUM_TOTAL_TERMS> denominator_accumulator;
133
134 // The lookup relation = \sum_j (1 / read_term[j]) - \sum_k (read_counts[k] / write_term[k])
135 // To get the inverses (1 / read_term[i]), (1 / write_term[i]), we have a commitment to the product of all inverses
136 // i.e. lookup_inverse = \prod_j (1 / read_term[j]) * \prod_k (1 / write_term[k])
137 // The purpose of this next section is to derive individual inverse terms using `lookup_inverses`
138 // i.e. (1 / read_term[i]) = lookup_inverse * \prod_{j /ne i} (read_term[j]) * \prod_k (write_term[k])
139 // (1 / write_term[i]) = lookup_inverse * \prod_j (read_term[j]) * \prod_{k ne i} (write_term[k])
140 bb::constexpr_for<0, READ_TERMS, 1>(
141 [&]<size_t i>() { lookup_terms[i] = Relation::template compute_read_term<Accumulator, i>(in, params); });
142 bb::constexpr_for<0, WRITE_TERMS, 1>([&]<size_t i>() {
143 lookup_terms[i + READ_TERMS] = Relation::template compute_write_term<Accumulator, i>(in, params);
144 });
145
146 bb::constexpr_for<0, NUM_TOTAL_TERMS, 1>([&]<size_t i>() { denominator_accumulator[i] = lookup_terms[i]; });
147
148 bb::constexpr_for<0, NUM_TOTAL_TERMS - 1, 1>(
149 [&]<size_t i>() { denominator_accumulator[i + 1] *= denominator_accumulator[i]; });
150
151 auto inverse_accumulator = Accumulator(lookup_inverses); // denominator_accumulator[NUM_TOTAL_TERMS - 1];
152
153 const auto inverse_exists = Relation::template compute_inverse_exists<Accumulator>(in);
154
155 // Note: the lookup_inverses are computed so that the value is 0 if !inverse_exists
156 std::get<0>(accumulator) +=
157 (denominator_accumulator[NUM_TOTAL_TERMS - 1] * lookup_inverses - inverse_exists) * scaling_factor;
158
159 // After this algo, total degree of denominator_accumulator = NUM_TOTAL_TERMS
160 for (size_t i = 0; i < NUM_TOTAL_TERMS - 1; ++i) {
161 denominator_accumulator[NUM_TOTAL_TERMS - 1 - i] =
162 denominator_accumulator[NUM_TOTAL_TERMS - 2 - i] * inverse_accumulator;
163 inverse_accumulator = inverse_accumulator * lookup_terms[NUM_TOTAL_TERMS - 1 - i];
164 }
165 denominator_accumulator[0] = inverse_accumulator;
166
167 // each predicate is degree-1
168 // degree of relation at this point = NUM_TOTAL_TERMS + 1
169 bb::constexpr_for<0, READ_TERMS, 1>([&]<size_t i>() {
170 std::get<1>(accumulator) +=
171 Relation::template compute_read_term_predicate<Accumulator, i>(in) * denominator_accumulator[i];
172 });
173
174 // each predicate is degree-1, `lookup_read_counts` is degree-1
175 // degree of relation = NUM_TOTAL_TERMS + 2
176 bb::constexpr_for<0, WRITE_TERMS, 1>([&]<size_t i>() {
177 const auto p = Relation::template compute_write_term_predicate<Accumulator, i>(in);
178 const auto lookup_read_count = Relation::template lookup_read_counts<Accumulator, i>(in);
179 std::get<1>(accumulator) -= p * (denominator_accumulator[i + READ_TERMS] * lookup_read_count);
180 });
181}
182
212template <typename FF, typename Relation, typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
213void accumulate_logderivative_permutation_subrelation_contributions(ContainerOverSubrelations& accumulator,
214 const AllEntities& in,
215 const Parameters& params,
216 const FF& scaling_factor)
217{
218 constexpr size_t READ_TERMS = Relation::READ_TERMS;
219 constexpr size_t WRITE_TERMS = Relation::WRITE_TERMS;
220
221 // For now we only do simple permutations over tuples with 1 read and 1 write term
222 static_assert(READ_TERMS == 1);
223 static_assert(WRITE_TERMS == 1);
224
225 using Accumulator = typename std::tuple_element_t<0, ContainerOverSubrelations>;
226 using View = typename Accumulator::View;
227
228 auto permutation_inverses = View(Relation::get_inverse_polynomial(in));
229
230 constexpr size_t NUM_TOTAL_TERMS = 2;
232 std::array<Accumulator, NUM_TOTAL_TERMS> denominator_accumulator;
233
234 // The permutation relation = 1 / read_term - 1 / write_term
235 // To get the inverses (1 / read_term), (1 / write_term), we have a commitment to the product ofinver ses
236 // i.e. permutation_inverses = (1 / read_term) * (1 / write_term)
237 // The purpose of this next section is to derive individual inverse terms using `permutation_inverses`
238 // i.e. (1 / read_term) = permutation_inverses * write_term
239 // (1 / write_term) = permutation_inverses * read_term
240 permutation_terms[0] = Relation::template compute_read_term<Accumulator, 0>(in, params);
241 permutation_terms[1] = Relation::template compute_write_term<Accumulator, 0>(in, params);
242
243 bb::constexpr_for<0, NUM_TOTAL_TERMS, 1>([&]<size_t i>() { denominator_accumulator[i] = permutation_terms[i]; });
244
245 bb::constexpr_for<0, NUM_TOTAL_TERMS - 1, 1>(
246 [&]<size_t i>() { denominator_accumulator[i + 1] *= denominator_accumulator[i]; });
247
248 auto inverse_accumulator = Accumulator(permutation_inverses); // denominator_accumulator[NUM_TOTAL_TERMS - 1];
249
250 const auto inverse_exists = Relation::template compute_inverse_exists<Accumulator>(in);
251
252 // Note: the lookup_inverses are computed so that the value is 0 if !inverse_exists
253 std::get<0>(accumulator) +=
254 (denominator_accumulator[NUM_TOTAL_TERMS - 1] * permutation_inverses - inverse_exists) * scaling_factor;
255
256 // After this algo, total degree of denominator_accumulator = NUM_TOTAL_TERMS
257 for (size_t i = 0; i < NUM_TOTAL_TERMS - 1; ++i) {
258 denominator_accumulator[NUM_TOTAL_TERMS - 1 - i] =
259 denominator_accumulator[NUM_TOTAL_TERMS - 2 - i] * inverse_accumulator;
260 inverse_accumulator = inverse_accumulator * permutation_terms[NUM_TOTAL_TERMS - 1 - i];
261 }
262 denominator_accumulator[0] = inverse_accumulator;
263
264 // each predicate is degree-1
265 // degree of relation at this point = NUM_TOTAL_TERMS + 1
266 std::get<1>(accumulator) +=
267 Relation::template compute_read_term_predicate<Accumulator, 0>(in) * denominator_accumulator[0];
268
269 // each predicate is degree-1
270 // degree of relation = NUM_TOTAL_TERMS + 1
271 std::get<1>(accumulator) -=
272 Relation::template compute_write_term_predicate<Accumulator, 0>(in) * denominator_accumulator[1];
273}
274
275} // 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:254
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
static void batch_invert(C &coeffs) noexcept