arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/test/spqlios_vec_rnx_test.cpp
poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/test/spqlios_vec_rnx_test.cppRaw
  1#include <gtest/gtest.h>
  2
  3#include "spqlios/arithmetic/vec_rnx_arithmetic_private.h"
  4#include "spqlios/reim/reim_fft.h"
  5#include "testlib/vec_rnx_layout.h"
  6
  7// disabling this test by default, since it depicts on purpose wrong accesses
  8#if 0
  9TEST(rnx_layout, valgrind_antipattern_test) {
 10  uint64_t n = 4;
 11  rnx_vec_f64_layout v(n, 7, 13);
 12  // this should be ok
 13  v.set(0, rnx_f64::zero(n));
 14  // this should abort (wrong ring dimension)
 15  ASSERT_DEATH(v.set(3, rnx_f64::zero(2 * n)), "");
 16  // this should abort (out of bounds)
 17  ASSERT_DEATH(v.set(8, rnx_f64::zero(n)), "");
 18  // this should be ok
 19  ASSERT_EQ(v.get_copy_zext(0), rnx_f64::zero(n));
 20  // should be an uninit read
 21  ASSERT_TRUE(!(v.get_copy_zext(2) == rnx_f64::zero(n)));  // should be uninit
 22  // should be an invalid read (inter-slice)
 23  ASSERT_NE(v.data()[4], 0);
 24  ASSERT_EQ(v.data()[2], 0);  // should be ok
 25  // should be an uninit read
 26  ASSERT_NE(v.data()[13], 0);  // should be uninit
 27}
 28#endif
 29
 30// test of binary operations
 31
 32// test for out of place calls
 33template <typename ACTUAL_FCN, typename EXPECT_FCN>
 34void test_vec_rnx_elemw_binop_outplace(ACTUAL_FCN binop, EXPECT_FCN ref_binop) {
 35  for (uint64_t n : {2, 4, 8, 128}) {
 36    RNX_MODULE_TYPE mtype = FFT64;
 37    MOD_RNX* mod = new_rnx_module_info(n, mtype);
 38    for (uint64_t sa : {7, 13, 15}) {
 39      for (uint64_t sb : {7, 13, 15}) {
 40        for (uint64_t sc : {7, 13, 15}) {
 41          uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
 42          uint64_t b_sl = uniform_u64_bits(3) * 5 + n;
 43          uint64_t c_sl = uniform_u64_bits(3) * 5 + n;
 44          rnx_vec_f64_layout la(n, sa, a_sl);
 45          rnx_vec_f64_layout lb(n, sb, b_sl);
 46          rnx_vec_f64_layout lc(n, sc, c_sl);
 47          std::vector<rnx_f64> expect(sc);
 48          for (uint64_t i = 0; i < sa; ++i) {
 49            la.set(i, rnx_f64::random_log2bound(n, 1.));
 50          }
 51          for (uint64_t i = 0; i < sb; ++i) {
 52            lb.set(i, rnx_f64::random_log2bound(n, 1.));
 53          }
 54          for (uint64_t i = 0; i < sc; ++i) {
 55            expect[i] = ref_binop(la.get_copy_zext(i), lb.get_copy_zext(i));
 56          }
 57          binop(mod,                  // N
 58                lc.data(), sc, c_sl,  // res
 59                la.data(), sa, a_sl,  // a
 60                lb.data(), sb, b_sl);
 61          for (uint64_t i = 0; i < sc; ++i) {
 62            ASSERT_EQ(lc.get_copy_zext(i), expect[i]);
 63          }
 64        }
 65      }
 66    }
 67    delete_rnx_module_info(mod);
 68  }
 69}
 70// test for inplace1 calls
 71template <typename ACTUAL_FCN, typename EXPECT_FCN>
 72void test_vec_rnx_elemw_binop_inplace1(ACTUAL_FCN binop, EXPECT_FCN ref_binop) {
 73  for (uint64_t n : {2, 4, 64}) {
 74    RNX_MODULE_TYPE mtype = FFT64;
 75    MOD_RNX* mod = new_rnx_module_info(n, mtype);
 76    for (uint64_t sa : {3, 9, 12}) {
 77      for (uint64_t sb : {3, 9, 12}) {
 78        uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
 79        uint64_t b_sl = uniform_u64_bits(3) * 5 + n;
 80        rnx_vec_f64_layout la(n, sa, a_sl);
 81        rnx_vec_f64_layout lb(n, sb, b_sl);
 82        std::vector<rnx_f64> expect(sa);
 83        for (uint64_t i = 0; i < sa; ++i) {
 84          la.set(i, rnx_f64::random_log2bound(n, 1.));
 85        }
 86        for (uint64_t i = 0; i < sb; ++i) {
 87          lb.set(i, rnx_f64::random_log2bound(n, 1.));
 88        }
 89        for (uint64_t i = 0; i < sa; ++i) {
 90          expect[i] = ref_binop(la.get_copy_zext(i), lb.get_copy_zext(i));
 91        }
 92        binop(mod,                  // N
 93              la.data(), sa, a_sl,  // res
 94              la.data(), sa, a_sl,  // a
 95              lb.data(), sb, b_sl);
 96        for (uint64_t i = 0; i < sa; ++i) {
 97          ASSERT_EQ(la.get_copy_zext(i), expect[i]);
 98        }
 99      }
100    }
101    delete_rnx_module_info(mod);
102  }
103}
104// test for inplace2 calls
105template <typename ACTUAL_FCN, typename EXPECT_FCN>
106void test_vec_rnx_elemw_binop_inplace2(ACTUAL_FCN binop, EXPECT_FCN ref_binop) {
107  for (uint64_t n : {4, 32, 64}) {
108    RNX_MODULE_TYPE mtype = FFT64;
109    MOD_RNX* mod = new_rnx_module_info(n, mtype);
110    for (uint64_t sa : {3, 9, 12}) {
111      for (uint64_t sb : {3, 9, 12}) {
112        uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
113        uint64_t b_sl = uniform_u64_bits(3) * 5 + n;
114        rnx_vec_f64_layout la(n, sa, a_sl);
115        rnx_vec_f64_layout lb(n, sb, b_sl);
116        std::vector<rnx_f64> expect(sb);
117        for (uint64_t i = 0; i < sa; ++i) {
118          la.set(i, rnx_f64::random_log2bound(n, 1.));
119        }
120        for (uint64_t i = 0; i < sb; ++i) {
121          lb.set(i, rnx_f64::random_log2bound(n, 1.));
122        }
123        for (uint64_t i = 0; i < sb; ++i) {
124          expect[i] = ref_binop(la.get_copy_zext(i), lb.get_copy_zext(i));
125        }
126        binop(mod,                  // N
127              lb.data(), sb, b_sl,  // res
128              la.data(), sa, a_sl,  // a
129              lb.data(), sb, b_sl);
130        for (uint64_t i = 0; i < sb; ++i) {
131          ASSERT_EQ(lb.get_copy_zext(i), expect[i]);
132        }
133      }
134    }
135    delete_rnx_module_info(mod);
136  }
137}
138// test for inplace3 calls
139template <typename ACTUAL_FCN, typename EXPECT_FCN>
140void test_vec_rnx_elemw_binop_inplace3(ACTUAL_FCN binop, EXPECT_FCN ref_binop) {
141  for (uint64_t n : {2, 16, 1024}) {
142    RNX_MODULE_TYPE mtype = FFT64;
143    MOD_RNX* mod = new_rnx_module_info(n, mtype);
144    for (uint64_t sa : {2, 6, 11}) {
145      uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
146      rnx_vec_f64_layout la(n, sa, a_sl);
147      std::vector<rnx_f64> expect(sa);
148      for (uint64_t i = 0; i < sa; ++i) {
149        la.set(i, rnx_f64::random_log2bound(n, 1.));
150      }
151      for (uint64_t i = 0; i < sa; ++i) {
152        expect[i] = ref_binop(la.get_copy_zext(i), la.get_copy_zext(i));
153      }
154      binop(mod,                  // N
155            la.data(), sa, a_sl,  // res
156            la.data(), sa, a_sl,  // a
157            la.data(), sa, a_sl);
158      for (uint64_t i = 0; i < sa; ++i) {
159        ASSERT_EQ(la.get_copy_zext(i), expect[i]);
160      }
161    }
162    delete_rnx_module_info(mod);
163  }
164}
165template <typename ACTUAL_FCN, typename EXPECT_FCN>
166void test_vec_rnx_elemw_binop(ACTUAL_FCN binop, EXPECT_FCN ref_binop) {
167  test_vec_rnx_elemw_binop_outplace(binop, ref_binop);
168  test_vec_rnx_elemw_binop_inplace1(binop, ref_binop);
169  test_vec_rnx_elemw_binop_inplace2(binop, ref_binop);
170  test_vec_rnx_elemw_binop_inplace3(binop, ref_binop);
171}
172
173static rnx_f64 poly_add(const rnx_f64& a, const rnx_f64& b) { return a + b; }
174static rnx_f64 poly_sub(const rnx_f64& a, const rnx_f64& b) { return a - b; }
175TEST(vec_rnx, vec_rnx_add) { test_vec_rnx_elemw_binop(vec_rnx_add, poly_add); }
176TEST(vec_rnx, vec_rnx_add_ref) { test_vec_rnx_elemw_binop(vec_rnx_add_ref, poly_add); }
177#ifdef __x86_64__
178TEST(vec_rnx, vec_rnx_add_avx) { test_vec_rnx_elemw_binop(vec_rnx_add_avx, poly_add); }
179#endif
180TEST(vec_rnx, vec_rnx_sub) { test_vec_rnx_elemw_binop(vec_rnx_sub, poly_sub); }
181TEST(vec_rnx, vec_rnx_sub_ref) { test_vec_rnx_elemw_binop(vec_rnx_sub_ref, poly_sub); }
182#ifdef __x86_64__
183TEST(vec_rnx, vec_rnx_sub_avx) { test_vec_rnx_elemw_binop(vec_rnx_sub_avx, poly_sub); }
184#endif
185
186// test for out of place calls
187template <typename ACTUAL_FCN, typename EXPECT_FCN>
188void test_vec_rnx_elemw_unop_param_outplace(ACTUAL_FCN test_mul_xp_minus_one, EXPECT_FCN ref_mul_xp_minus_one,
189                                            int64_t (*param_gen)()) {
190  for (uint64_t n : {2, 4, 8, 128}) {
191    MOD_RNX* mod = new_rnx_module_info(n, FFT64);
192    for (uint64_t sa : {7, 13, 15}) {
193      for (uint64_t sb : {7, 13, 15}) {
194        {
195          int64_t p = param_gen();
196          uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
197          uint64_t b_sl = uniform_u64_bits(3) * 4 + n;
198          rnx_vec_f64_layout la(n, sa, a_sl);
199          rnx_vec_f64_layout lb(n, sb, b_sl);
200          std::vector<rnx_f64> expect(sb);
201          for (uint64_t i = 0; i < sa; ++i) {
202            la.set(i, rnx_f64::random_log2bound(n, 0));
203          }
204          for (uint64_t i = 0; i < sb; ++i) {
205            expect[i] = ref_mul_xp_minus_one(p, la.get_copy_zext(i));
206          }
207          test_mul_xp_minus_one(mod,                  //
208                                p,                    //
209                                lb.data(), sb, b_sl,  //
210                                la.data(), sa, a_sl   //
211          );
212          for (uint64_t i = 0; i < sb; ++i) {
213            ASSERT_EQ(lb.get_copy_zext(i), expect[i]) << n << " " << sa << " " << sb << " " << i;
214          }
215        }
216      }
217    }
218    delete_rnx_module_info(mod);
219  }
220}
221
222// test for inplace calls
223template <typename ACTUAL_FCN, typename EXPECT_FCN>
224void test_vec_rnx_elemw_unop_param_inplace(ACTUAL_FCN actual_function, EXPECT_FCN ref_function,
225                                           int64_t (*param_gen)()) {
226  for (uint64_t n : {2, 16, 1024}) {
227    MOD_RNX* mod = new_rnx_module_info(n, FFT64);
228    for (uint64_t sa : {2, 6, 11}) {
229      {
230        int64_t p = param_gen();
231        uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
232        rnx_vec_f64_layout la(n, sa, a_sl);
233        std::vector<rnx_f64> expect(sa);
234        for (uint64_t i = 0; i < sa; ++i) {
235          la.set(i, rnx_f64::random_log2bound(n, 0));
236        }
237        for (uint64_t i = 0; i < sa; ++i) {
238          expect[i] = ref_function(p, la.get_copy_zext(i));
239        }
240        actual_function(mod,                  // N
241                        p,                    //;
242                        la.data(), sa, a_sl,  // res
243                        la.data(), sa, a_sl   // a
244        );
245        for (uint64_t i = 0; i < sa; ++i) {
246          ASSERT_EQ(la.get_copy_zext(i), expect[i]) << n << " " << sa << " " << i;
247        }
248      }
249    }
250    delete_rnx_module_info(mod);
251  }
252}
253
254static int64_t random_mul_xp_minus_one_param() { return uniform_i64(); }
255static int64_t random_automorphism_param() { return 2 * uniform_i64() + 1; }
256static int64_t random_rotation_param() { return uniform_i64(); }
257
258template <typename ACTUAL_FCN, typename EXPECT_FCN>
259void test_vec_rnx_elemw_mul_xp_minus_one(ACTUAL_FCN binop, EXPECT_FCN ref_binop) {
260  test_vec_rnx_elemw_unop_param_outplace(binop, ref_binop, random_mul_xp_minus_one_param);
261  test_vec_rnx_elemw_unop_param_inplace(binop, ref_binop, random_mul_xp_minus_one_param);
262}
263template <typename ACTUAL_FCN, typename EXPECT_FCN>
264void test_vec_rnx_elemw_rotate(ACTUAL_FCN binop, EXPECT_FCN ref_binop) {
265  test_vec_rnx_elemw_unop_param_outplace(binop, ref_binop, random_rotation_param);
266  test_vec_rnx_elemw_unop_param_inplace(binop, ref_binop, random_rotation_param);
267}
268template <typename ACTUAL_FCN, typename EXPECT_FCN>
269void test_vec_rnx_elemw_automorphism(ACTUAL_FCN binop, EXPECT_FCN ref_binop) {
270  test_vec_rnx_elemw_unop_param_outplace(binop, ref_binop, random_automorphism_param);
271  test_vec_rnx_elemw_unop_param_inplace(binop, ref_binop, random_automorphism_param);
272}
273
274static rnx_f64 poly_mul_xp_minus_one(const int64_t p, const rnx_f64& a) {
275  uint64_t n = a.nn();
276  rnx_f64 res(n);
277  for (uint64_t i = 0; i < n; ++i) {
278    res.set_coeff(i, a.get_coeff(i - p) - a.get_coeff(i));
279  }
280  return res;
281}
282static rnx_f64 poly_rotate(const int64_t p, const rnx_f64& a) {
283  uint64_t n = a.nn();
284  rnx_f64 res(n);
285  for (uint64_t i = 0; i < n; ++i) {
286    res.set_coeff(i, a.get_coeff(i - p));
287  }
288  return res;
289}
290static rnx_f64 poly_automorphism(const int64_t p, const rnx_f64& a) {
291  uint64_t n = a.nn();
292  rnx_f64 res(n);
293  for (uint64_t i = 0; i < n; ++i) {
294    res.set_coeff(i * p, a.get_coeff(i));
295  }
296  return res;
297}
298
299TEST(vec_rnx, vec_rnx_mul_xp_minus_one) {
300  test_vec_rnx_elemw_mul_xp_minus_one(vec_rnx_mul_xp_minus_one, poly_mul_xp_minus_one);
301}
302TEST(vec_rnx, vec_rnx_mul_xp_minus_one_ref) {
303  test_vec_rnx_elemw_mul_xp_minus_one(vec_rnx_mul_xp_minus_one_ref, poly_mul_xp_minus_one);
304}
305
306TEST(vec_rnx, vec_rnx_rotate) { test_vec_rnx_elemw_rotate(vec_rnx_rotate, poly_rotate); }
307TEST(vec_rnx, vec_rnx_rotate_ref) { test_vec_rnx_elemw_rotate(vec_rnx_rotate_ref, poly_rotate); }
308TEST(vec_rnx, vec_rnx_automorphism) { test_vec_rnx_elemw_automorphism(vec_rnx_automorphism, poly_automorphism); }
309TEST(vec_rnx, vec_rnx_automorphism_ref) {
310  test_vec_rnx_elemw_automorphism(vec_rnx_automorphism_ref, poly_automorphism);
311}
312
313// test for out of place calls
314template <typename ACTUAL_FCN, typename EXPECT_FCN>
315void test_vec_rnx_elemw_unop_outplace(ACTUAL_FCN actual_function, EXPECT_FCN ref_function) {
316  for (uint64_t n : {2, 4, 8, 128}) {
317    MOD_RNX* mod = new_rnx_module_info(n, FFT64);
318    for (uint64_t sa : {7, 13, 15}) {
319      for (uint64_t sb : {7, 13, 15}) {
320        {
321          uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
322          uint64_t b_sl = uniform_u64_bits(3) * 4 + n;
323          rnx_vec_f64_layout la(n, sa, a_sl);
324          rnx_vec_f64_layout lb(n, sb, b_sl);
325          std::vector<rnx_f64> expect(sb);
326          for (uint64_t i = 0; i < sa; ++i) {
327            la.set(i, rnx_f64::random_log2bound(n, 0));
328          }
329          for (uint64_t i = 0; i < sb; ++i) {
330            expect[i] = ref_function(la.get_copy_zext(i));
331          }
332          actual_function(mod,                  //
333                          lb.data(), sb, b_sl,  //
334                          la.data(), sa, a_sl   //
335          );
336          for (uint64_t i = 0; i < sb; ++i) {
337            ASSERT_EQ(lb.get_copy_zext(i), expect[i]) << n << " " << sa << " " << sb << " " << i;
338          }
339        }
340      }
341    }
342    delete_rnx_module_info(mod);
343  }
344}
345
346// test for inplace calls
347template <typename ACTUAL_FCN, typename EXPECT_FCN>
348void test_vec_rnx_elemw_unop_inplace(ACTUAL_FCN actual_function, EXPECT_FCN ref_function) {
349  for (uint64_t n : {2, 16, 1024}) {
350    MOD_RNX* mod = new_rnx_module_info(n, FFT64);
351    for (uint64_t sa : {2, 6, 11}) {
352      {
353        uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
354        rnx_vec_f64_layout la(n, sa, a_sl);
355        std::vector<rnx_f64> expect(sa);
356        for (uint64_t i = 0; i < sa; ++i) {
357          la.set(i, rnx_f64::random_log2bound(n, 0));
358        }
359        for (uint64_t i = 0; i < sa; ++i) {
360          expect[i] = ref_function(la.get_copy_zext(i));
361        }
362        actual_function(mod,                  // N
363                        la.data(), sa, a_sl,  // res
364                        la.data(), sa, a_sl   // a
365        );
366        for (uint64_t i = 0; i < sa; ++i) {
367          ASSERT_EQ(la.get_copy_zext(i), expect[i]) << n << " " << sa << " " << i;
368        }
369      }
370    }
371    delete_rnx_module_info(mod);
372  }
373}
374template <typename ACTUAL_FCN, typename EXPECT_FCN>
375void test_vec_rnx_elemw_unop(ACTUAL_FCN unnop, EXPECT_FCN ref_unnop) {
376  test_vec_rnx_elemw_unop_outplace(unnop, ref_unnop);
377  test_vec_rnx_elemw_unop_inplace(unnop, ref_unnop);
378}
379
380static rnx_f64 poly_copy(const rnx_f64& a) { return a; }
381static rnx_f64 poly_negate(const rnx_f64& a) { return -a; }
382
383TEST(vec_rnx, vec_rnx_copy) { test_vec_rnx_elemw_unop(vec_rnx_copy, poly_copy); }
384TEST(vec_rnx, vec_rnx_copy_ref) { test_vec_rnx_elemw_unop(vec_rnx_copy_ref, poly_copy); }
385TEST(vec_rnx, vec_rnx_negate) { test_vec_rnx_elemw_unop(vec_rnx_negate, poly_negate); }
386TEST(vec_rnx, vec_rnx_negate_ref) { test_vec_rnx_elemw_unop(vec_rnx_negate_ref, poly_negate); }
387#ifdef __x86_64__
388TEST(vec_rnx, vec_rnx_negate_avx) { test_vec_rnx_elemw_unop(vec_rnx_negate_avx, poly_negate); }
389#endif
390
391// test for inplace calls
392void test_vec_rnx_zero(VEC_RNX_ZERO_F actual_function) {
393  for (uint64_t n : {2, 16, 1024}) {
394    MOD_RNX* mod = new_rnx_module_info(n, FFT64);
395    for (uint64_t sa : {2, 6, 11}) {
396      {
397        uint64_t a_sl = uniform_u64_bits(3) * 5 + n;
398        rnx_vec_f64_layout la(n, sa, a_sl);
399        const rnx_f64 ZERO = rnx_f64::zero(n);
400        for (uint64_t i = 0; i < sa; ++i) {
401          la.set(i, rnx_f64::random_log2bound(n, 0));
402        }
403        actual_function(mod,                 // N
404                        la.data(), sa, a_sl  // res
405        );
406        for (uint64_t i = 0; i < sa; ++i) {
407          ASSERT_EQ(la.get_copy_zext(i), ZERO) << n << " " << sa << " " << i;
408        }
409      }
410    }
411    delete_rnx_module_info(mod);
412  }
413}
414
415TEST(vec_rnx, vec_rnx_zero) { test_vec_rnx_zero(vec_rnx_zero); }
416
417TEST(vec_rnx, vec_rnx_zero_ref) { test_vec_rnx_zero(vec_rnx_zero_ref); }