poulpy/poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/test/spqlios_reim_test.cpp
poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/test/spqlios_reim_test.cppRaw
1#include <inttypes.h>
2
3#include <cmath>
4
5#include "gtest/gtest.h"
6#include "spqlios/commons_private.h"
7#include "spqlios/cplx/cplx_fft_internal.h"
8#include "spqlios/reim/reim_fft_internal.h"
9#include "spqlios/reim/reim_fft_private.h"
10
11#ifdef __x86_64__
12TEST(fft, reim_fft_avx2_vs_fft_reim_ref) {
13 for (uint64_t nn : {16, 32, 64, 1024, 8192, 65536}) {
14 uint64_t m = nn / 2;
15 // CPLX_FFT_PRECOMP* tables = new_cplx_fft_precomp(m, 0);
16 REIM_FFT_PRECOMP* reimtables = new_reim_fft_precomp(m, 0);
17 CPLX* a = (CPLX*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
18 double* a1 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
19 double* a2 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
20 int64_t p = 1 << 16;
21 for (uint32_t i = 0; i < nn / 2; i++) {
22 a[i][0] = (rand() % p) - p / 2; // between -p/2 and p/2
23 a[i][1] = (rand() % p) - p / 2;
24 }
25 memcpy(a1, a, nn / 2 * sizeof(CPLX));
26 memcpy(a2, a, nn / 2 * sizeof(CPLX));
27 reim_fft_ref(reimtables, a2);
28 reim_fft_avx2_fma(reimtables, a1);
29 double d = 0;
30 for (uint32_t i = 0; i < nn / 2; i++) {
31 double dre = fabs(a1[i] - a2[i]);
32 double dim = fabs(a1[nn / 2 + i] - a2[nn / 2 + i]);
33 if (dre > d) d = dre;
34 if (dim > d) d = dim;
35 ASSERT_LE(d, nn * 1e-10) << nn;
36 }
37 ASSERT_LE(d, nn * 1e-10) << nn;
38 spqlios_free(a);
39 spqlios_free(a1);
40 spqlios_free(a2);
41 // delete_cplx_fft_precomp(tables);
42 delete_reim_fft_precomp(reimtables);
43 }
44}
45#endif
46
47#ifdef __x86_64__
48TEST(fft, reim_ifft_avx2_vs_reim_ifft_ref) {
49 for (uint64_t nn : {16, 32, 64, 1024, 8192, 65536}) {
50 uint64_t m = nn / 2;
51 // CPLX_FFT_PRECOMP* tables = new_cplx_fft_precomp(m, 0);
52 REIM_IFFT_PRECOMP* reimtables = new_reim_ifft_precomp(m, 0);
53 CPLX* a = (CPLX*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
54 double* a1 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
55 double* a2 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
56 int64_t p = 1 << 16;
57 for (uint32_t i = 0; i < nn / 2; i++) {
58 a[i][0] = (rand() % p) - p / 2; // between -p/2 and p/2
59 a[i][1] = (rand() % p) - p / 2;
60 }
61 memcpy(a1, a, nn / 2 * sizeof(CPLX));
62 memcpy(a2, a, nn / 2 * sizeof(CPLX));
63 reim_ifft_ref(reimtables, a2);
64 reim_ifft_avx2_fma(reimtables, a1);
65 double d = 0;
66 for (uint32_t i = 0; i < nn / 2; i++) {
67 double dre = fabs(a1[i] - a2[i]);
68 double dim = fabs(a1[nn / 2 + i] - a2[nn / 2 + i]);
69 if (dre > d) d = dre;
70 if (dim > d) d = dim;
71 ASSERT_LE(d, 1e-8);
72 }
73 ASSERT_LE(d, 1e-8);
74 spqlios_free(a);
75 spqlios_free(a1);
76 spqlios_free(a2);
77 // delete_cplx_fft_precomp(tables);
78 delete_reim_fft_precomp(reimtables);
79 }
80}
81#endif
82
83#ifdef __x86_64__
84TEST(fft, reim_vecfft_addmul_fma_vs_ref) {
85 for (uint64_t nn : {16, 32, 64, 1024, 8192, 65536}) {
86 uint64_t m = nn / 2;
87 REIM_FFTVEC_ADDMUL_PRECOMP* tbl = new_reim_fftvec_addmul_precomp(m);
88 ASSERT_TRUE(tbl != nullptr);
89 double* a1 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
90 double* a2 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
91 double* b1 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
92 double* b2 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
93 double* r1 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
94 double* r2 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
95 int64_t p = 1 << 16;
96 for (uint32_t i = 0; i < nn; i++) {
97 a1[i] = (rand() % p) - p / 2; // between -p/2 and p/2
98 b1[i] = (rand() % p) - p / 2;
99 r1[i] = (rand() % p) - p / 2;
100 }
101 memcpy(a2, a1, nn / 2 * sizeof(CPLX));
102 memcpy(b2, b1, nn / 2 * sizeof(CPLX));
103 memcpy(r2, r1, nn / 2 * sizeof(CPLX));
104 reim_fftvec_addmul_ref(tbl, r1, a1, b1);
105 reim_fftvec_addmul_fma(tbl, r2, a2, b2);
106 double d = 0;
107 for (uint32_t i = 0; i < nn; i++) {
108 double di = fabs(r1[i] - r2[i]);
109 if (di > d) d = di;
110 ASSERT_LE(d, 1e-8);
111 }
112 ASSERT_LE(d, 1e-8);
113 spqlios_free(a1);
114 spqlios_free(a2);
115 spqlios_free(b1);
116 spqlios_free(b2);
117 spqlios_free(r1);
118 spqlios_free(r2);
119 delete_reim_fftvec_addmul_precomp(tbl);
120 }
121}
122#endif
123
124#ifdef __x86_64__
125TEST(fft, reim_vecfft_mul_fma_vs_ref) {
126 for (uint64_t nn : {16, 32, 64, 1024, 8192, 65536}) {
127 uint64_t m = nn / 2;
128 REIM_FFTVEC_MUL_PRECOMP* tbl = new_reim_fftvec_mul_precomp(m);
129 double* a1 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
130 double* a2 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
131 double* b1 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
132 double* b2 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
133 double* r1 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
134 double* r2 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
135 int64_t p = 1 << 16;
136 for (uint32_t i = 0; i < nn; i++) {
137 a1[i] = (rand() % p) - p / 2; // between -p/2 and p/2
138 b1[i] = (rand() % p) - p / 2;
139 r1[i] = (rand() % p) - p / 2;
140 }
141 memcpy(a2, a1, nn / 2 * sizeof(CPLX));
142 memcpy(b2, b1, nn / 2 * sizeof(CPLX));
143 memcpy(r2, r1, nn / 2 * sizeof(CPLX));
144 reim_fftvec_mul_ref(tbl, r1, a1, b1);
145 reim_fftvec_mul_fma(tbl, r2, a2, b2);
146 double d = 0;
147 for (uint32_t i = 0; i < nn; i++) {
148 double di = fabs(r1[i] - r2[i]);
149 if (di > d) d = di;
150 ASSERT_LE(d, 1e-8);
151 }
152 ASSERT_LE(d, 1e-8);
153 spqlios_free(a1);
154 spqlios_free(a2);
155 spqlios_free(b1);
156 spqlios_free(b2);
157 spqlios_free(r1);
158 spqlios_free(r2);
159 delete_reim_fftvec_mul_precomp(tbl);
160 }
161}
162#endif
163
164#ifdef __x86_64__
165TEST(fft, reim_vecfft_add_fma_vs_ref) {
166 for (uint64_t nn : {16, 32, 64, 1024, 8192, 65536}) {
167 uint64_t m = nn / 2;
168 REIM_FFTVEC_ADD_PRECOMP* tbl = new_reim_fftvec_add_precomp(m);
169 double* a1 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
170 double* a2 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
171 double* b1 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
172 double* b2 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
173 double* r1 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
174 double* r2 = (double*)spqlios_alloc_custom_align(32, nn / 2 * sizeof(CPLX));
175 int64_t p = 1 << 16;
176 for (uint32_t i = 0; i < nn; i++) {
177 a1[i] = (rand() % p) - p / 2; // between -p/2 and p/2
178 b1[i] = (rand() % p) - p / 2;
179 r1[i] = (rand() % p) - p / 2;
180 }
181 memcpy(a2, a1, nn / 2 * sizeof(CPLX));
182 memcpy(b2, b1, nn / 2 * sizeof(CPLX));
183 memcpy(r2, r1, nn / 2 * sizeof(CPLX));
184 reim_fftvec_add_ref(tbl, r1, a1, b1);
185 reim_fftvec_add_fma(tbl, r2, a2, b2);
186 double d = 0;
187 for (uint32_t i = 0; i < nn; i++) {
188 double di = fabs(r1[i] - r2[i]);
189 if (di > d) d = di;
190 ASSERT_LE(d, 1e-8);
191 }
192 ASSERT_LE(d, 1e-8);
193 spqlios_free(a1);
194 spqlios_free(a2);
195 spqlios_free(b1);
196 spqlios_free(b2);
197 spqlios_free(r1);
198 spqlios_free(r2);
199 delete_reim_fftvec_add_precomp(tbl);
200 }
201}
202#endif
203
204typedef void (*FILL_REIM_FFT_OMG_F)(const double entry_pwr, double** omg);
205typedef void (*REIM_FFT_F)(double* dre, double* dim, const void* omega);
206
207// template to test a fixed-dimension fft vs. naive
208template <uint64_t N>
209void test_reim_fft_ref_vs_naive(FILL_REIM_FFT_OMG_F fill_omega_f, REIM_FFT_F reim_fft_f) {
210 double om[N];
211 double data[2 * N];
212 double datacopy[2 * N];
213 double* omg = om;
214 fill_omega_f(0.25, &omg);
215 ASSERT_EQ(omg - om, ptrdiff_t(N)); // it may depend on N
216 for (uint64_t i = 0; i < N; ++i) {
217 datacopy[i] = data[i] = (rand() % 100) - 50;
218 datacopy[N + i] = data[N + i] = (rand() % 100) - 50;
219 }
220 reim_fft_f(datacopy, datacopy + N, om);
221 reim_naive_fft(N, 0.25, data, data + N);
222 double d = 0;
223 for (uint64_t i = 0; i < 2 * N; ++i) {
224 d += fabs(datacopy[i] - data[i]);
225 }
226 ASSERT_LE(d, 1e-7);
227}
228
229template <uint64_t N>
230void test_reim_fft_ref_vs_accel(REIM_FFT_F reim_fft_ref_f, REIM_FFT_F reim_fft_accel_f) {
231 double om[N];
232 double data[2 * N];
233 double datacopy[2 * N];
234 for (uint64_t i = 0; i < N; ++i) {
235 om[i] = (rand() % 100) - 50;
236 datacopy[i] = data[i] = (rand() % 100) - 50;
237 datacopy[N + i] = data[N + i] = (rand() % 100) - 50;
238 }
239 reim_fft_ref_f(datacopy, datacopy + N, om);
240 reim_fft_accel_f(data, data + N, om);
241 double d = 0;
242 for (uint64_t i = 0; i < 2 * N; ++i) {
243 d += fabs(datacopy[i] - data[i]);
244 }
245 if (d > 1e-15) {
246 for (uint64_t i = 0; i < N; ++i) {
247 printf("%" PRId64 " %lf %lf %lf %lf\n", i, data[i], data[N + i], datacopy[i], datacopy[N + i]);
248 }
249 ASSERT_LE(d, 0);
250 }
251}
252
253TEST(fft, reim_fft16_ref_vs_naive) { test_reim_fft_ref_vs_naive<16>(fill_reim_fft16_omegas, reim_fft16_ref); }
254#ifdef __aarch64__
255TEST(fft, reim_fft16_neon_vs_naive) { test_reim_fft_ref_vs_naive<16>(fill_reim_fft16_omegas_neon, reim_fft16_neon); }
256#endif
257
258#ifdef __x86_64__
259TEST(fft, reim_fft16_ref_vs_fma) { test_reim_fft_ref_vs_accel<16>(reim_fft16_ref, reim_fft16_avx_fma); }
260#endif
261
262#ifdef __aarch64__
263static void reim_fft16_ref_neon_pom(double* dre, double* dim, const void* omega) {
264 const double* pom = (double*)omega;
265 // put the omegas in neon order
266 double x_pom[] = {pom[0], pom[1], pom[2], pom[3], pom[4], pom[5], pom[6], pom[7],
267 pom[8], pom[10], pom[12], pom[14], pom[9], pom[11], pom[13], pom[15]};
268 reim_fft16_ref(dre, dim, x_pom);
269}
270TEST(fft, reim_fft16_ref_vs_neon) { test_reim_fft_ref_vs_accel<16>(reim_fft16_ref_neon_pom, reim_fft16_neon); }
271#endif
272
273TEST(fft, reim_fft8_ref_vs_naive) { test_reim_fft_ref_vs_naive<8>(fill_reim_fft8_omegas, reim_fft8_ref); }
274
275#ifdef __x86_64__
276TEST(fft, reim_fft8_ref_vs_fma) { test_reim_fft_ref_vs_accel<8>(reim_fft8_ref, reim_fft8_avx_fma); }
277#endif
278
279TEST(fft, reim_fft4_ref_vs_naive) { test_reim_fft_ref_vs_naive<4>(fill_reim_fft4_omegas, reim_fft4_ref); }
280
281#ifdef __x86_64__
282TEST(fft, reim_fft4_ref_vs_fma) { test_reim_fft_ref_vs_accel<4>(reim_fft4_ref, reim_fft4_avx_fma); }
283#endif
284
285TEST(fft, reim_fft2_ref_vs_naive) { test_reim_fft_ref_vs_naive<2>(fill_reim_fft2_omegas, reim_fft2_ref); }
286
287TEST(fft, reim_fft_bfs_16_ref_vs_naive) {
288 for (const uint64_t m : {16, 32, 64, 128, 256, 512, 1024, 2048}) {
289 std::vector<double> om(2 * m);
290 std::vector<double> data(2 * m);
291 std::vector<double> datacopy(2 * m);
292 double* omg = om.data();
293 fill_reim_fft_bfs_16_omegas(m, 0.25, &omg);
294 ASSERT_LE(omg - om.data(), ptrdiff_t(2 * m)); // it may depend on m
295 for (uint64_t i = 0; i < m; ++i) {
296 datacopy[i] = data[i] = (rand() % 100) - 50;
297 datacopy[m + i] = data[m + i] = (rand() % 100) - 50;
298 }
299 omg = om.data();
300 reim_fft_bfs_16_ref(m, datacopy.data(), datacopy.data() + m, &omg);
301 reim_naive_fft(m, 0.25, data.data(), data.data() + m);
302 double d = 0;
303 for (uint64_t i = 0; i < 2 * m; ++i) {
304 d += fabs(datacopy[i] - data[i]);
305 }
306 ASSERT_LE(d, 1e-7);
307 }
308}
309
310TEST(fft, reim_fft_rec_16_ref_vs_naive) {
311 for (const uint64_t m : {2048, 4096, 8192, 32768, 65536}) {
312 std::vector<double> om(2 * m);
313 std::vector<double> data(2 * m);
314 std::vector<double> datacopy(2 * m);
315 double* omg = om.data();
316 fill_reim_fft_rec_16_omegas(m, 0.25, &omg);
317 ASSERT_LE(omg - om.data(), ptrdiff_t(2 * m)); // it may depend on m
318 for (uint64_t i = 0; i < m; ++i) {
319 datacopy[i] = data[i] = (rand() % 100) - 50;
320 datacopy[m + i] = data[m + i] = (rand() % 100) - 50;
321 }
322 omg = om.data();
323 reim_fft_rec_16_ref(m, datacopy.data(), datacopy.data() + m, &omg);
324 reim_naive_fft(m, 0.25, data.data(), data.data() + m);
325 double d = 0;
326 for (uint64_t i = 0; i < 2 * m; ++i) {
327 d += fabs(datacopy[i] - data[i]);
328 }
329 ASSERT_LE(d, 1e-5);
330 }
331}
332
333TEST(fft, reim_fft_ref_vs_naive) {
334 for (const uint64_t m : {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 32768, 65536}) {
335 std::vector<double> om(2 * m);
336 std::vector<double> data(2 * m);
337 std::vector<double> datacopy(2 * m);
338 REIM_FFT_PRECOMP* precomp = new_reim_fft_precomp(m, 0);
339 for (uint64_t i = 0; i < m; ++i) {
340 datacopy[i] = data[i] = (rand() % 100) - 50;
341 datacopy[m + i] = data[m + i] = (rand() % 100) - 50;
342 }
343 reim_fft_ref(precomp, datacopy.data());
344 reim_naive_fft(m, 0.25, data.data(), data.data() + m);
345 double d = 0;
346 for (uint64_t i = 0; i < 2 * m; ++i) {
347 d += fabs(datacopy[i] - data[i]);
348 }
349 ASSERT_LE(d, 1e-5) << m;
350 delete_reim_fft_precomp(precomp);
351 }
352}
353
354#ifdef __aarch64__
355EXPORT REIM_FFT_PRECOMP* new_reim_fft_precomp_neon(uint32_t m, uint32_t num_buffers);
356EXPORT void reim_fft_neon(const REIM_FFT_PRECOMP* precomp, double* d);
357TEST(fft, reim_fft_neon_vs_naive) {
358 for (const uint64_t m : {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 32768, 65536}) {
359 std::vector<double> om(2 * m);
360 std::vector<double> data(2 * m);
361 std::vector<double> datacopy(2 * m);
362 REIM_FFT_PRECOMP* precomp = new_reim_fft_precomp_neon(m, 0);
363 for (uint64_t i = 0; i < m; ++i) {
364 datacopy[i] = data[i] = (rand() % 100) - 50;
365 datacopy[m + i] = data[m + i] = (rand() % 100) - 50;
366 }
367 reim_fft_neon(precomp, datacopy.data());
368 reim_naive_fft(m, 0.25, data.data(), data.data() + m);
369 double d = 0;
370 for (uint64_t i = 0; i < 2 * m; ++i) {
371 d += fabs(datacopy[i] - data[i]);
372 }
373 ASSERT_LE(d, 1e-5) << m;
374 delete_reim_fft_precomp(precomp);
375 }
376}
377#endif
378
379typedef void (*FILL_REIM_IFFT_OMG_F)(const double entry_pwr, double** omg);
380typedef void (*REIM_IFFT_F)(double* dre, double* dim, const void* omega);
381
382// template to test a fixed-dimension fft vs. naive
383template <uint64_t N>
384void test_reim_ifft_ref_vs_naive(FILL_REIM_IFFT_OMG_F fill_omega_f, REIM_IFFT_F reim_ifft_f) {
385 double om[N];
386 double data[2 * N];
387 double datacopy[2 * N];
388 double* omg = om;
389 fill_omega_f(0.25, &omg);
390 ASSERT_EQ(omg - om, ptrdiff_t(N)); // it may depend on N
391 for (uint64_t i = 0; i < N; ++i) {
392 datacopy[i] = data[i] = (rand() % 100) - 50;
393 datacopy[N + i] = data[N + i] = (rand() % 100) - 50;
394 }
395 reim_ifft_f(datacopy, datacopy + N, om);
396 reim_naive_ifft(N, 0.25, data, data + N);
397 double d = 0;
398 for (uint64_t i = 0; i < 2 * N; ++i) {
399 d += fabs(datacopy[i] - data[i]);
400 }
401 ASSERT_LE(d, 1e-7);
402}
403
404template <uint64_t N>
405void test_reim_ifft_ref_vs_accel(REIM_IFFT_F reim_ifft_ref_f, REIM_IFFT_F reim_ifft_accel_f) {
406 double om[N];
407 double data[2 * N];
408 double datacopy[2 * N];
409 for (uint64_t i = 0; i < N; ++i) {
410 om[i] = (rand() % 100) - 50;
411 datacopy[i] = data[i] = (rand() % 100) - 50;
412 datacopy[N + i] = data[N + i] = (rand() % 100) - 50;
413 }
414 reim_ifft_ref_f(datacopy, datacopy + N, om);
415 reim_ifft_accel_f(data, data + N, om);
416 double d = 0;
417 for (uint64_t i = 0; i < 2 * N; ++i) {
418 d += fabs(datacopy[i] - data[i]);
419 }
420 if (d > 1e-15) {
421 for (uint64_t i = 0; i < N; ++i) {
422 printf("%" PRId64 " %lf %lf %lf %lf\n", i, data[i], data[N + i], datacopy[i], datacopy[N + i]);
423 }
424 ASSERT_LE(d, 0);
425 }
426}
427
428TEST(fft, reim_ifft16_ref_vs_naive) { test_reim_ifft_ref_vs_naive<16>(fill_reim_ifft16_omegas, reim_ifft16_ref); }
429
430#ifdef __x86_64__
431TEST(fft, reim_ifft16_ref_vs_fma) { test_reim_ifft_ref_vs_accel<16>(reim_ifft16_ref, reim_ifft16_avx_fma); }
432#endif
433
434TEST(fft, reim_ifft8_ref_vs_naive) { test_reim_ifft_ref_vs_naive<8>(fill_reim_ifft8_omegas, reim_ifft8_ref); }
435
436#ifdef __x86_64__
437TEST(fft, reim_ifft8_ref_vs_fma) { test_reim_ifft_ref_vs_accel<8>(reim_ifft8_ref, reim_ifft8_avx_fma); }
438#endif
439
440TEST(fft, reim_ifft4_ref_vs_naive) { test_reim_ifft_ref_vs_naive<4>(fill_reim_ifft4_omegas, reim_ifft4_ref); }
441
442#ifdef __x86_64__
443TEST(fft, reim_ifft4_ref_vs_fma) { test_reim_ifft_ref_vs_accel<4>(reim_ifft4_ref, reim_ifft4_avx_fma); }
444#endif
445
446TEST(fft, reim_ifft2_ref_vs_naive) { test_reim_ifft_ref_vs_naive<2>(fill_reim_ifft2_omegas, reim_ifft2_ref); }
447
448TEST(fft, reim_ifft_bfs_16_ref_vs_naive) {
449 for (const uint64_t m : {16, 32, 64, 128, 256, 512, 1024, 2048}) {
450 std::vector<double> om(2 * m);
451 std::vector<double> data(2 * m);
452 std::vector<double> datacopy(2 * m);
453 double* omg = om.data();
454 fill_reim_ifft_bfs_16_omegas(m, 0.25, &omg);
455 ASSERT_LE(omg - om.data(), ptrdiff_t(2 * m)); // it may depend on m
456 for (uint64_t i = 0; i < m; ++i) {
457 datacopy[i] = data[i] = (rand() % 100) - 50;
458 datacopy[m + i] = data[m + i] = (rand() % 100) - 50;
459 }
460 omg = om.data();
461 reim_ifft_bfs_16_ref(m, datacopy.data(), datacopy.data() + m, &omg);
462 reim_naive_ifft(m, 0.25, data.data(), data.data() + m);
463 double d = 0;
464 for (uint64_t i = 0; i < 2 * m; ++i) {
465 d += fabs(datacopy[i] - data[i]);
466 }
467 ASSERT_LE(d, 1e-7);
468 }
469}
470
471TEST(fft, reim_ifft_rec_16_ref_vs_naive) {
472 for (const uint64_t m : {2048, 4096, 8192, 32768, 65536}) {
473 std::vector<double> om(2 * m);
474 std::vector<double> data(2 * m);
475 std::vector<double> datacopy(2 * m);
476 double* omg = om.data();
477 fill_reim_ifft_rec_16_omegas(m, 0.25, &omg);
478 ASSERT_LE(omg - om.data(), ptrdiff_t(2 * m)); // it may depend on m
479 for (uint64_t i = 0; i < m; ++i) {
480 datacopy[i] = data[i] = (rand() % 100) - 50;
481 datacopy[m + i] = data[m + i] = (rand() % 100) - 50;
482 }
483 omg = om.data();
484 reim_ifft_rec_16_ref(m, datacopy.data(), datacopy.data() + m, &omg);
485 reim_naive_ifft(m, 0.25, data.data(), data.data() + m);
486 double d = 0;
487 for (uint64_t i = 0; i < 2 * m; ++i) {
488 d += fabs(datacopy[i] - data[i]);
489 }
490 ASSERT_LE(d, 1e-5);
491 }
492}
493
494TEST(fft, reim_ifft_ref_vs_naive) {
495 for (const uint64_t m : {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 32768, 65536}) {
496 std::vector<double> om(2 * m);
497 std::vector<double> data(2 * m);
498 std::vector<double> datacopy(2 * m);
499 REIM_IFFT_PRECOMP* precomp = new_reim_ifft_precomp(m, 0);
500 for (uint64_t i = 0; i < m; ++i) {
501 datacopy[i] = data[i] = (rand() % 100) - 50;
502 datacopy[m + i] = data[m + i] = (rand() % 100) - 50;
503 }
504 reim_ifft_ref(precomp, datacopy.data());
505 reim_naive_ifft(m, 0.25, data.data(), data.data() + m);
506 double d = 0;
507 for (uint64_t i = 0; i < 2 * m; ++i) {
508 d += fabs(datacopy[i] - data[i]);
509 }
510 ASSERT_LE(d, 1e-5) << m;
511 delete_reim_ifft_precomp(precomp);
512 }
513}