Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
polynomial.cpp
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#include "polynomial.hpp"
16#include <cstddef>
17#include <fcntl.h>
18#include <list>
19#include <memory>
20#include <mutex>
21#include <span>
22#include <sys/stat.h>
23#include <unordered_map>
24#include <utility>
25
26namespace bb {
27
28// Note: This function is pretty gnarly, but we try to make it the only function that deals
29// with copying polynomials. It should be scrutinized thusly.
30template <typename Fr>
32 size_t right_expansion = 0,
33 size_t left_expansion = 0)
34{
35 size_t expanded_size = array.size() + right_expansion + left_expansion;
36 BackingMemory<Fr> backing_clone = BackingMemory<Fr>::allocate(expanded_size);
37 // zero any left extensions to the array
38 memset(static_cast<void*>(backing_clone.raw_data), 0, sizeof(Fr) * left_expansion);
39 // copy our cloned array over
40 memcpy(static_cast<void*>(backing_clone.raw_data + left_expansion),
41 static_cast<const void*>(array.data()),
42 sizeof(Fr) * array.size());
43 // zero any right extensions to the array
44 memset(static_cast<void*>(backing_clone.raw_data + left_expansion + array.size()), 0, sizeof(Fr) * right_expansion);
45 return {
46 array.start_ - left_expansion, array.end_ + right_expansion, array.virtual_size_, std::move(backing_clone)
47 };
48}
49
50template <typename Fr>
51void Polynomial<Fr>::allocate_backing_memory(size_t size, size_t virtual_size, size_t start_index)
52{
53 BB_BENCH_NAME("Polynomial::allocate_backing_memory");
54 BB_ASSERT_LTE(start_index + size, virtual_size);
56 start_index, /* start index, used for shifted polynomials and offset 'islands' of non-zeroes */
57 size + start_index, /* end index, actual memory used is (end - start) */
58 virtual_size, /* virtual size, i.e. until what size do we conceptually have zeroes */
60 };
61}
62
72template <typename Fr> Polynomial<Fr>::Polynomial(size_t size, size_t virtual_size, size_t start_index)
73{
74 BB_BENCH_NAME("Polynomial::Polynomial(size_t, size_t, size_t)");
75 allocate_backing_memory(size, virtual_size, start_index);
76
77 parallel_for([&](const ThreadChunk& chunk) {
78 auto range = chunk.range(size);
79 if (!range.empty()) {
80 size_t start = *range.begin();
81 size_t range_size = range.size();
82 BB_ASSERT(start < size || size == 0);
83 BB_ASSERT_LTE((start + range_size), size);
84 memset(static_cast<void*>(coefficients_.data() + start), 0, sizeof(Fr) * range_size);
85 }
86 });
87}
88
96template <typename Fr>
97Polynomial<Fr>::Polynomial(size_t size, size_t virtual_size, size_t start_index, [[maybe_unused]] DontZeroMemory flag)
99 allocate_backing_memory(size, virtual_size, start_index);
100}
101
102template <typename Fr>
104 : Polynomial<Fr>(other, other.size())
105{}
106
107// fully copying "expensive" constructor
108template <typename Fr> Polynomial<Fr>::Polynomial(const Polynomial<Fr>& other, const size_t target_size)
109{
110 BB_ASSERT_LTE(other.size(), target_size);
111 coefficients_ = _clone(other.coefficients_, target_size - other.size());
112}
113
114// interpolation constructor
115template <typename Fr>
117 std::span<const Fr> evaluations,
118 size_t virtual_size)
119 : Polynomial(interpolation_points.size(), virtual_size)
120{
121 BB_ASSERT_GT(coefficients_.size(), static_cast<size_t>(0));
122
124 evaluations.data(), coefficients_.data(), interpolation_points.data(), coefficients_.size());
125}
126
127template <typename Fr> Polynomial<Fr>::Polynomial(std::span<const Fr> coefficients, size_t virtual_size)
129 allocate_backing_memory(coefficients.size(), virtual_size, 0);
130
131 memcpy(static_cast<void*>(data()), static_cast<const void*>(coefficients.data()), sizeof(Fr) * coefficients.size());
132}
133
134// Assignments
135
136// full copy "expensive" assignment
137template <typename Fr> Polynomial<Fr>& Polynomial<Fr>::operator=(const Polynomial<Fr>& other)
139 if (this == &other) {
140 return *this;
141 }
142 coefficients_ = _clone(other.coefficients_);
143 return *this;
144}
145
146template <typename Fr> Polynomial<Fr> Polynomial<Fr>::share() const
147{
148 Polynomial p;
149 p.coefficients_ = coefficients_;
150 return p;
151}
152
153template <typename Fr> bool Polynomial<Fr>::operator==(Polynomial const& rhs) const
154{
155 // If either is empty, both must be
156 if (is_empty() || rhs.is_empty()) {
157 return is_empty() && rhs.is_empty();
158 }
159 // Size must agree
160 if (virtual_size() != rhs.virtual_size()) {
161 return false;
162 }
163 // Each coefficient must agree
164 for (size_t i = std::min(coefficients_.start_, rhs.coefficients_.start_);
165 i < std::max(coefficients_.end_, rhs.coefficients_.end_);
166 i++) {
167 if (coefficients_.get(i) != rhs.coefficients_.get(i)) {
168 return false;
169 }
170 }
171 return true;
172}
173
175{
176 BB_ASSERT_LTE(start_index(), other.start_index);
177 BB_ASSERT_GTE(end_index(), other.end_index());
178 parallel_for([&](const ThreadChunk& chunk) {
179 for (size_t offset : chunk.range(other.size())) {
180 size_t i = offset + other.start_index;
181 at(i) += other[i];
182 }
183 });
184 return *this;
185}
186
187template <typename Fr> Fr Polynomial<Fr>::evaluate(const Fr& z, const size_t target_size) const
188{
189 BB_ASSERT(size() == virtual_size());
190 return polynomial_arithmetic::evaluate(data(), z, target_size);
191}
192
193template <typename Fr> Fr Polynomial<Fr>::evaluate(const Fr& z) const
194{
195 BB_ASSERT(size() == virtual_size());
196 return polynomial_arithmetic::evaluate(data(), z, size());
197}
198
199template <typename Fr> Fr Polynomial<Fr>::evaluate_mle(std::span<const Fr> evaluation_points, bool shift) const
200{
201 return _evaluate_mle(evaluation_points, coefficients_, shift);
202}
203
204template <typename Fr>
210
212{
213 BB_ASSERT_LTE(start_index(), other.start_index);
214 BB_ASSERT_GTE(end_index(), other.end_index());
215 parallel_for([&](const ThreadChunk& chunk) {
216 for (size_t offset : chunk.range(other.size())) {
217 size_t i = offset + other.start_index;
218 at(i) -= other[i];
219 }
220 });
221 return *this;
222}
223
224template <typename Fr> Polynomial<Fr>& Polynomial<Fr>::operator*=(const Fr scaling_factor)
225{
226 parallel_for([scaling_factor, this](const ThreadChunk& chunk) { multiply_chunk(chunk, scaling_factor); });
227 return *this;
228}
229
230template <typename Fr> void Polynomial<Fr>::multiply_chunk(const ThreadChunk& chunk, const Fr scaling_factor)
231{
232 for (size_t i : chunk.range(size())) {
233 data()[i] *= scaling_factor;
234 }
236
237template <typename Fr> Polynomial<Fr> Polynomial<Fr>::create_non_parallel_zero_init(size_t size, size_t virtual_size)
238{
240 memset(static_cast<void*>(p.coefficients_.data()), 0, sizeof(Fr) * size);
241 return p;
242}
243
244template <typename Fr> void Polynomial<Fr>::shrink_end_index(const size_t new_end_index)
245{
246 BB_ASSERT_LTE(new_end_index, end_index());
247 coefficients_.end_ = new_end_index;
248}
249
250template <typename Fr> Polynomial<Fr> Polynomial<Fr>::full() const
252 Polynomial result = *this;
253 // Make 0..virtual_size usable
254 result.coefficients_ = _clone(coefficients_, virtual_size() - end_index(), start_index());
255 return result;
256}
257
258template <typename Fr> void Polynomial<Fr>::add_scaled(PolynomialSpan<const Fr> other, Fr scaling_factor) &
259{
260 BB_ASSERT_LTE(start_index(), other.start_index);
261 BB_ASSERT_GTE(end_index(), other.end_index());
263 [&other, scaling_factor, this](const ThreadChunk& chunk) { add_scaled_chunk(chunk, other, scaling_factor); });
264}
265
266template <typename Fr>
268{
269 // Iterate over the chunk of the other polynomial's range
270 for (size_t offset : chunk.range(other.size())) {
271 size_t index = other.start_index + offset;
272 at(index) += scaling_factor * other[index];
273 }
274}
275
276template <typename Fr> Polynomial<Fr> Polynomial<Fr>::shifted() const
277{
278 BB_ASSERT_GTE(coefficients_.start_, static_cast<size_t>(1));
279 Polynomial result;
280 result.coefficients_ = coefficients_;
281 result.coefficients_.start_ -= 1;
282 result.coefficients_.end_ -= 1;
283 return result;
284}
285
286template <typename Fr> Polynomial<Fr> Polynomial<Fr>::right_shifted(const size_t magnitude) const
287{
288 // ensure that at least the last magnitude-many coefficients are virtual 0's
289 BB_ASSERT_LTE((coefficients_.end_ + magnitude), virtual_size());
290 Polynomial result;
291 result.coefficients_ = coefficients_;
292 result.coefficients_.start_ += magnitude;
293 result.coefficients_.end_ += magnitude;
294 return result;
295}
296
297template <typename Fr> Polynomial<Fr> Polynomial<Fr>::reverse() const
298{
299 const size_t end_index = this->end_index();
300 const size_t start_index = this->start_index();
301 const size_t poly_size = this->size();
302 Polynomial reversed(/*size=*/poly_size, /*virtual_size=*/end_index);
303 for (size_t idx = end_index; idx > start_index; --idx) {
304 reversed.at(end_index - idx) = this->at(idx - 1);
305 }
306 return reversed;
307}
308
309template class Polynomial<bb::fr>;
310template class Polynomial<grumpkin::fr>;
311} // namespace bb
#define BB_ASSERT(expression,...)
Definition assert.hpp:67
#define BB_ASSERT_GTE(left, right,...)
Definition assert.hpp:122
#define BB_ASSERT_GT(left, right,...)
Definition assert.hpp:107
#define BB_ASSERT_LTE(left, right,...)
Definition assert.hpp:152
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:219
Structured polynomial class that represents the coefficients 'a' of a_0 + a_1 x .....
Polynomial & operator=(Polynomial &&other) noexcept=default
Polynomial shifted() const
Returns a Polynomial the left-shift of self.
Polynomial & operator*=(Fr scaling_factor)
sets this = p(X) to s⋅p(X)
bool is_empty() const
Polynomial()=default
std::size_t virtual_size() const
Fr evaluate(const Fr &z, size_t target_size) const
SharedShiftedVirtualZeroesArray< Fr > coefficients_
void multiply_chunk(const ThreadChunk &chunk, Fr scaling_factor)
Fr evaluate_mle(std::span< const Fr > evaluation_points, bool shift=false) const
evaluate multi-linear extension p(X_0,…,X_{n-1}) = \sum_i a_i*L_i(X_0,…,X_{n-1}) at u = (u_0,...
const Fr & get(size_t i, size_t virtual_padding=0) const
Retrieves the value at the specified index.
Polynomial & operator-=(PolynomialSpan< const Fr > other)
subtracts the polynomial q(X) 'other'.
Polynomial share() const
Polynomial reverse() const
Returns the polynomial equal to the reverse of self.
Polynomial right_shifted(const size_t magnitude) const
Returns a Polynomial equal to the right-shift-by-magnitude of self.
Fr compute_barycentric_evaluation(const Fr &z, const EvaluationDomain< Fr > &domain)
Fr & at(size_t index)
Our mutable accessor, unlike operator[]. We abuse precedent a bit to differentiate at() and operator[...
void add_scaled(PolynomialSpan< const Fr > other, Fr scaling_factor) &
adds the polynomial q(X) 'other', multiplied by a scaling factor.
bool operator==(Polynomial const &rhs) const
void shrink_end_index(const size_t new_end_index)
The end_index of the polynomial is decreased without any memory de-allocation. This is a very fast wa...
Polynomial & operator+=(PolynomialSpan< const Fr > other)
adds the polynomial q(X) 'other'.
void add_scaled_chunk(const ThreadChunk &chunk, PolynomialSpan< const Fr > other, Fr scaling_factor) &
static Polynomial create_non_parallel_zero_init(size_t size, size_t virtual_size)
A factory to construct a polynomial where parallel initialization is not possible (e....
void allocate_backing_memory(size_t size, size_t virtual_size, size_t start_index)
Polynomial full() const
Copys the polynomial, but with the whole address space usable. The value of the polynomial remains th...
const std::vector< MemoryValue > data
ssize_t offset
Definition engine.cpp:36
Fr evaluate(const Fr *coeffs, const Fr &z, const size_t n)
fr compute_barycentric_evaluation(const fr *coeffs, const size_t num_coeffs, const fr &z, const EvaluationDomain< fr > &domain)
void compute_efficient_interpolation(const Fr *src, Fr *dest, const Fr *evaluation_points, const size_t n)
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
SharedShiftedVirtualZeroesArray< Fr > _clone(const SharedShiftedVirtualZeroesArray< Fr > &array, size_t right_expansion=0, size_t left_expansion=0)
Fr_ _evaluate_mle(std::span< const Fr_ > evaluation_points, const SharedShiftedVirtualZeroesArray< Fr_ > &coefficients, bool shift)
Internal implementation to support both native and stdlib circuit field types.
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 BackingMemory allocate(size_t size)
A shared pointer array template that represents a virtual array filled with zeros up to virtual_size_...
size_t start_
The starting index of the memory-backed range.
T * data()
Returns a pointer to the underlying memory array. NOTE: This should be used with care,...
size_t virtual_size_
The total logical size of the array.
size_t end_
The ending index of the memory-backed range.
size_t size() const
size_t end_index() const
auto range(size_t size, size_t offset=0) const
Definition thread.hpp:161