barretenberg
Loading...
Searching...
No Matches
univariate.hpp
1#pragma once
2#include "barretenberg/common/assert.hpp"
3#include "barretenberg/common/serialize.hpp"
4#include "barretenberg/polynomials/barycentric.hpp"
5#include <span>
6
7namespace barretenberg {
8
16template <class Fr, size_t view_domain_end, size_t view_domain_start> class UnivariateView;
17
23template <class Fr, size_t domain_end, size_t domain_start = 0> class Univariate {
24 public:
25 static constexpr size_t LENGTH = domain_end - domain_start;
27
28 // TODO(https://github.com/AztecProtocol/barretenberg/issues/714) Try out std::valarray?
29 std::array<Fr, LENGTH> evaluations;
30
31 Univariate() = default;
32
33 explicit Univariate(std::array<Fr, LENGTH> evaluations)
34 : evaluations(evaluations)
35 {}
36 ~Univariate() = default;
37 Univariate(const Univariate& other) = default;
38 Univariate(Univariate&& other) noexcept = default;
39 Univariate& operator=(const Univariate& other) = default;
40 Univariate& operator=(Univariate&& other) noexcept = default;
41 // Construct constant Univariate from scalar which represents the value that all the points in the domain evaluate
42 // to
43 explicit Univariate(Fr value)
44 : evaluations{}
45 {
46 for (size_t i = 0; i < LENGTH; ++i) {
47 evaluations[i] = value;
48 }
49 }
50 // Construct Univariate from UnivariateView
52 : evaluations{}
53 {
54 for (size_t i = 0; i < in.evaluations.size(); ++i) {
55 evaluations[i] = in.evaluations[i];
56 }
57 }
58
59 Fr& value_at(size_t i) { return evaluations[i - domain_start]; };
60 const Fr& value_at(size_t i) const { return evaluations[i - domain_start]; };
61 size_t size() { return evaluations.size(); };
62
63 // Write the Univariate evaluations to a buffer
64 [[nodiscard]] std::vector<uint8_t> to_buffer() const { return ::to_buffer(evaluations); }
65
66 // Static method for creating a Univariate from a buffer
67 // IMPROVEMENT: Could be made to identically match equivalent methods in e.g. field.hpp. Currently bypasses
68 // unnecessary ::from_buffer call
69 static Univariate serialize_from_buffer(uint8_t const* buffer)
70 {
71 Univariate result;
72 std::read(buffer, result.evaluations);
73 return result;
74 }
75
76 static Univariate get_random()
77 {
79 for (size_t i = 0; i != LENGTH; ++i) {
80 output.value_at(i) = Fr::random_element();
81 }
82 return output;
83 };
84
85 static Univariate zero()
86 {
88 for (size_t i = 0; i != LENGTH; ++i) {
89 output.value_at(i) = Fr::zero();
90 }
91 return output;
92 }
93
94 static Univariate random_element() { return get_random(); };
95
96 // Operations between Univariate and other Univariate
97 bool operator==(const Univariate& other) const = default;
98
99 Univariate& operator+=(const Univariate& other)
100 {
101 for (size_t i = 0; i < LENGTH; ++i) {
102 evaluations[i] += other.evaluations[i];
103 }
104 return *this;
105 }
106 Univariate& operator-=(const Univariate& other)
107 {
108 for (size_t i = 0; i < LENGTH; ++i) {
109 evaluations[i] -= other.evaluations[i];
110 }
111 return *this;
112 }
113 Univariate& operator*=(const Univariate& other)
114 {
115 for (size_t i = 0; i < LENGTH; ++i) {
116 evaluations[i] *= other.evaluations[i];
117 }
118 return *this;
119 }
120 Univariate operator+(const Univariate& other) const
121 {
122 Univariate res(*this);
123 res += other;
124 return res;
125 }
126
127 Univariate operator-(const Univariate& other) const
128 {
129 Univariate res(*this);
130 res -= other;
131 return res;
132 }
133 Univariate operator-() const
134 {
135 Univariate res(*this);
136 for (auto& eval : res.evaluations) {
137 eval = -eval;
138 }
139 return res;
140 }
141
142 Univariate operator*(const Univariate& other) const
143 {
144 Univariate res(*this);
145 res *= other;
146 return res;
147 }
148
149 // Operations between Univariate and scalar
150 Univariate& operator+=(const Fr& scalar)
151 {
152 for (auto& eval : evaluations) {
153 eval += scalar;
154 }
155 return *this;
156 }
157
158 Univariate& operator-=(const Fr& scalar)
159 {
160 for (auto& eval : evaluations) {
161 eval -= scalar;
162 }
163 return *this;
164 }
165 Univariate& operator*=(const Fr& scalar)
166 {
167 for (auto& eval : evaluations) {
168 eval *= scalar;
169 }
170 return *this;
171 }
172
173 Univariate operator+(const Fr& scalar) const
174 {
175 Univariate res(*this);
176 res += scalar;
177 return res;
178 }
179
180 Univariate operator-(const Fr& scalar) const
181 {
182 Univariate res(*this);
183 res -= scalar;
184 return res;
185 }
186
187 Univariate operator*(const Fr& scalar) const
188 {
189 Univariate res(*this);
190 res *= scalar;
191 return res;
192 }
193
194 // Operations between Univariate and UnivariateView
196 {
197 for (size_t i = 0; i < LENGTH; ++i) {
198 evaluations[i] += view.evaluations[i];
199 }
200 return *this;
201 }
202
204 {
205 for (size_t i = 0; i < LENGTH; ++i) {
206 evaluations[i] -= view.evaluations[i];
207 }
208 return *this;
209 }
210
212 {
213 for (size_t i = 0; i < LENGTH; ++i) {
214 evaluations[i] *= view.evaluations[i];
215 }
216 return *this;
217 }
218
220 {
221 Univariate res(*this);
222 res += view;
223 return res;
224 }
225
227 {
228 Univariate res(*this);
229 res -= view;
230 return res;
231 }
232
234 {
235 Univariate res(*this);
236 res *= view;
237 return res;
238 }
239
240 // Output is immediately parsable as a list of integers by Python.
241 friend std::ostream& operator<<(std::ostream& os, const Univariate& u)
242 {
243 os << "[";
244 os << u.evaluations[0] << "," << std::endl;
245 for (size_t i = 1; i < u.evaluations.size(); i++) {
246 os << " " << u.evaluations[i];
247 if (i + 1 < u.evaluations.size()) {
248 os << "," << std::endl;
249 } else {
250 os << "]";
251 };
252 }
253 return os;
254 }
255
272 template <size_t EXTENDED_DOMAIN_END> Univariate<Fr, EXTENDED_DOMAIN_END> extend_to() const
273 {
274 const size_t EXTENDED_LENGTH = EXTENDED_DOMAIN_END - domain_start;
276 static_assert(EXTENDED_LENGTH >= LENGTH);
277
279
280 std::copy(evaluations.begin(), evaluations.end(), result.evaluations.begin());
281
282 if constexpr (LENGTH == 2) {
283 Fr delta = value_at(1) - value_at(0);
284 static_assert(EXTENDED_LENGTH != 0);
285 for (size_t idx = domain_start; idx < EXTENDED_DOMAIN_END - 1; idx++) {
286 result.value_at(idx + 1) = result.value_at(idx) + delta;
287 }
288 return result;
289 } else {
290 for (size_t k = domain_end; k != EXTENDED_DOMAIN_END; ++k) {
291 result.value_at(k) = 0;
292 // compute each term v_j / (d_j*(x-x_j)) of the sum
293 for (size_t j = domain_start; j != domain_end; ++j) {
294 Fr term = value_at(j);
295 term *= Data::precomputed_denominator_inverses[LENGTH * k + j];
296 result.value_at(k) += term;
297 }
298 // scale the sum by the the value of of B(x)
299 result.value_at(k) *= Data::full_numerator_values[k];
300 }
301 return result;
302 }
303 }
304
311 Fr evaluate(const Fr& u)
312 {
314 Fr full_numerator_value = 1;
315 for (size_t i = domain_start; i != domain_end; ++i) {
316 full_numerator_value *= u - i;
317 }
318
319 // build set of domain size-many denominator inverses 1/(d_i*(x_k - x_j)). will multiply against each of
320 // these (rather than to divide by something) for each barycentric evaluation
321 std::array<Fr, LENGTH> denominator_inverses;
322 for (size_t i = 0; i != LENGTH; ++i) {
323 Fr inv = Data::lagrange_denominators[i];
324 inv *= u - Data::big_domain[i]; // warning: need to avoid zero here
325 inv = Fr(1) / inv;
326 denominator_inverses[i] = inv;
327 }
328
329 Fr result = 0;
330 // compute each term v_j / (d_j*(x-x_j)) of the sum
331 for (size_t i = domain_start; i != domain_end; ++i) {
332 Fr term = value_at(i);
333 term *= denominator_inverses[i - domain_start];
334 result += term;
335 }
336 // scale the sum by the the value of of B(x)
337 result *= full_numerator_value;
338 return result;
339 };
340};
341
342template <typename B, class Fr, size_t domain_end, size_t domain_start = 0>
343inline void read(B& it, Univariate<Fr, domain_end, domain_start>& univariate)
344{
345 using serialize::read;
346 read(it, univariate.evaluations);
347}
348
349template <typename B, class Fr, size_t domain_end, size_t domain_start = 0>
350inline void write(B& it, Univariate<Fr, domain_end, domain_start> const& univariate)
351{
352 using serialize::write;
353 write(it, univariate.evaluations);
354}
355
356template <class Fr, size_t domain_end, size_t domain_start = 0> class UnivariateView {
357 public:
358 static constexpr size_t LENGTH = domain_end - domain_start;
359 std::span<const Fr, LENGTH> evaluations;
360
361 UnivariateView() = default;
362
363 const Fr& value_at(size_t i) const { return evaluations[i]; };
364
365 template <size_t full_domain_end, size_t full_domain_start = 0>
367 : evaluations(std::span<const Fr>(univariate_in.evaluations.data(), LENGTH)){};
368
369 Univariate<Fr, domain_end, domain_start> operator+(const UnivariateView& other) const
370 {
372 res += other;
373 return res;
374 }
375
376 Univariate<Fr, domain_end, domain_start> operator-(const UnivariateView& other) const
377 {
379 res -= other;
380 return res;
381 }
382
384 {
386 for (auto& eval : res.evaluations) {
387 eval = -eval;
388 }
389 return res;
390 }
391
392 Univariate<Fr, domain_end, domain_start> operator*(const UnivariateView& other) const
393 {
395 res *= other;
396 return res;
397 }
398
400 {
402 res *= other;
403 return res;
404 }
405
407 {
409 res += other;
410 return res;
411 }
412
413 Univariate<Fr, domain_end, domain_start> operator+(const Fr& other) const
414 {
416 res += other;
417 return res;
418 }
419
420 Univariate<Fr, domain_end, domain_start> operator-(const Fr& other) const
421 {
423 res -= other;
424 return res;
425 }
426
427 Univariate<Fr, domain_end, domain_start> operator*(const Fr& other) const
428 {
430 res *= other;
431 return res;
432 }
433
435 {
437 res -= other;
438 return res;
439 }
440
441 // Output is immediately parsable as a list of integers by Python.
442 friend std::ostream& operator<<(std::ostream& os, const UnivariateView& u)
443 {
444 os << "[";
445 os << u.evaluations[0] << "," << std::endl;
446 for (size_t i = 1; i < u.evaluations.size(); i++) {
447 os << " " << u.evaluations[i];
448 if (i + 1 < u.evaluations.size()) {
449 os << "," << std::endl;
450 } else {
451 os << "]";
452 };
453 }
454 return os;
455 }
456};
457
471template <typename T, typename U, std::size_t N, std::size_t... Is>
472std::array<T, sizeof...(Is)> array_to_array_aux(const std::array<U, N>& elements, std::index_sequence<Is...>)
473{
474 return { { T{ elements[Is] }... } };
475};
476
493template <typename T, typename U, std::size_t N> std::array<T, N> array_to_array(const std::array<U, N>& elements)
494{
495 // Calls the aux method that uses the index sequence to unpack all values in `elements`
496 return array_to_array_aux<T, U, N>(elements, std::make_index_sequence<N>());
497};
498
499} // namespace barretenberg
A view of a univariate, also used to truncate univariates.
Definition: univariate.hpp:356
A univariate polynomial represented by its values on {domain_start, domain_start + 1,...
Definition: univariate.hpp:23
Univariate< Fr, EXTENDED_DOMAIN_END > extend_to() const
Given a univariate f represented by {f(domain_start), ..., f(domain_end - 1)}, compute the evaluation...
Definition: univariate.hpp:272
Fr evaluate(const Fr &u)
Evaluate a univariate at a point u not known at compile time and assumed not to be in the domain (els...
Definition: univariate.hpp:311
constexpr_utils defines some helper methods that perform some stl-equivalent operations but in a cons...
Definition: constexpr_utils.hpp:16
std::array< T, sizeof...(Is)> array_to_array_aux(const std::array< U, N > &elements, std::index_sequence< Is... >)
Create a sub-array of elements at the indices given in the template pack Is, converting them to the n...
Definition: univariate.hpp:472
std::array< T, N > array_to_array(const std::array< U, N > &elements)
Given an std::array<U,N>, returns an std::array<T,N>, by calling the (explicit) constructor T(U).
Definition: univariate.hpp:493
std::conditional_t< is_field_type_v< Fr >, BarycentricDataCompileTime< Fr, domain_end, num_evals, domain_start >, BarycentricDataRunTime< Fr, domain_end, num_evals, domain_start > > BarycentricData
Exposes BarycentricData with compile time arrays if the type is bberg::field and runtime arrays other...
Definition: barycentric.hpp:257