arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/spqlios/lib/test/spqlios_vec_znx_dft_test.cpp
spqlios/lib/test/spqlios_vec_znx_dft_test.cppRaw
  1#include <gtest/gtest.h>
  2
  3#include <cstdint>
  4
  5#include "../spqlios/arithmetic/vec_znx_arithmetic_private.h"
  6#include "spqlios/arithmetic/vec_znx_arithmetic.h"
  7#include "test/testlib/ntt120_dft.h"
  8#include "test/testlib/ntt120_layouts.h"
  9#include "testlib/fft64_dft.h"
 10#include "testlib/fft64_layouts.h"
 11#include "testlib/polynomial_vector.h"
 12
 13static void test_fft64_vec_znx_dft(VEC_ZNX_DFT_F dft) {
 14  for (uint64_t n : {2, 4, 128}) {
 15    MODULE* module = new_module_info(n, FFT64);
 16    for (uint64_t sa : {3, 5, 8}) {
 17      for (uint64_t sr : {3, 5, 8}) {
 18        uint64_t a_sl = n + uniform_u64_bits(2);
 19        znx_vec_i64_layout a(n, sa, a_sl);
 20        fft64_vec_znx_dft_layout res(n, sr);
 21        a.fill_random(42);
 22        std::vector<reim_fft64vec> expect(sr);
 23        for (uint64_t i = 0; i < sr; ++i) {
 24          expect[i] = simple_fft64(a.get_copy_zext(i));
 25        }
 26        // test the function
 27        thash hash_before = a.content_hash();
 28        dft(module, res.data, sr, a.data(), sa, a_sl);
 29        ASSERT_EQ(a.content_hash(), hash_before);
 30        for (uint64_t i = 0; i < sr; ++i) {
 31          reim_fft64vec actual = res.get_copy_zext(i);
 32          ASSERT_LE(infty_dist(actual, expect[i]), 1e-10);
 33        }
 34      }
 35    }
 36    delete_module_info(module);
 37  }
 38}
 39
 40#ifdef __x86_64__
 41// FIXME: currently, it only works on avx
 42static void test_ntt120_vec_znx_dft(VEC_ZNX_DFT_F dft) {
 43  for (uint64_t n : {2, 4, 128}) {
 44    MODULE* module = new_module_info(n, NTT120);
 45    for (uint64_t sa : {3, 5, 8}) {
 46      for (uint64_t sr : {3, 5, 8}) {
 47        uint64_t a_sl = n + uniform_u64_bits(2);
 48        znx_vec_i64_layout a(n, sa, a_sl);
 49        ntt120_vec_znx_dft_layout res(n, sr);
 50        a.fill_random(42);
 51        std::vector<q120_nttvec> expect(sr);
 52        for (uint64_t i = 0; i < sr; ++i) {
 53          expect[i] = simple_ntt120(a.get_copy_zext(i));
 54        }
 55        // test the function
 56        thash hash_before = a.content_hash();
 57        dft(module, res.data, sr, a.data(), sa, a_sl);
 58        ASSERT_EQ(a.content_hash(), hash_before);
 59        for (uint64_t i = 0; i < sr; ++i) {
 60          q120_nttvec actual = res.get_copy_zext(i);
 61          if (!(actual == expect[i])) {
 62            for (uint64_t j = 0; j < n; ++j) {
 63              std::cerr << actual.v[j] << " vs " << expect[i].v[j] << std::endl;
 64            }
 65          }
 66          ASSERT_EQ(actual, expect[i]);
 67        }
 68      }
 69    }
 70    delete_module_info(module);
 71  }
 72}
 73#endif
 74
 75TEST(vec_znx_dft, fft64_vec_znx_dft) { test_fft64_vec_znx_dft(fft64_vec_znx_dft); }
 76#ifdef __x86_64__
 77// FIXME: currently, it only works on avx
 78TEST(vec_znx_dft, ntt120_vec_znx_dft) { test_ntt120_vec_znx_dft(ntt120_vec_znx_dft_avx); }
 79#endif
 80TEST(vec_znx_dft, vec_znx_dft) {
 81  test_fft64_vec_znx_dft(vec_znx_dft);
 82#ifdef __x86_64__
 83  // FIXME: currently, it only works on avx
 84  test_ntt120_vec_znx_dft(ntt120_vec_znx_dft_avx);
 85#endif
 86}
 87
 88static void test_fft64_vec_znx_idft(VEC_ZNX_IDFT_F idft, VEC_ZNX_IDFT_TMP_A_F idft_tmp_a,
 89                                    VEC_ZNX_IDFT_TMP_BYTES_F idft_tmp_bytes) {
 90  for (uint64_t n : {2, 4, 64, 128}) {
 91    MODULE* module = new_module_info(n, FFT64);
 92    uint64_t tmp_size = idft_tmp_bytes ? idft_tmp_bytes(module) : 0;
 93    std::vector<uint8_t> tmp(tmp_size);
 94    for (uint64_t sa : {3, 5, 8}) {
 95      for (uint64_t sr : {3, 5, 8}) {
 96        fft64_vec_znx_dft_layout a(n, sa);
 97        fft64_vec_znx_big_layout res(n, sr);
 98        a.fill_dft_random_log2bound(22);
 99        std::vector<znx_i64> expect(sr);
100        for (uint64_t i = 0; i < sr; ++i) {
101          expect[i] = simple_rint_ifft64(a.get_copy_zext(i));
102        }
103        // test the function
104        if (idft_tmp_bytes) {
105          thash hash_before = a.content_hash();
106          idft(module, res.data, sr, a.data, sa, tmp.data());
107          ASSERT_EQ(a.content_hash(), hash_before);
108        } else {
109          idft_tmp_a(module, res.data, sr, a.data, sa);
110        }
111        for (uint64_t i = 0; i < sr; ++i) {
112          znx_i64 actual = res.get_copy_zext(i);
113          // ASSERT_EQ(res.get_copy_zext(i), expect[i]);
114          if (!(actual == expect[i])) {
115            for (uint64_t j = 0; j < n; ++j) {
116              std::cerr << actual.get_coeff(j) << " dft vs. " << expect[i].get_coeff(j) << std::endl;
117            }
118            FAIL();
119          }
120        }
121      }
122    }
123    delete_module_info(module);
124  }
125}
126
127TEST(vec_znx_dft, fft64_vec_znx_idft) {
128  test_fft64_vec_znx_idft(fft64_vec_znx_idft, nullptr, fft64_vec_znx_idft_tmp_bytes);
129}
130TEST(vec_znx_dft, fft64_vec_znx_idft_tmp_a) { test_fft64_vec_znx_idft(nullptr, fft64_vec_znx_idft_tmp_a, nullptr); }
131
132#ifdef __x86_64__
133// FIXME: currently, it only works on avx
134static void test_ntt120_vec_znx_idft(VEC_ZNX_IDFT_F idft, VEC_ZNX_IDFT_TMP_A_F idft_tmp_a,
135                                     VEC_ZNX_IDFT_TMP_BYTES_F idft_tmp_bytes) {
136  for (uint64_t n : {2, 4, 64, 128}) {
137    MODULE* module = new_module_info(n, NTT120);
138    uint64_t tmp_size = idft_tmp_bytes ? idft_tmp_bytes(module) : 0;
139    std::vector<uint8_t> tmp(tmp_size);
140    for (uint64_t sa : {3, 5, 8}) {
141      for (uint64_t sr : {3, 5, 8}) {
142        ntt120_vec_znx_dft_layout a(n, sa);
143        ntt120_vec_znx_big_layout res(n, sr);
144        a.fill_random();
145        std::vector<znx_i128> expect(sr);
146        for (uint64_t i = 0; i < sr; ++i) {
147          expect[i] = simple_intt120(a.get_copy_zext(i));
148        }
149        // test the function
150        if (idft_tmp_bytes) {
151          thash hash_before = a.content_hash();
152          idft(module, res.data, sr, a.data, sa, tmp.data());
153          ASSERT_EQ(a.content_hash(), hash_before);
154        } else {
155          idft_tmp_a(module, res.data, sr, a.data, sa);
156        }
157        for (uint64_t i = 0; i < sr; ++i) {
158          znx_i128 actual = res.get_copy_zext(i);
159          ASSERT_EQ(res.get_copy_zext(i), expect[i]);
160          // if (!(actual == expect[i])) {
161          //   for (uint64_t j = 0; j < n; ++j) {
162          //     std::cerr << actual.get_coeff(j) << " dft vs. " << expect[i].get_coeff(j) << std::endl;
163          //   }
164          //   FAIL();
165          // }
166        }
167      }
168    }
169    delete_module_info(module);
170  }
171}
172
173TEST(vec_znx_dft, ntt120_vec_znx_idft) {
174  test_ntt120_vec_znx_idft(ntt120_vec_znx_idft_avx, nullptr, ntt120_vec_znx_idft_tmp_bytes_avx);
175}
176TEST(vec_znx_dft, ntt120_vec_znx_idft_tmp_a) {
177  test_ntt120_vec_znx_idft(nullptr, ntt120_vec_znx_idft_tmp_a_avx, nullptr);
178}
179#endif
180TEST(vec_znx_dft, vec_znx_idft) {
181  test_fft64_vec_znx_idft(vec_znx_idft, nullptr, vec_znx_idft_tmp_bytes);
182#ifdef __x86_64__
183  // FIXME: currently, only supported on avx
184  test_ntt120_vec_znx_idft(vec_znx_idft, nullptr, vec_znx_idft_tmp_bytes);
185#endif
186}
187TEST(vec_znx_dft, vec_znx_idft_tmp_a) {
188  test_fft64_vec_znx_idft(nullptr, vec_znx_idft_tmp_a, nullptr);
189#ifdef __x86_64__
190  // FIXME: currently, only supported on avx
191  test_ntt120_vec_znx_idft(nullptr, vec_znx_idft_tmp_a, nullptr);
192#endif
193}