poulpy/poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/test/spqlios_coeffs_arithmetic_test.cpp
poulpy-backend/src/cpu_spqlios/spqlios-arithmetic/test/spqlios_coeffs_arithmetic_test.cppRaw
1#include <gtest/gtest.h>
2#include <sys/types.h>
3
4#include <cstdint>
5#include <limits>
6#include <random>
7#include <vector>
8
9#include "../spqlios/coeffs/coeffs_arithmetic.h"
10#include "test/testlib/mod_q120.h"
11#include "testlib/negacyclic_polynomial.h"
12#include "testlib/test_commons.h"
13
14/// tests of element-wise operations
15template <typename T, typename F, typename G>
16void test_elemw_op(F elemw_op, G poly_elemw_op) {
17 for (uint64_t n : {1, 2, 4, 8, 16, 64, 256, 4096}) {
18 polynomial<T> a = polynomial<T>::random(n);
19 polynomial<T> b = polynomial<T>::random(n);
20 polynomial<T> expect(n);
21 polynomial<T> actual(n);
22 // out of place
23 expect = poly_elemw_op(a, b);
24 elemw_op(n, actual.data(), a.data(), b.data());
25 ASSERT_EQ(actual, expect);
26 // in place 1
27 actual = polynomial<T>::random(n);
28 expect = poly_elemw_op(actual, b);
29 elemw_op(n, actual.data(), actual.data(), b.data());
30 ASSERT_EQ(actual, expect);
31 // in place 2
32 actual = polynomial<T>::random(n);
33 expect = poly_elemw_op(a, actual);
34 elemw_op(n, actual.data(), a.data(), actual.data());
35 ASSERT_EQ(actual, expect);
36 // in place 3
37 actual = polynomial<T>::random(n);
38 expect = poly_elemw_op(actual, actual);
39 elemw_op(n, actual.data(), actual.data(), actual.data());
40 ASSERT_EQ(actual, expect);
41 }
42}
43
44static polynomial<int64_t> poly_i64_add(const polynomial<int64_t>& u, polynomial<int64_t>& v) { return u + v; }
45static polynomial<int64_t> poly_i64_sub(const polynomial<int64_t>& u, polynomial<int64_t>& v) { return u - v; }
46TEST(coeffs_arithmetic, znx_add_i64_ref) { test_elemw_op<int64_t>(znx_add_i64_ref, poly_i64_add); }
47TEST(coeffs_arithmetic, znx_sub_i64_ref) { test_elemw_op<int64_t>(znx_sub_i64_ref, poly_i64_sub); }
48#ifdef __x86_64__
49TEST(coeffs_arithmetic, znx_add_i64_avx) { test_elemw_op<int64_t>(znx_add_i64_avx, poly_i64_add); }
50TEST(coeffs_arithmetic, znx_sub_i64_avx) { test_elemw_op<int64_t>(znx_sub_i64_avx, poly_i64_sub); }
51#endif
52
53/// tests of element-wise operations
54template <typename T, typename F, typename G>
55void test_elemw_unary_op(F elemw_op, G poly_elemw_op) {
56 for (uint64_t n : {1, 2, 4, 8, 16, 64, 256, 4096}) {
57 polynomial<T> a = polynomial<T>::random(n);
58 polynomial<T> expect(n);
59 polynomial<T> actual(n);
60 // out of place
61 expect = poly_elemw_op(a);
62 elemw_op(n, actual.data(), a.data());
63 ASSERT_EQ(actual, expect);
64 // in place
65 actual = polynomial<T>::random(n);
66 expect = poly_elemw_op(actual);
67 elemw_op(n, actual.data(), actual.data());
68 ASSERT_EQ(actual, expect);
69 }
70}
71
72static polynomial<int64_t> poly_i64_neg(const polynomial<int64_t>& u) { return -u; }
73static polynomial<int64_t> poly_i64_copy(const polynomial<int64_t>& u) { return u; }
74TEST(coeffs_arithmetic, znx_neg_i64_ref) { test_elemw_unary_op<int64_t>(znx_negate_i64_ref, poly_i64_neg); }
75TEST(coeffs_arithmetic, znx_copy_i64_ref) { test_elemw_unary_op<int64_t>(znx_copy_i64_ref, poly_i64_copy); }
76#ifdef __x86_64__
77TEST(coeffs_arithmetic, znx_neg_i64_avx) { test_elemw_unary_op<int64_t>(znx_negate_i64_avx, poly_i64_neg); }
78#endif
79
80/// tests of the rotations out of place
81template <typename T, typename F>
82void test_rotation_outplace(F rotate) {
83 for (uint64_t n : {1, 2, 4, 8, 16, 64, 256, 4096}) {
84 polynomial<T> poly = polynomial<T>::random(n);
85 polynomial<T> expect(n);
86 polynomial<T> actual(n);
87 for (uint64_t trial = 0; trial < 10; ++trial) {
88 int64_t p = uniform_i64_bits(32);
89 // rotate by p
90 for (uint64_t i = 0; i < n; ++i) {
91 expect.set_coeff(i, poly.get_coeff(i - p));
92 }
93 // rotate using the function
94 rotate(n, p, actual.data(), poly.data());
95 ASSERT_EQ(actual, expect);
96 }
97 }
98}
99
100TEST(coeffs_arithmetic, rnx_rotate_f64) { test_rotation_outplace<double>(rnx_rotate_f64); }
101TEST(coeffs_arithmetic, znx_rotate_i64) { test_rotation_outplace<int64_t>(znx_rotate_i64); }
102
103/// tests of the rotations out of place
104template <typename T, typename F>
105void test_rotation_inplace(F rotate) {
106 for (uint64_t n : {1, 2, 4, 8, 16, 64, 256, 4096}) {
107 polynomial<T> poly = polynomial<T>::random(n);
108 polynomial<T> expect(n);
109 for (uint64_t trial = 0; trial < 10; ++trial) {
110 polynomial<T> actual = poly;
111 int64_t p = uniform_i64_bits(32);
112 // rotate by p
113 for (uint64_t i = 0; i < n; ++i) {
114 expect.set_coeff(i, poly.get_coeff(i - p));
115 }
116 // rotate using the function
117 rotate(n, p, actual.data());
118 ASSERT_EQ(actual, expect);
119 }
120 }
121}
122
123TEST(coeffs_arithmetic, rnx_rotate_inplace_f64) { test_rotation_inplace<double>(rnx_rotate_inplace_f64); }
124
125TEST(coeffs_arithmetic, znx_rotate_inplace_i64) { test_rotation_inplace<int64_t>(znx_rotate_inplace_i64); }
126
127/// tests of the rotations out of place
128template <typename T, typename F>
129void test_mul_xp_minus_one_outplace(F rotate) {
130 for (uint64_t n : {1, 2, 4, 8, 16, 64, 256, 4096}) {
131 polynomial<T> poly = polynomial<T>::random(n);
132 polynomial<T> expect(n);
133 polynomial<T> actual(n);
134 for (uint64_t trial = 0; trial < 10; ++trial) {
135 int64_t p = uniform_i64_bits(32);
136 // rotate by p
137 for (uint64_t i = 0; i < n; ++i) {
138 expect.set_coeff(i, poly.get_coeff(i - p) - poly.get_coeff(i));
139 }
140 // rotate using the function
141 rotate(n, p, actual.data(), poly.data());
142 ASSERT_EQ(actual, expect);
143 }
144 }
145}
146
147TEST(coeffs_arithmetic, rnx_mul_xp_minus_one_f64) { test_mul_xp_minus_one_outplace<double>(rnx_mul_xp_minus_one_f64); }
148TEST(coeffs_arithmetic, znx_mul_xp_minus_one_i64) { test_mul_xp_minus_one_outplace<int64_t>(znx_mul_xp_minus_one_i64); }
149
150/// tests of the rotations out of place
151template <typename T, typename F>
152void test_mul_xp_minus_one_inplace(F rotate) {
153 for (uint64_t n : {1, 2, 4, 8, 16, 64, 256, 4096}) {
154 polynomial<T> poly = polynomial<T>::random(n);
155 polynomial<T> expect(n);
156 for (uint64_t trial = 0; trial < 10; ++trial) {
157 polynomial<T> actual = poly;
158 int64_t p = uniform_i64_bits(32);
159 // rotate by p
160 for (uint64_t i = 0; i < n; ++i) {
161 expect.set_coeff(i, poly.get_coeff(i - p) - poly.get_coeff(i));
162 }
163 // rotate using the function
164 rotate(n, p, actual.data());
165 ASSERT_EQ(actual, expect);
166 }
167 }
168}
169
170TEST(coeffs_arithmetic, rnx_mul_xp_minus_one_inplace_f64) {
171 test_mul_xp_minus_one_inplace<double>(rnx_mul_xp_minus_one_inplace_f64);
172}
173
174// TEST(coeffs_arithmetic, znx_mul_xp_minus_one_inplace_i64) {
175// test_mul_xp_minus_one_inplace<int64_t>(znx_rotate_inplace_i64); }
176/// tests of the automorphisms out of place
177template <typename T, typename F>
178void test_automorphism_outplace(F automorphism) {
179 for (uint64_t n : {1, 2, 4, 8, 16, 64, 256, 4096}) {
180 polynomial<T> poly = polynomial<T>::random(n);
181 polynomial<T> expect(n);
182 polynomial<T> actual(n);
183 for (uint64_t trial = 0; trial < 10; ++trial) {
184 int64_t p = uniform_i64_bits(32) | int64_t(1); // make it odd
185 // automorphism p
186 for (uint64_t i = 0; i < n; ++i) {
187 expect.set_coeff(i * p, poly.get_coeff(i));
188 }
189 // rotate using the function
190 automorphism(n, p, actual.data(), poly.data());
191 ASSERT_EQ(actual, expect);
192 }
193 }
194}
195
196TEST(coeffs_arithmetic, rnx_automorphism_f64) { test_automorphism_outplace<double>(rnx_automorphism_f64); }
197TEST(coeffs_arithmetic, znx_automorphism_i64) { test_automorphism_outplace<int64_t>(znx_automorphism_i64); }
198
199/// tests of the automorphisms out of place
200template <typename T, typename F>
201void test_automorphism_inplace(F automorphism) {
202 for (uint64_t n : {1, 2, 4, 8, 16, 64, 256, 4096, 16384}) {
203 polynomial<T> poly = polynomial<T>::random(n);
204 polynomial<T> expect(n);
205 for (uint64_t trial = 0; trial < 20; ++trial) {
206 polynomial<T> actual = poly;
207 int64_t p = uniform_i64_bits(32) | int64_t(1); // make it odd
208 // automorphism p
209 for (uint64_t i = 0; i < n; ++i) {
210 expect.set_coeff(i * p, poly.get_coeff(i));
211 }
212 automorphism(n, p, actual.data());
213 if (!(actual == expect)) {
214 std::cerr << "automorphism p: " << p << std::endl;
215 for (uint64_t i = 0; i < n; ++i) {
216 std::cerr << i << " " << actual.get_coeff(i) << " vs " << expect.get_coeff(i) << " "
217 << (actual.get_coeff(i) == expect.get_coeff(i)) << std::endl;
218 }
219 }
220 ASSERT_EQ(actual, expect);
221 }
222 }
223}
224TEST(coeffs_arithmetic, rnx_automorphism_inplace_f64) {
225 test_automorphism_inplace<double>(rnx_automorphism_inplace_f64);
226}
227TEST(coeffs_arithmetic, znx_automorphism_inplace_i64) {
228 test_automorphism_inplace<int64_t>(znx_automorphism_inplace_i64);
229}
230
231// TODO: write a test later!
232
233/**
234 * @brief res = (X^p-1).in
235 * @param nn the ring dimension
236 * @param p must be between -2nn <= p <= 2nn
237 * @param in is a rnx/znx vector of dimension nn
238 */
239EXPORT void rnx_mul_xp_minus_one(uint64_t nn, int64_t p, double* res, const double* in);
240EXPORT void znx_mul_xp_minus_one(uint64_t nn, int64_t p, int64_t* res, const int64_t* in);
241
242// normalize with no carry in nor carry out
243template <uint8_t inplace_flag, typename F>
244void test_znx_normalize(F normalize) {
245 for (const uint64_t n : {1, 2, 4, 8, 16, 64, 256, 4096}) {
246 polynomial<int64_t> inp = znx_i64::random_log2bound(n, 62);
247 if (n >= 2) {
248 inp.set_coeff(0, -(INT64_C(1) << 62));
249 inp.set_coeff(1, (INT64_C(1) << 62));
250 }
251 for (const uint64_t base_k : {2, 3, 19, 35, 62}) {
252 polynomial<int64_t> out;
253 int64_t* inp_ptr;
254 if (inplace_flag == 1) {
255 out = polynomial<int64_t>(inp);
256 inp_ptr = out.data();
257 } else {
258 out = polynomial<int64_t>(n);
259 inp_ptr = inp.data();
260 }
261
262 znx_normalize(n, base_k, out.data(), nullptr, inp_ptr, nullptr);
263 for (uint64_t i = 0; i < n; ++i) {
264 const int64_t x = inp.get_coeff(i);
265 const int64_t y = out.get_coeff(i);
266 const int64_t y_exp = centermod(x, INT64_C(1) << base_k);
267 ASSERT_EQ(y, y_exp) << n << " " << base_k << " " << i << " " << x << " " << y;
268 }
269 }
270 }
271}
272
273TEST(coeffs_arithmetic, znx_normalize_outplace) { test_znx_normalize<0>(znx_normalize); }
274TEST(coeffs_arithmetic, znx_normalize_inplace) { test_znx_normalize<1>(znx_normalize); }
275
276// normalize with no carry in nor carry out
277template <uint8_t inplace_flag, bool has_output, typename F>
278void test_znx_normalize_cout(F normalize) {
279 static_assert(inplace_flag < 3, "either out or cout can be inplace with inp");
280 for (const uint64_t n : {1, 2, 4, 8, 16, 64, 256, 4096}) {
281 polynomial<int64_t> inp = znx_i64::random_log2bound(n, 62);
282 if (n >= 2) {
283 inp.set_coeff(0, -(INT64_C(1) << 62));
284 inp.set_coeff(1, (INT64_C(1) << 62));
285 }
286 for (const uint64_t base_k : {2, 3, 19, 35, 62}) {
287 polynomial<int64_t> out, cout;
288 int64_t* inp_ptr;
289 if (inplace_flag == 1) {
290 // out and inp are the same
291 out = polynomial<int64_t>(inp);
292 inp_ptr = out.data();
293 cout = polynomial<int64_t>(n);
294 } else if (inplace_flag == 2) {
295 // carry out and inp are the same
296 cout = polynomial<int64_t>(inp);
297 inp_ptr = cout.data();
298 out = polynomial<int64_t>(n);
299 } else {
300 // inp, out and carry out are distinct
301 out = polynomial<int64_t>(n);
302 cout = polynomial<int64_t>(n);
303 inp_ptr = inp.data();
304 }
305
306 znx_normalize(n, base_k, has_output ? out.data() : nullptr, cout.data(), inp_ptr, nullptr);
307 for (uint64_t i = 0; i < n; ++i) {
308 const int64_t x = inp.get_coeff(i);
309 const int64_t co = cout.get_coeff(i);
310 const int64_t y_exp = centermod((int64_t)x, INT64_C(1) << base_k);
311 const int64_t co_exp = (x - y_exp) >> base_k;
312 ASSERT_EQ(co, co_exp);
313
314 if (has_output) {
315 const int64_t y = out.get_coeff(i);
316 ASSERT_EQ(y, y_exp);
317 }
318 }
319 }
320 }
321}
322
323TEST(coeffs_arithmetic, znx_normalize_cout_outplace) { test_znx_normalize_cout<0, false>(znx_normalize); }
324TEST(coeffs_arithmetic, znx_normalize_out_cout_outplace) { test_znx_normalize_cout<0, true>(znx_normalize); }
325TEST(coeffs_arithmetic, znx_normalize_cout_inplace1) { test_znx_normalize_cout<1, false>(znx_normalize); }
326TEST(coeffs_arithmetic, znx_normalize_out_cout_inplace1) { test_znx_normalize_cout<1, true>(znx_normalize); }
327TEST(coeffs_arithmetic, znx_normalize_cout_inplace2) { test_znx_normalize_cout<2, false>(znx_normalize); }
328TEST(coeffs_arithmetic, znx_normalize_out_cout_inplace2) { test_znx_normalize_cout<2, true>(znx_normalize); }
329
330// normalize with no carry in nor carry out
331template <uint8_t inplace_flag, typename F>
332void test_znx_normalize_cin(F normalize) {
333 static_assert(inplace_flag < 3, "either inp or cin can be inplace with out");
334 for (const uint64_t n : {1, 2, 4, 8, 16, 64, 256, 4096}) {
335 polynomial<int64_t> inp = znx_i64::random_log2bound(n, 62);
336 if (n >= 4) {
337 inp.set_coeff(0, -(INT64_C(1) << 62));
338 inp.set_coeff(1, -(INT64_C(1) << 62));
339 inp.set_coeff(2, (INT64_C(1) << 62));
340 inp.set_coeff(3, (INT64_C(1) << 62));
341 }
342 for (const uint64_t base_k : {2, 3, 19, 35, 62}) {
343 polynomial<int64_t> cin = znx_i64::random_log2bound(n, 62);
344 if (n >= 4) {
345 inp.set_coeff(0, -(INT64_C(1) << 62));
346 inp.set_coeff(1, (INT64_C(1) << 62));
347 inp.set_coeff(0, -(INT64_C(1) << 62));
348 inp.set_coeff(1, (INT64_C(1) << 62));
349 }
350
351 polynomial<int64_t> out;
352 int64_t *inp_ptr, *cin_ptr;
353 if (inplace_flag == 1) {
354 // out and inp are the same
355 out = polynomial<int64_t>(inp);
356 inp_ptr = out.data();
357 cin_ptr = cin.data();
358 } else if (inplace_flag == 2) {
359 // out and carry in are the same
360 out = polynomial<int64_t>(cin);
361 inp_ptr = inp.data();
362 cin_ptr = out.data();
363 } else {
364 // inp, carry in and out are distinct
365 out = polynomial<int64_t>(n);
366 inp_ptr = inp.data();
367 cin_ptr = cin.data();
368 }
369
370 znx_normalize(n, base_k, out.data(), nullptr, inp_ptr, cin_ptr);
371 for (uint64_t i = 0; i < n; ++i) {
372 const int64_t x = inp.get_coeff(i);
373 const int64_t ci = cin.get_coeff(i);
374 const int64_t y = out.get_coeff(i);
375
376 const __int128_t xp = (__int128_t)x + ci;
377 const int64_t y_exp = centermod((int64_t)xp, INT64_C(1) << base_k);
378
379 ASSERT_EQ(y, y_exp) << n << " " << base_k << " " << i << " " << x << " " << y << " " << ci;
380 }
381 }
382 }
383}
384
385TEST(coeffs_arithmetic, znx_normalize_cin_outplace) { test_znx_normalize_cin<0>(znx_normalize); }
386TEST(coeffs_arithmetic, znx_normalize_cin_inplace1) { test_znx_normalize_cin<1>(znx_normalize); }
387TEST(coeffs_arithmetic, znx_normalize_cin_inplace2) { test_znx_normalize_cin<2>(znx_normalize); }
388
389// normalize with no carry in nor carry out
390template <uint8_t inplace_flag, bool has_output, typename F>
391void test_znx_normalize_cin_cout(F normalize) {
392 static_assert(inplace_flag < 7, "either inp or cin can be inplace with out");
393 for (const uint64_t n : {1, 2, 4, 8, 16, 64, 256, 4096}) {
394 polynomial<int64_t> inp = znx_i64::random_log2bound(n, 62);
395 if (n >= 4) {
396 inp.set_coeff(0, -(INT64_C(1) << 62));
397 inp.set_coeff(1, -(INT64_C(1) << 62));
398 inp.set_coeff(2, (INT64_C(1) << 62));
399 inp.set_coeff(3, (INT64_C(1) << 62));
400 }
401 for (const uint64_t base_k : {2, 3, 19, 35, 62}) {
402 polynomial<int64_t> cin = znx_i64::random_log2bound(n, 62);
403 if (n >= 4) {
404 inp.set_coeff(0, -(INT64_C(1) << 62));
405 inp.set_coeff(1, (INT64_C(1) << 62));
406 inp.set_coeff(0, -(INT64_C(1) << 62));
407 inp.set_coeff(1, (INT64_C(1) << 62));
408 }
409
410 polynomial<int64_t> out, cout;
411 int64_t *inp_ptr, *cin_ptr;
412 if (inplace_flag == 1) {
413 // out == inp
414 out = polynomial<int64_t>(inp);
415 cout = polynomial<int64_t>(n);
416 inp_ptr = out.data();
417 cin_ptr = cin.data();
418 } else if (inplace_flag == 2) {
419 // cout == inp
420 out = polynomial<int64_t>(n);
421 cout = polynomial<int64_t>(inp);
422 inp_ptr = cout.data();
423 cin_ptr = cin.data();
424 } else if (inplace_flag == 3) {
425 // out == cin
426 out = polynomial<int64_t>(cin);
427 cout = polynomial<int64_t>(n);
428 inp_ptr = inp.data();
429 cin_ptr = out.data();
430 } else if (inplace_flag == 4) {
431 // cout == cin
432 out = polynomial<int64_t>(n);
433 cout = polynomial<int64_t>(cin);
434 inp_ptr = inp.data();
435 cin_ptr = cout.data();
436 } else if (inplace_flag == 5) {
437 // out == inp, cout == cin
438 out = polynomial<int64_t>(inp);
439 cout = polynomial<int64_t>(cin);
440 inp_ptr = out.data();
441 cin_ptr = cout.data();
442 } else if (inplace_flag == 6) {
443 // out == cin, cout == inp
444 out = polynomial<int64_t>(cin);
445 cout = polynomial<int64_t>(inp);
446 inp_ptr = cout.data();
447 cin_ptr = out.data();
448 } else {
449 out = polynomial<int64_t>(n);
450 cout = polynomial<int64_t>(n);
451 inp_ptr = inp.data();
452 cin_ptr = cin.data();
453 }
454
455 znx_normalize(n, base_k, has_output ? out.data() : nullptr, cout.data(), inp_ptr, cin_ptr);
456 for (uint64_t i = 0; i < n; ++i) {
457 const int64_t x = inp.get_coeff(i);
458 const int64_t ci = cin.get_coeff(i);
459 const int64_t co = cout.get_coeff(i);
460
461 const __int128_t xp = (__int128_t)x + ci;
462 const int64_t y_exp = centermod((int64_t)xp, INT64_C(1) << base_k);
463 const int64_t co_exp = (xp - y_exp) >> base_k;
464 ASSERT_EQ(co, co_exp);
465
466 if (has_output) {
467 const int64_t y = out.get_coeff(i);
468 ASSERT_EQ(y, y_exp);
469 }
470 }
471 }
472 }
473}
474
475TEST(coeffs_arithmetic, znx_normalize_cin_cout_outplace) { test_znx_normalize_cin_cout<0, false>(znx_normalize); }
476TEST(coeffs_arithmetic, znx_normalize_out_cin_cout_outplace) { test_znx_normalize_cin_cout<0, true>(znx_normalize); }
477TEST(coeffs_arithmetic, znx_normalize_cin_cout_inplace1) { test_znx_normalize_cin_cout<1, false>(znx_normalize); }
478TEST(coeffs_arithmetic, znx_normalize_out_cin_cout_inplace1) { test_znx_normalize_cin_cout<1, true>(znx_normalize); }
479TEST(coeffs_arithmetic, znx_normalize_cin_cout_inplace2) { test_znx_normalize_cin_cout<2, false>(znx_normalize); }
480TEST(coeffs_arithmetic, znx_normalize_out_cin_cout_inplace2) { test_znx_normalize_cin_cout<2, true>(znx_normalize); }
481TEST(coeffs_arithmetic, znx_normalize_cin_cout_inplace3) { test_znx_normalize_cin_cout<3, false>(znx_normalize); }
482TEST(coeffs_arithmetic, znx_normalize_out_cin_cout_inplace3) { test_znx_normalize_cin_cout<3, true>(znx_normalize); }
483TEST(coeffs_arithmetic, znx_normalize_cin_cout_inplace4) { test_znx_normalize_cin_cout<4, false>(znx_normalize); }
484TEST(coeffs_arithmetic, znx_normalize_out_cin_cout_inplace4) { test_znx_normalize_cin_cout<4, true>(znx_normalize); }
485TEST(coeffs_arithmetic, znx_normalize_cin_cout_inplace5) { test_znx_normalize_cin_cout<5, false>(znx_normalize); }
486TEST(coeffs_arithmetic, znx_normalize_out_cin_cout_inplace5) { test_znx_normalize_cin_cout<5, true>(znx_normalize); }
487TEST(coeffs_arithmetic, znx_normalize_cin_cout_inplace6) { test_znx_normalize_cin_cout<6, false>(znx_normalize); }
488TEST(coeffs_arithmetic, znx_normalize_out_cin_cout_inplace6) { test_znx_normalize_cin_cout<6, true>(znx_normalize); }