22 x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
23 x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
24 x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
25 x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
26 return (((x >> 16) | (x << 16))) >> (32 - bit_length);
38 const Fr& generator_start,
39 const Fr& generator_shift,
40 const size_t generator_size)
43 "generator_size must be divisible by num_threads to avoid silently skipping elements");
45 Fr thread_shift = generator_shift.pow(static_cast<uint64_t>(j * (generator_size / domain.num_threads)));
46 Fr work_generator = generator_start * thread_shift;
47 const size_t offset = j * (generator_size / domain.num_threads);
48 const size_t end = offset + (generator_size / domain.num_threads);
49 for (size_t i = offset; i < end; ++i) {
50 target[i] = coeffs[i] * work_generator;
51 work_generator *= generator_shift;
61 BB_ASSERT(coeffs !=
target,
"fft_inner_parallel does not support in-place operation");
65 for (size_t i = (j * domain.thread_size); i < ((j + 1) * domain.thread_size); i += 2) {
66 uint32_t next_index_1 = (uint32_t)reverse_bits((uint32_t)i + 2, (uint32_t)domain.log2_size);
67 uint32_t next_index_2 = (uint32_t)reverse_bits((uint32_t)i + 3, (uint32_t)domain.log2_size);
68 __builtin_prefetch(&coeffs[next_index_1]);
69 __builtin_prefetch(&coeffs[next_index_2]);
71 uint32_t swap_index_1 = (uint32_t)reverse_bits((uint32_t)i, (uint32_t)domain.log2_size);
72 uint32_t swap_index_2 = (uint32_t)reverse_bits((uint32_t)i + 1, (uint32_t)domain.log2_size);
74 Fr::__copy(coeffs[swap_index_1], temp_1);
75 Fr::__copy(coeffs[swap_index_2], temp_2);
76 target[i + 1] = temp_1 - temp_2;
77 target[i] = temp_1 + temp_2;
82 for (
size_t m = 2; m < (domain.size); m <<= 1) {
93 const size_t start = j * (domain.thread_size >> 1);
94 const size_t end = (j + 1) * (domain.thread_size >> 1);
114 const size_t block_mask = m - 1;
124 const size_t index_mask = ~block_mask;
129 const Fr* round_roots = root_table[static_cast<size_t>(numeric::get_msb(m)) - 1];
134 for (size_t i = start; i < end; ++i) {
135 size_t k1 = (i & index_mask) << 1;
136 size_t j1 = i & block_mask;
137 temp = round_roots[j1] * target[k1 + j1 + m];
138 target[k1 + j1 + m] = target[k1 + j1] - temp;
139 target[k1 + j1] += temp;
279 for (
size_t i = 0; i < n; ++i) {
280 for (
size_t j = i + 1; j < n; ++j) {
281 BB_ASSERT(evaluation_points[i] != evaluation_points[j],
282 "compute_efficient_interpolation requires distinct evaluation points");
286 std::vector<Fr> numerator_polynomial(n + 1);
287 polynomial_arithmetic::compute_linear_polynomial_product(evaluation_points, numerator_polynomial.
data(), n);
289 std::vector<Fr> roots_and_denominators(2 * n);
290 std::vector<Fr> temp_src(n);
291 for (
size_t i = 0; i < n; ++i) {
292 roots_and_denominators[i] = -evaluation_points[i];
293 temp_src[i] = src[i];
296 roots_and_denominators[n + i] = 1;
297 for (
size_t j = 0; j < n; ++j) {
301 roots_and_denominators[n + i] *= (evaluation_points[i] - evaluation_points[j]);
309 std::vector<Fr> temp_dest(n);
311 bool interpolation_domain_contains_zero =
false;
314 if (numerator_polynomial[0] ==
Fr(0)) {
315 for (
size_t i = 0; i < n; ++i) {
316 if (evaluation_points[i] ==
Fr(0)) {
318 interpolation_domain_contains_zero =
true;
324 if (!interpolation_domain_contains_zero) {
325 for (
size_t i = 0; i < n; ++i) {
327 z = roots_and_denominators[i];
329 multiplier = temp_src[i] * roots_and_denominators[n + i];
330 temp_dest[0] = multiplier * numerator_polynomial[0];
332 dest[0] += temp_dest[0];
333 for (
size_t j = 1; j < n; ++j) {
334 temp_dest[j] = multiplier * numerator_polynomial[j] - temp_dest[j - 1];
336 dest[j] += temp_dest[j];
340 for (
size_t i = 0; i < n; ++i) {
346 z = roots_and_denominators[i];
348 multiplier = temp_src[i] * roots_and_denominators[n + i];
350 temp_dest[1] = multiplier * numerator_polynomial[1];
354 dest[1] += temp_dest[1];
356 for (
size_t j = 2; j < n; ++j) {
357 temp_dest[j] = multiplier * numerator_polynomial[j] - temp_dest[j - 1];
359 dest[j] += temp_dest[j];
363 for (
size_t i = 0; i < n; ++i) {
364 dest[i] += temp_src[idx_zero] * roots_and_denominators[n + idx_zero] * numerator_polynomial[i + 1];