Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
vectorized_for.test.cpp
Go to the documentation of this file.
2
6
7#include <gtest/gtest.h>
8#include <vector>
9
10namespace {
11
13using bb::ScalarIndex;
14using bb::shift;
16using bb::VectorIndex;
19using Fr = bb::fr;
21using Poly = bb::Polynomial<Fr>;
22
23TEST(VectorizedForTest, ScalarIndexShift)
24{
25 EXPECT_EQ(shift(ScalarIndex{ 7 }, 3).i, 10u);
26}
27
28TEST(VectorizedForTest, VectorIndexShift)
29{
30 auto out = shift(VectorIndex<5>{ { 0, 1, 2, 3, 4 } }, 10);
31 std::array<size_t, 5> expected{ 10, 11, 12, 13, 14 };
32 for (size_t k = 0; k < 5; ++k) {
33 EXPECT_EQ(out.idx[k], expected[k]) << "lane " << k;
34 }
35}
36
37TEST(VectorizedForTest, ConstexprShift)
38{
39 static_assert(shift(ScalarIndex{ 1 }, 2).i == 3);
40 static_assert(shift(VectorIndex<3>{ { 1, 2, 3 } }, 5).idx[2] == 8);
41 SUCCEED();
42}
43
44TEST(VectorizedFor, ContiguousVectorIndexShift)
45{
46 EXPECT_EQ(shift(ContiguousVectorIndex<5>{ 7 }, 3).base, 10u);
47}
48
49TEST(VectorizedForTest, PolynomialScalarReadWrite)
50{
51 Poly p(8);
53 for (size_t i = 0; i < 8; ++i) {
54 known[i] = Fr::random_element();
55 p.at(i) = known[i];
56 }
57
58 // Read via ScalarIndex on a mutable Polynomial: the proxy implicitly
59 // converts to Fr.
60 Fr r = p[ScalarIndex{ 3 }];
61 EXPECT_EQ(r, known[3]);
62
63 // Write via ScalarIndex.
64 Fr v = Fr(42);
65 p[ScalarIndex{ 5 }] = v;
66 EXPECT_EQ(p[5], v);
67}
68
69TEST(VectorizedForTest, PolynomialVectorReadRoundTrip)
70{
71 Poly p(16);
72 for (size_t i = 0; i < 16; ++i) {
73 p.at(i) = Fr::random_element();
74 }
75
76 std::array<size_t, 5> idx{ 3, 0, 7, 15, 9 };
77 // Read via VectorIndex on a mutable Polynomial: the proxy implicitly
78 // converts to VectorField.
79 Vec v = p[VectorIndex<5>{ idx }];
80 for (size_t L = 0; L < 5; ++L) {
81 EXPECT_EQ(v.get(L), p[idx[L]]) << "lane " << L;
82 }
83}
84
85TEST(VectorizedForTest, PolynomialVectorWrite)
86{
87 Poly p(16); // Zero-initialized by the (size_t) ctor.
88
91 };
92 Vec v(vals);
93
94 std::array<size_t, 5> idx{ 2, 5, 1, 8, 0 };
95 p[VectorIndex<5>{ idx }] = v;
96
97 // Target positions match.
98 for (size_t L = 0; L < 5; ++L) {
99 EXPECT_EQ(p[idx[L]], vals[L]) << "lane " << L;
100 }
101
102 // Untouched positions remain zero.
103 for (size_t i = 0; i < 16; ++i) {
104 bool is_target = false;
105 for (size_t L = 0; L < 5; ++L) {
106 if (idx[L] == i) {
107 is_target = true;
108 break;
109 }
110 }
111 if (!is_target) {
112 EXPECT_TRUE(p[i].is_zero()) << "position " << i;
113 }
114 }
115}
116
117TEST(VectorizedForTest, VectorizedForPointwiseMulExact)
118{
119 constexpr size_t SIZE = 20;
120 Poly a(SIZE), b(SIZE), out(SIZE);
121 for (size_t i = 0; i < SIZE; ++i) {
122 a.at(i) = Fr(i * 7 + 3);
123 b.at(i) = Fr(i * 11 + 5);
124 }
125
126 vectorized_for<VECTOR_FIELD_WIDTH, Fr>(0, SIZE, [&](auto ctx) { out[ctx] = a[ctx] * b[ctx]; });
127
128 for (size_t i = 0; i < SIZE; ++i) {
129 Fr ref = a[i] * b[i];
130 EXPECT_EQ(out[i], ref) << "i=" << i;
131 }
132}
133
134TEST(VectorizedForTest, VectorizedForTailExercised)
135{
136 constexpr size_t SIZE = 23;
137 Poly a(SIZE), b(SIZE), out(SIZE);
138 for (size_t i = 0; i < SIZE; ++i) {
139 a.at(i) = Fr(i * 7 + 3);
140 b.at(i) = Fr(i * 11 + 5);
141 }
142
143 vectorized_for<VECTOR_FIELD_WIDTH, Fr>(0, SIZE, [&](auto ctx) { out[ctx] = a[ctx] * b[ctx]; });
144
145 for (size_t i = 0; i < SIZE; ++i) {
146 Fr ref = a[i] * b[i];
147 EXPECT_EQ(out[i], ref) << "i=" << i;
148 }
149}
150
151TEST(VectorizedForTest, VectorizedForNonZeroStart)
152{
153 constexpr size_t SIZE = 16;
154 Poly a(SIZE), out(SIZE); // out zero-initialized.
155 for (size_t i = 0; i < SIZE; ++i) {
156 a.at(i) = Fr(i * 13 + 1);
157 }
158
159 vectorized_for<VECTOR_FIELD_WIDTH, Fr>(3, 14, [&](auto ctx) { out[ctx] = a[ctx] + a[ctx]; });
160
161 for (size_t i = 0; i < 3; ++i) {
162 EXPECT_TRUE(out[i].is_zero()) << "i=" << i;
163 }
164 for (size_t i = 3; i < 14; ++i) {
165 Fr ref = a[i] + a[i];
166 EXPECT_EQ(out[i], ref) << "i=" << i;
167 }
168 for (size_t i = 14; i < SIZE; ++i) {
169 EXPECT_TRUE(out[i].is_zero()) << "i=" << i;
170 }
171}
172
173TEST(VectorizedForTest, VectorizedForEmptyRange)
174{
175 size_t counter = 0;
176 vectorized_for<VECTOR_FIELD_WIDTH, Fr>(5, 5, [&](auto) { ++counter; });
177 EXPECT_EQ(counter, 0u);
178
179 counter = 0;
180 vectorized_for<VECTOR_FIELD_WIDTH, Fr>(5, 7, [&](auto) { ++counter; });
181 EXPECT_EQ(counter, 2u);
182}
183
184TEST(VectorizedForTest, VectorizedForSelfReadMutable)
185{
186 constexpr size_t SIZE = 20;
187 Poly p(SIZE);
188 std::array<Fr, SIZE> original;
189 for (size_t i = 0; i < SIZE; ++i) {
190 original[i] = Fr(i * 7 + 3);
191 p.at(i) = original[i];
192 }
193
194 vectorized_for<VECTOR_FIELD_WIDTH, Fr>(0, SIZE, [&](auto ctx) { p[ctx] = p[ctx] + p[ctx]; });
195
196 for (size_t i = 0; i < SIZE; ++i) {
197 Fr ref = original[i] + original[i];
198 EXPECT_EQ(p[i], ref) << "i=" << i;
199 }
200}
201
202TEST(VectorizedForTest, VectorizedForSelfReadMutableTail)
203{
204 constexpr size_t SIZE = 23;
205 Poly p(SIZE);
206 std::array<Fr, SIZE> original;
207 for (size_t i = 0; i < SIZE; ++i) {
208 original[i] = Fr(i * 7 + 3);
209 p.at(i) = original[i];
210 }
211
212 vectorized_for<VECTOR_FIELD_WIDTH, Fr>(0, SIZE, [&](auto ctx) { p[ctx] = p[ctx] + p[ctx]; });
213
214 for (size_t i = 0; i < SIZE; ++i) {
215 Fr ref = original[i] + original[i];
216 EXPECT_EQ(p[i], ref) << "i=" << i;
217 }
218}
219
220TEST(VectorizedForTest, MixedKernelSelfPlusOther)
221{
222 constexpr size_t SIZE = 20;
223 Poly self(SIZE), other(SIZE);
224 std::array<Fr, SIZE> self_orig, other_vals;
225 for (size_t i = 0; i < SIZE; ++i) {
226 self_orig[i] = Fr(i * 13 + 1);
227 other_vals[i] = Fr(i * 17 + 2);
228 self.at(i) = self_orig[i];
229 other.at(i) = other_vals[i];
230 }
231 Fr scalar = Fr(7);
232
233 vectorized_for<VECTOR_FIELD_WIDTH, Fr>(0, SIZE, [&](auto ctx) { self[ctx] = self[ctx] + other[ctx] * scalar; });
234
235 for (size_t i = 0; i < SIZE; ++i) {
236 Fr ref = self_orig[i] + other_vals[i] * scalar;
237 EXPECT_EQ(self[i], ref) << "i=" << i;
238 }
239}
240
241TEST(VectorizedForTest, VectorizedForIfEvenIndices)
242{
243 constexpr size_t SIZE = 32;
244 Poly p(SIZE);
245 for (size_t i = 0; i < SIZE; ++i) {
246 p.at(i) = Fr(i);
247 }
248
249 vectorized_for_if<VECTOR_FIELD_WIDTH, Fr>(
250 0, SIZE, [](size_t i) { return (i % 2) == 0; }, [&](auto ctx) { p[ctx] = p[ctx] + p[ctx]; });
251
252 for (size_t i = 0; i < SIZE; ++i) {
253 if (i % 2 == 0) {
254 EXPECT_EQ(p[i], Fr(2 * i)) << "i=" << i;
255 } else {
256 EXPECT_EQ(p[i], Fr(i)) << "i=" << i;
257 }
258 }
259}
260
261TEST(VectorizedForTest, VectorizedForIfAllMatch)
262{
263 constexpr size_t SIZE = 25;
264 Poly p(SIZE);
265 std::array<Fr, SIZE> original;
266 for (size_t i = 0; i < SIZE; ++i) {
267 original[i] = Fr(i * 3 + 1);
268 p.at(i) = original[i];
269 }
270
271 vectorized_for_if<VECTOR_FIELD_WIDTH, Fr>(
272 0, SIZE, [](size_t) { return true; }, [&](auto ctx) { p[ctx] = p[ctx] + p[ctx]; });
273
274 for (size_t i = 0; i < SIZE; ++i) {
275 EXPECT_EQ(p[i], original[i] + original[i]) << "i=" << i;
276 }
277}
278
279TEST(VectorizedForTest, VectorizedForIfNoneMatch)
280{
281 size_t counter = 0;
282 vectorized_for_if<VECTOR_FIELD_WIDTH, Fr>(0, 20, [](size_t) { return false; }, [&](auto) { ++counter; });
283 EXPECT_EQ(counter, 0u);
284}
285
286TEST(VectorizedForTest, VectorizedForIfTailOnly)
287{
288 constexpr size_t SIZE = 10;
289 Poly p(SIZE);
290 std::array<Fr, SIZE> original;
291 for (size_t i = 0; i < SIZE; ++i) {
292 original[i] = Fr(i * 11 + 7);
293 p.at(i) = original[i];
294 }
295
296 auto pred = [](size_t i) { return i == 1 || i == 4 || i == 7; };
297 size_t kernel_calls = 0;
298 vectorized_for_if<VECTOR_FIELD_WIDTH, Fr>(0, SIZE, pred, [&](auto ctx) {
299 ++kernel_calls;
300 p[ctx] = p[ctx] + p[ctx];
301 });
302
303 EXPECT_EQ(kernel_calls, 3u);
304 for (size_t i = 0; i < SIZE; ++i) {
305 if (pred(i)) {
306 EXPECT_EQ(p[i], original[i] + original[i]) << "i=" << i;
307 } else {
308 EXPECT_EQ(p[i], original[i]) << "i=" << i;
309 }
310 }
311}
312
313TEST(VectorizedForTest, VectorizedForIfPredicateCallOrder)
314{
315 std::vector<size_t> log;
316 vectorized_for_if<VECTOR_FIELD_WIDTH, Fr>(
317 5,
318 17,
319 [&](size_t i) {
320 log.push_back(i);
321 return false;
322 },
323 [&](auto) { /* never invoked */ });
324
325 std::vector<size_t> expected{ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
326 EXPECT_EQ(log, expected);
327}
328
329} // namespace
TEST(acir_formal_proofs, uint_terms_add)
Tests 128-bit unsigned addition Verifies that the ACIR implementation of addition is correct Executio...
FF a
FF b
field< Bn254FrParams > fr
Definition fr.hpp:155
void vectorized_for(size_t start, size_t end, K &&kernel)
constexpr size_t VECTOR_FIELD_WIDTH
constexpr ScalarIndex shift(ScalarIndex ctx, size_t d)
void vectorized_for_if(size_t start, size_t end, P &&predicate, K &&kernel)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Curve::ScalarField Fr
bb::VectorAffineElementPushSpan< BaseParams > out
Field get(size_t i) const noexcept
static field random_element(numeric::RNG *engine=nullptr) noexcept