Orbiter 2022
Combinatorial Objects
number_theoretic_transform.cpp
Go to the documentation of this file.
1/*
2 * number_theoretic_transform.cpp
3 *
4 * Created on: Jun 19, 2020
5 * Author: betten
6 */
7
8
9
10
11#include "foundations.h"
12
13using namespace std;
14
15
16
17namespace orbiter {
18namespace layer1_foundations {
19namespace number_theory {
20
21
22static void ntt4_forward(int *input, int *output, field_theory::finite_field *F);
23static void ntt4_backward(int *input, int *output, field_theory::finite_field *F);
24
25
27{
28 k = 0;
29 q = 0;
30
31 //std::string fname_code;
32
33 F = NULL;
34 N = NULL;
35
36 alpha = omega = 0;
38
39 A = Av = NULL;
40 A_log = NULL;
41 Omega = NULL;
42
43 G = D = Dv = T = Tv = P = NULL;
44
45 X = Y = Z = NULL;
46 X1 = X2 = Y1 = Y2 = NULL;
47
48 Gr = Dr = Dvr = Tr = Tvr = Pr = NULL;
49
50 Tmp1 = Tmp2 = NULL;
51
52 bit_reversal = NULL;
53
54 Q = 0;
55 FQ = NULL;
56 alphaQ = 0;
57 psi = 0;
58
59 Psi_powers = NULL;
60
61 //null();
62}
63
65{
66}
67
69 int k, int q, int verbose_level)
70{
71 int f_v = (verbose_level >= 1);
72 int idx, i, j, h;
73 int nb_m10, nb_m11, nb_a10, nb_a11;
74 int nb_m20, nb_m21, nb_a20, nb_a21;
75 int nb_m1, nb_a1;
76 int nb_m2, nb_a2;
77
79
80
81 if (f_v) {
82 cout << "number_theoretic_transform::init" << endl;
83 cout << "number_theoretic_transform::init k = " << k << " q=" << q << endl;
84 }
85
89
90 fname_code.assign("NTT_");
91 char str[1000];
92
93 sprintf(str, "k%d_q%d.cpp", k, q);
94 fname_code.append(str);
95
96
97 //F = NEW_OBJECT(finite_field);
98 //F->finite_field_init(q, FALSE /* f_without_tables */, 0 /* verbose_level */);
99
100
101 minus_one = F->negate(1);
103 if (f_v) {
104 cout << "alpha = " << alpha << endl;
105 }
106 Omega = NEW_int(k + 1);
107 A = NEW_pint(k + 1);
108 Av = NEW_pint(k + 1);
109 A_log = NEW_pint(k + 1);
110 N = NEW_int(k + 1);
111
112 for (h = 0; h <= k; h++) {
113 N[h] = 1 << h;
114 }
115
116 cout << "N[]:" << endl;
117 Int_matrix_print(N, k + 1, 1);
118
119 idx = (q - 1) / N[k];
120 omega = F->power(alpha, idx);
121 if (f_v) {
122 cout << "idx = " << idx << endl;
123 cout << "omega = " << omega << endl;
124 }
125
126 Tmp1 = NEW_int(N[k] * N[k]);
127 Tmp2 = NEW_int(N[k] * N[k]);
128
129 F->Linear_algebra->make_Fourier_matrices(omega, k, N, A, Av, Omega, verbose_level);
130
131 for (h = k; h >= 1; h--) {
132 char str[1000];
133 string fname;
135
136 sprintf(str, "Fourier_q%d_N%d.csv", q, N[h]);
137 fname.assign(str);
138 Fio.int_matrix_write_csv(fname, A[h], N[h], N[h]);
139 }
140
141
142 {
143
144
145 Psi_powers = NEW_int(N[k]);
146 Q = q * q;
148 FQ->finite_field_init(Q, FALSE /* f_without_tables */, 0);
150
151 psi = FQ->power(alphaQ, (q + 1) >> 1);
152 Psi_powers[0] = 1;
153 for (i = 1; i < N[k]; i++) {
154 Psi_powers[i] = FQ->mult(Psi_powers[i - 1], psi);
155 }
156
157 if (f_v) {
158 cout << "alphaQ=" << alphaQ << endl;
159 cout << "psi=" << psi << endl;
160 cout << "Psi_powers:" << endl;
162 }
163
164
165 }
166
167
168 cout << "Omega:" << endl;
169 Int_matrix_print(Omega, k + 1, 1);
170
171
172 cout << "h : N[h] : Omega[h] : multiplicative_order : Omega[h]^2" << endl;
173 for (h = k; h >= 1; h--) {
174 cout << setw(3) << h << " : ";
175 cout << setw(3) << N[h] << " : ";
176 cout << setw(3) << Omega[h] << " : ";
177 cout << setw(3) << F->multiplicative_order(Omega[h]) << " : ";
178 cout << setw(3) << F->mult(Omega[h], Omega[h]);
179 cout << endl;
180 }
181
182
183 for (h = k; h >= 0; h--) {
184 A_log[h] = NEW_int(N[h] * N[h]);
185 for (i = 0; i < N[h]; i++) {
186 for (j = 0; j < N[h]; j++) {
187 A_log[h][i * N[h] + j] = F->log_alpha(A[h][i * N[h] + j]) + 1;
188 }
189 }
190 cout << "A_" << N[h] << " using logarithms (+1):" << endl;
191 Int_matrix_print(A_log[h], N[h], N[h]);
192 }
193
194
195 X = NEW_int(N[k]);
196 Y = NEW_int(N[k]);
197 Z = NEW_int(N[k]);
198 X1 = NEW_int(N[k - 1]);
199 X2 = NEW_int(N[k - 1]);
200 Y1 = NEW_int(N[k - 1]);
201 Y2 = NEW_int(N[k - 1]);
202
203 for (i = 0; i < N[k]; i++) {
204 X[i] = Os.random_integer(q);
205 }
206 cout << "X:" << endl;
207 Int_matrix_print(X, 1, N[k]);
208 cout << endl;
209
210
211 nb_m10 = F->nb_times_mult_called();
212 nb_a10 = F->nb_times_add_called();
213
215
216 nb_m11 = F->nb_times_mult_called();
217 nb_a11 = F->nb_times_add_called();
218
219 nb_m1 = nb_m11 - nb_m10;
220 nb_a1 = nb_a11 - nb_a10;
221
222 cout << "nb_m1 = " << nb_m1 << " nb_a1 = " << nb_a1 << endl;
223
224
225 cout << "Y:" << endl;
226 Int_matrix_print(Y, 1, N[k]);
227 cout << endl;
228
229 //omega_power = omega; //F->power(omega, 2);
230
231 nb_m20 = F->nb_times_mult_called();
232 nb_a20 = F->nb_times_add_called();
233
234
235 for (i = 0; i < N[k - 1]; i++) {
236 X1[i] = X[2 * i + 0];
237 X2[i] = X[2 * i + 1];
238 }
239
240
241 F->Linear_algebra->mult_vector_from_the_right(A[k - 1], X1, Y1, N[k - 1], N[k - 1]);
242 F->Linear_algebra->mult_vector_from_the_right(A[k - 1], X2, Y2, N[k - 1], N[k - 1]);
243
244 gamma = 1;
246
247 for (i = 0; i < N[k - 1]; i++) {
248
249 Z[i] = F->add(Y1[i], F->mult(gamma, Y2[i]));
250 Z[N[k - 1] + i] = F->add(Y1[i], F->mult(minus_gamma, Y2[i]));
251
252 gamma = F->mult(gamma, omega);
254 }
255
256 nb_m21 = F->nb_times_mult_called();
257 nb_a21 = F->nb_times_add_called();
258 nb_m2 = nb_m21 - nb_m20;
259 nb_a2 = nb_a21 - nb_a20;
260
261 cout << "nb_m2 = " << nb_m2 << " nb_a2 = " << nb_a2 << endl;
262
263
264 cout << "Z:" << endl;
265 Int_matrix_print(Z, 1, N[k]);
266 cout << endl;
267
268 for (i = 0; i < N[k]; i++) {
269 if (Y[i] != Z[i]) {
270 cout << "problem in component " << i << endl;
271 exit(1);
272 }
273 }
274
275
276 G = NEW_pint(k + 1);
277 D = NEW_pint(k + 1);
278 Dv = NEW_pint(k + 1);
279 T = NEW_pint(k + 1);
280 Tv = NEW_pint(k + 1);
281 P = NEW_pint(k + 1);
282
283
284 G[k] = NEW_int(N[k] * N[k]);
285 D[k] = NEW_int(N[k] * N[k]);
286 Dv[k] = NEW_int(N[k] * N[k]);
287 T[k] = NEW_int(N[k] * N[k]);
288 Tv[k] = NEW_int(N[k] * N[k]);
289 P[k] = NEW_int(N[k] * N[k]);
290
291
292 Gr = NEW_pint(k + 1);
293 Dr = NEW_pint(k + 1);
294 Dvr = NEW_pint(k + 1);
295 Tr = NEW_pint(k + 1);
296 Tvr = NEW_pint(k + 1);
297 Pr = NEW_pint(k + 1);
298
299
300
301 // G[k - 1]:
302 make_G_matrix(k - 1, verbose_level);
303
304 // D[k - 1]:
305 make_D_matrix(k - 1, verbose_level);
306
307 // T[k - 1]:
308 make_T_matrix(k - 1, verbose_level);
309
310 //P[k - 1]:
311 make_P_matrix(k - 1, verbose_level);
312
313
314 cout << "G[k-1]:" << endl;
315 Int_matrix_print(Gr[k - 1], N[k], N[k]);
316 cout << endl;
317 cout << "D[k-1]:" << endl;
318 Int_matrix_print(Dr[k - 1], N[k], N[k]);
319 cout << endl;
320 cout << "T[k-1]:" << endl;
321 Int_matrix_print(Tr[k - 1], N[k], N[k]);
322 cout << endl;
323 cout << "Tv[k-1]:" << endl;
324 Int_matrix_print(Tvr[k - 1], N[k], N[k]);
325 cout << endl;
326 cout << "P[k-1]:" << endl;
327 Int_matrix_print(Pr[k - 1], N[k], N[k]);
328 cout << endl;
329
331
332 string fname_F;
333 string fname_Fv;
334 string fname_G;
335 string fname_D;
336 string fname_Dv;
337 string fname_T;
338 string fname_Tv;
339 string fname_P;
340
341 sprintf(str, "ntt_F_k%d.csv", k);
342 fname_F.assign(str);
343 sprintf(str, "ntt_Fv_k%d.csv", k);
344 fname_Fv.assign(str);
345 sprintf(str, "ntt_G_k%d.csv", k);
346 fname_G.assign(str);
347 sprintf(str, "ntt_D_k%d.csv", k);
348 fname_D.assign(str);
349 sprintf(str, "ntt_Dv_k%d.csv", k);
350 fname_Dv.assign(str);
351 sprintf(str, "ntt_T_k%d.csv", k);
352 fname_T.assign(str);
353 sprintf(str, "ntt_Tv_k%d.csv", k);
354 fname_Tv.assign(str);
355 sprintf(str, "ntt_P_k%d.csv", k);
356 fname_P.assign(str);
357 Fio.int_matrix_write_csv(fname_F, A[k], N[k], N[k]);
358 Fio.int_matrix_write_csv(fname_Fv, Av[k], N[k], N[k]);
359 Fio.int_matrix_write_csv(fname_G, Gr[k - 1], N[k], N[k]);
360 Fio.int_matrix_write_csv(fname_D, Dr[k - 1], N[k], N[k]);
361 Fio.int_matrix_write_csv(fname_Dv, Dvr[k - 1], N[k], N[k]);
362 Fio.int_matrix_write_csv(fname_T, Tr[k - 1], N[k], N[k]);
363 Fio.int_matrix_write_csv(fname_Tv, Tvr[k - 1], N[k], N[k]);
364 Fio.int_matrix_write_csv(fname_P, Pr[k - 1], N[k], N[k]);
365
366 cout << "Written file " << fname_F << " of size " << Fio.file_size(fname_F) << endl;
367 cout << "Written file " << fname_Fv << " of size " << Fio.file_size(fname_Fv) << endl;
368 cout << "Written file " << fname_G << " of size " << Fio.file_size(fname_G) << endl;
369 cout << "Written file " << fname_D << " of size " << Fio.file_size(fname_D) << endl;
370 cout << "Written file " << fname_Dv << " of size " << Fio.file_size(fname_Dv) << endl;
371 cout << "Written file " << fname_T << " of size " << Fio.file_size(fname_T) << endl;
372 cout << "Written file " << fname_Tv << " of size " << Fio.file_size(fname_Tv) << endl;
373 cout << "Written file " << fname_P << " of size " << Fio.file_size(fname_P) << endl;
374
375
376
377
378 F->Linear_algebra->mult_matrix_matrix(Gr[k - 1], Dr[k - 1], Tmp1, N[k], N[k], N[k], 0 /* verbose_level*/);
379 F->Linear_algebra->mult_matrix_matrix(Tmp1, Tr[k - 1], Tmp2, N[k], N[k], N[k], 0 /* verbose_level*/);
380 F->Linear_algebra->mult_matrix_matrix(Tmp2, Pr[k - 1], Tmp1, N[k], N[k], N[k], 0 /* verbose_level*/);
381
382 for (i = 0; i < N[k] * N[k]; i++) {
383 if (A[k][i] != Tmp1[i]) {
384 cout << "matrix product differs from the Fourier matrix, problem in component " << i << endl;
385 exit(1);
386 }
387 }
388
389
390
391 if (f_v) {
392 cout << "number_theoretic_transform::init before make_level(k - 2)" << endl;
393 }
394
395 make_level(k - 2, verbose_level);
396
397 if (f_v) {
398 cout << "number_theoretic_transform::init before make_level(k - 3)" << endl;
399 }
400
401 make_level(k - 3, verbose_level);
402
403
404 int **Stack;
405 int *the_P;
406 int *the_L;
407
408 Stack = NEW_pint(k * 3);
409 the_P = NEW_int(N[k] * N[k]);
410 the_L = NEW_int(N[k] * N[k]);
411
412 Stack[0] = P[k - 3];
413 Stack[1] = P[k - 2];
414 Stack[2] = Pr[k - 1];
415 multiply_matrix_stack(F, Stack, 3, N[k], the_P, verbose_level);
416
417 cout << "the_P:" << endl;
418 Int_matrix_print(the_P, N[k], N[k]);
419 cout << endl;
420
421 sprintf(str, "ntt_the_P_k%d.csv", k);
422 fname_P.assign(str);
423 Fio.int_matrix_write_csv(fname_P, the_P, N[k], N[k]);
424 cout << "Written file " << fname_P << " of size " << Fio.file_size(fname_P) << endl;
425
426
428 for (i = 0; i < N[k]; i++) {
429 for (j = 0; j < N[k]; j++) {
430 if (the_P[i * N[k] + j]) {
431 bit_reversal[i] = j;
432 break;
433 }
434 }
435 }
436 cout << "bit_reversal:" << endl;
438 cout << endl;
439
440
441 Stack[0] = Gr[k - 1];
442 Stack[1] = Dr[k - 1];
443 Stack[2] = G[k - 2];
444 Stack[3] = D[k - 2];
445 Stack[4] = G[k - 3];
446 Stack[5] = D[k - 3];
447
448
449 multiply_matrix_stack(F, Stack, 6, N[k], the_L, verbose_level);
450
451 cout << "the_L:" << endl;
452 Int_matrix_print(the_L, N[k], N[k]);
453 cout << endl;
454
455 string fname_L;
456
457 sprintf(str, "ntt_L_k%d.csv", k);
458 fname_L.assign(str);
459 Fio.int_matrix_write_csv(fname_L, the_L, N[k], N[k]);
460 cout << "Written file " << fname_L << " of size " << Fio.file_size(fname_L) << endl;
461
462
463 write_code(fname_code, verbose_level);
464
465 Stack[0] = Gr[2];
466 Stack[1] = Dr[2];
467 Stack[2] = Tr[2];
468 Stack[3] = Pr[2];
469
470
471 multiply_matrix_stack(F, Stack, 4, N[3], the_L, verbose_level);
472
473 cout << "G[2]*D[2]*T[2]*P[2]=" << endl;
474 Int_matrix_print(the_L, N[3], N[3]);
475 cout << endl;
476
477
478 for (i = 0; i < N[3] * N[3]; i++) {
479 if (A[3][i] != the_L[i]) {
480 cout << "matrix product differs from the Fourier matrix, problem in component " << i << endl;
481 exit(1);
482 }
483 }
484
485
486
487 Stack[0] = A[k];
488 Stack[1] = Av[k];
489
490
491 multiply_matrix_stack(F, Stack, 2, N[k], the_L, verbose_level);
492
493 cout << "A*Av=" << endl;
494 Int_matrix_print(the_L, N[k], N[k]);
495 cout << endl;
496
497 string fname_AAv;
498
499 sprintf(str, "ntt_AAv_k%d.csv", k);
500 fname_AAv.assign(str);
501 Fio.int_matrix_write_csv(fname_AAv, the_L, N[k], N[k]);
502 cout << "Written file " << fname_AAv << " of size " << Fio.file_size(fname_AAv) << endl;
503
504
505
506
507
508
509
511 int *poly_A;
512 int *poly_B;
513 int *poly_C;
514 int *poly_Ap;
515 int *poly_Bp;
516 int *poly_Cp;
517
519
520 Hom->init(F, 2, N[k] - 1, FALSE, t_LEX, verbose_level);
521 if (Hom->get_nb_monomials() != N[k]) {
522 cout << "Hom->get_nb_monomials() != N[k]" << endl;
523 exit(1);
524 }
525
526 Hom->print_monomial_ordering(cout);
527
528 poly_A = NEW_int(N[k]);
529 poly_B = NEW_int(N[k]);
530 poly_C = NEW_int(N[k]);
531 poly_Ap = NEW_int(N[k]);
532 poly_Bp = NEW_int(N[k]);
533 poly_Cp = NEW_int(N[k]);
534
535
536
537 for (i = 0; i < N[k]; i++) {
538 poly_A[i] = Os.random_integer(q);
539 }
540
541 cout << "poly_A:" << endl;
542 Int_matrix_print(poly_A, 1, N[k]);
543 cout << endl;
544
545
546 for (i = 0; i < N[k]; i++) {
547 poly_B[i] = Os.random_integer(q);
548 }
549
550 cout << "poly_B:" << endl;
551 Int_matrix_print(poly_B, 1, N[k]);
552 cout << endl;
553
554 Hom->multiply_mod(poly_A, poly_B, poly_C, 0/*verbose_level*/);
555
556
557 cout << "poly_C:" << endl;
558 Int_matrix_print(poly_C, 1, N[k]);
559 cout << endl;
560
561
562 ntt4_forward(poly_A, poly_Ap, F);
563 ntt4_forward(poly_B, poly_Bp, F);
564
565 for (i = 0; i < N[k]; i++) {
566 poly_Cp[i] = F->mult(poly_Ap[i], poly_Bp[i]);
567 }
568 ntt4_backward(poly_Cp, poly_C, F);
569
570 cout << "poly_C:" << endl;
571 Int_matrix_print(poly_C, 1, N[k]);
572 cout << endl;
573
574
575 cout << "negatively wrapped convolution:" << endl;
576
577 Hom->multiply_mod_negatively_wrapped(poly_A, poly_B, poly_C, 0/*verbose_level*/);
578
579 cout << "poly_C:" << endl;
580 Int_matrix_print(poly_C, 1, N[k]);
581 cout << endl;
582
583 for (i = 0; i < N[k]; i++) {
584 poly_A[i] = FQ->mult(poly_A[i], Psi_powers[i]);
585 }
586 for (i = 0; i < N[k]; i++) {
587 poly_B[i] = FQ->mult(poly_B[i], Psi_powers[i]);
588 }
589 ntt4_forward(poly_A, poly_Ap, FQ);
590 ntt4_forward(poly_B, poly_Bp, FQ);
591
592 for (i = 0; i < N[k]; i++) {
593 poly_Cp[i] = FQ->mult(poly_Ap[i], poly_Bp[i]);
594 }
595 ntt4_backward(poly_Cp, poly_C, FQ);
596 for (i = 0; i < N[k]; i++) {
597 poly_C[i] = FQ->mult(poly_C[i], FQ->inverse(Psi_powers[i]));
598 }
599 cout << "poly_C:" << endl;
600 Int_matrix_print(poly_C, 1, N[k]);
601 cout << endl;
602
603
604
605
606 if (f_v) {
607 cout << "number_theoretic_transform::init done" << endl;
608 }
609
610
611}
612
613
614void number_theoretic_transform::write_code(std::string &fname_code,
615 int verbose_level)
616{
617 int f_v = (verbose_level = 1);
619
620 if (f_v) {
621 cout << "number_theoretic_transform::write_code" << endl;
622 }
623
624 {
625 ofstream ost(fname_code);
626 int nb_add = 0;
627 int nb_negate = 0;
628 int nb_mult = 0;
629 write_code_header(ost, fname_code, verbose_level);
630
631 write_code2(ost, TRUE /* f_forward */, nb_add, nb_negate, nb_mult, verbose_level);
632 nb_add = 0;
633 nb_negate = 0;
634 nb_mult = 0;
635 write_code2(ost, FALSE /* f_forward */, nb_add, nb_negate, nb_mult, verbose_level);
636
637 }
638 cout << "Written file " << fname_code << " of size " << Fio.file_size(fname_code) << endl;
639
640
641}
642
644 int f_forward,
645 int &nb_add, int &nb_negate, int &nb_mult,
646 int verbose_level)
647{
648 int f_v = (verbose_level = 1);
649 int i, j1, j2, a, b, c, d;
650
651 if (f_v) {
652 cout << "number_theoretic_transform::write_code2" << endl;
653 }
654
655
656
657 if (f_forward) {
658 ost << "void ntt" << k << "_forward(int *input, int *output, finite_field *F)" << endl;
659 }
660 else {
661 ost << "void ntt" << k << "_backward(int *input, int *output, finite_field *F)" << endl;
662 }
663 ost << "{" << endl;
664 ost << "\tint t0[" << N[k] << "];" << endl;
665 ost << "\tint t1[" << N[k] << "];" << endl;
666 ost << "\tint t2[" << N[k] << "];" << endl;
667 ost << "\tint t3[" << N[k] << "];" << endl;
668 ost << "\tint t4[" << N[k] << "];" << endl;
669 ost << "\tint t5[" << N[k] << "];" << endl;
670 ost << endl;
671 for (i = 0; i < N[k]; i += 2) {
672 a = T[k - 3][i * N[k] + i];
673 b = T[k - 3][i * N[k] + i + 1];
674 c = T[k - 3][(i + 1) * N[k] + i];
675 d = T[k - 3][(i + 1) * N[k] + i + 1];
676 if (a != 1) {
677 cout << "a != 1" << endl;
678 exit(1);
679 }
680 if (b != 1) {
681 cout << "b != 1" << endl;
682 exit(1);
683 }
684 if (c != 1) {
685 cout << "c != 1" << endl;
686 exit(1);
687 }
688 if (d != minus_one) {
689 cout << "d != -1" << endl;
690 exit(1);
691 }
692 ost << "\tt0[" << i << "] = F->add(input[" << bit_reversal[i] << "], input[" << bit_reversal[i + 1] << "]);" << endl;
693 ost << "\tt0[" << i + 1 << "] = F->add(input[" << bit_reversal[i] << "], F->negate(input[" << bit_reversal[i + 1] << "]));" << endl;
694 nb_add += 2;
695 nb_negate++;
696 }
697
698 for (i = 0; i < N[k]; i++) {
699 if (f_forward) {
700 d = D[k - 3][i * N[k] + i];
701 }
702 else {
703 d = Dv[k - 3][i * N[k] + i];
704 }
705 if (d == 1) {
706 ost << "\tt1[" << i << "] = t0[" << i << "];" << endl;
707 }
708 else if (d == minus_one) {
709 ost << "\tt1[" << i << "] = F->negate(t0[" << i << "]);" << endl;
710 nb_negate++;
711 }
712 else {
713 ost << "\tt1[" << i << "] = F->mult(" << d << ", t0[" << i << "]);" << endl;
714 nb_mult++;
715 }
716 }
717
718 for (i = 0; i < N[k]; i++) {
719 for (j1 = 0; j1 < N[k]; j1++) {
720 a = G[k - 3][i * N[k] + j1];
721 if (a) {
722 break;
723 }
724 }
725 for (j2 = j1 + 1; j2 < N[k]; j2++) {
726 b = G[k - 3][i * N[k] + j2];
727 if (b) {
728 break;
729 }
730 }
731 ost << "\tt2[" << i << "] = F->add(";
732 nb_add++;
733
734 if (a == 1) {
735 ost << "t1[" << j1 << "]";
736 }
737 else if (a == minus_one) {
738 ost << "F->negate(t1[" << j1 << "])";
739 nb_negate++;
740 }
741 else {
742 ost << "F->mult(" << a << ", t1[" << j1 << "])";
743 nb_mult++;
744 }
745 ost << ", ";
746 if (b == 1) {
747 ost << "t1[" << j2 << "]";
748 }
749 else if (b == minus_one) {
750 ost << "F->negate(t1[" << j2 << "])";
751 nb_negate++;
752 }
753 else {
754 ost << "F->mult(" << b << ", t1[" << j2 << "])";
755 nb_mult++;
756 }
757 ost << ");" << endl;
758 }
759
760
761
762 for (i = 0; i < N[k]; i++) {
763 if (f_forward) {
764 d = D[k - 2][i * N[k] + i];
765 }
766 else {
767 d = Dv[k - 2][i * N[k] + i];
768 }
769 if (d == 1) {
770 ost << "\tt3[" << i << "] = t2[" << i << "];" << endl;
771 }
772 else if (d == minus_one) {
773 ost << "\tt3[" << i << "] = F->negate(t2[" << i << "]);" << endl;
774 nb_negate++;
775 }
776 else {
777 ost << "\tt3[" << i << "] = F->mult(" << d << ", t2[" << i << "]);" << endl;
778 nb_mult++;
779 }
780 }
781
782 for (i = 0; i < N[k]; i++) {
783 for (j1 = 0; j1 < N[k]; j1++) {
784 a = G[k - 2][i * N[k] + j1];
785 if (a) {
786 break;
787 }
788 }
789 for (j2 = j1 + 1; j2 < N[k]; j2++) {
790 b = G[k - 2][i * N[k] + j2];
791 if (b) {
792 break;
793 }
794 }
795 ost << "\tt4[" << i << "] = F->add(";
796 nb_add++;
797
798 if (a == 1) {
799 ost << "t3[" << j1 << "]";
800 }
801 else if (a == minus_one) {
802 ost << "F->negate(t3[" << j1 << "])";
803 nb_negate++;
804 }
805 else {
806 ost << "F->mult(" << a << ", t3[" << j1 << "])";
807 nb_mult++;
808 }
809 ost << ", ";
810 if (b == 1) {
811 ost << "t3[" << j2 << "]";
812 }
813 else if (b == minus_one) {
814 ost << "F->negate(t3[" << j2 << "])";
815 nb_negate++;
816 }
817 else {
818 ost << "F->mult(" << b << ", t3[" << j2 << "])";
819 nb_mult++;
820 }
821 ost << ");" << endl;
822 }
823
824
825 for (i = 0; i < N[k]; i++) {
826 if (f_forward) {
827 d = Dr[k - 1][i * N[k] + i];
828 }
829 else {
830 d = Dvr[k - 1][i * N[k] + i];
831 }
832 if (d == 1) {
833 ost << "\tt5[" << i << "] = t4[" << i << "];" << endl;
834 }
835 else if (d == minus_one) {
836 ost << "\tt5[" << i << "] = F->negate(t4[" << i << "]);" << endl;
837 nb_negate++;
838 }
839 else {
840 ost << "\tt5[" << i << "] = F->mult(" << d << ", t4[" << i << "]);" << endl;
841 nb_mult++;
842 }
843 }
844
845
846 for (i = 0; i < N[k]; i++) {
847 for (j1 = 0; j1 < N[k]; j1++) {
848 a = Gr[k - 1][i * N[k] + j1];
849 if (a) {
850 break;
851 }
852 }
853 for (j2 = j1 + 1; j2 < N[k]; j2++) {
854 b = Gr[k - 1][i * N[k] + j2];
855 if (b) {
856 break;
857 }
858 }
859 ost << "\toutput[" << i << "] = ";
860 if (f_forward == FALSE) {
861 ost << "F->negate(";
862 nb_negate++;
863 }
864 ost << "F->add(";
865 nb_add++;
866
867 if (a == 1) {
868 ost << "t5[" << j1 << "]";
869 }
870 else if (a == minus_one) {
871 ost << "F->negate(t5[" << j1 << "])";
872 nb_negate++;
873 }
874 else {
875 ost << "F->mult(" << a << ", t5[" << j1 << "])";
876 nb_mult++;
877 }
878 ost << ", ";
879 if (b == 1) {
880 ost << "t5[" << j2 << "]";
881 }
882 else if (b == minus_one) {
883 ost << "F->negate(t5[" << j2 << "])";
884 nb_negate++;
885 }
886 else {
887 ost << "F->mult(" << b << ", t5[" << j2 << "])";
888 nb_mult++;
889 }
890 ost << ")";
891 if (f_forward == FALSE) {
892 ost << ")";
893 }
894 ost << ";" << endl;
895 }
896 ost << "}" << endl;
897 ost << "// nb_add = " << nb_add << endl;
898 ost << "// nb_negate = " << nb_negate << endl;
899 ost << "// nb_mult = " << nb_mult << endl;
900
901
902
903 if (f_v) {
904 cout << "number_theoretic_transform::write_code done" << endl;
905 }
906}
907
908
909void number_theoretic_transform::write_code_header(std::ostream &ost, std::string &fname_code, int verbose_level)
910{
911 string str;
913
914 Os.get_date(str);
915
916 ost << "/*" << endl;
917 ost << " * " << fname_code << endl;
918 ost << " *" << endl;
919 ost << " * Created on: " << str << endl;
920 ost << " * Author: Orbiter" << endl;
921 ost << " */" << endl;
922 ost << endl;
923 ost << "#include \"orbiter.h\"" << endl;
924 ost << endl;
925 ost << "using namespace std;" << endl;
926 ost << "using namespace orbiter;" << endl;
927 ost << endl;
928 ost << "void ntt" << k << "_forward(int *input, int *output, finite_field *F);" << endl;
929 ost << "void ntt" << k << "_backward(int *input, int *output, finite_field *F);" << endl;
930 ost << endl;
931 ost << "int main(int argc, char **argv)" << endl;
932 ost << "{" << endl;
933 ost << "\torbiter::top_level::orbiter_top_level_session Top_level_session;" << endl;
934 ost << "\torbiter::top_level::The_Orbiter_top_level_session = &Top_level_session;" << endl;
935 ost << "\torbiter::top_level::The_Orbiter_top_level_session->Orbiter_session = new orbiter_session;" << endl;
936 ost << "\tfinite_field *F;" << endl;
937 ost << "\tos_interface Os;" << endl;
938 ost << "\tint q = " << q << ";" << endl;
939 ost << "\tint n = " << N[k] << ";" << endl;
940 ost << "\tint i;" << endl;
941 ost << "\t" << endl;
942 ost << "\tF = NEW_OBJECT(finite_field);" << endl;
943 ost << "\tF->finite_field_init(q, FALSE /*f_without_tables*/, 0 /*verbose_level*/);" << endl;
944 ost << "\t" << endl;
945 ost << "\tint *input;" << endl;
946 ost << "\tint *output;" << endl;
947 ost << "\t" << endl;
948 ost << "\tinput = NEW_int(n);" << endl;
949 ost << "\toutput = NEW_int(n);" << endl;
950 ost << "\t" << endl;
951 ost << "\tfor (i = 0; i < n; i++) {" << endl;
952 ost << "\t\tinput[i] = Os.random_integer(q);" << endl;
953 ost << "\t}" << endl;
954 ost << "\tcout << \"input:\" << endl;" << endl;
955 ost << "\tOrbiter->Int_vec.matrix_print(input, 1, n);" << endl;
956 ost << "\tcout << endl;" << endl;
957 ost << "\t" << endl;
958 ost << "\tntt" << k << "_forward(input, output, F);" << endl;
959 ost << "\t" << endl;
960 ost << "\tcout << \"output:\" << endl;" << endl;
961 ost << "\tOrbiter->Int_vec.matrix_print(output, 1, n);" << endl;
962 ost << "\tcout << endl;" << endl;
963 ost << "\t" << endl;
964 ost << "\tFREE_OBJECT(F);" << endl;
965 ost << "}" << endl;
966 ost << endl;
967
968
969}
970
971void number_theoretic_transform::make_level(int s, int verbose_level)
972{
973 int f_v = (verbose_level = 1);
974 int i;
976
977 if (f_v) {
978 cout << "number_theoretic_transform::make_level s=" << s << endl;
979 }
980
981
982
983
984 cout << "making k - 2 matrices:" << endl;
985
986
987 // G[k - 2]:
988 make_G_matrix(s, verbose_level);
989
990 // D[k - 2]:
991 make_D_matrix(s, verbose_level);
992
993 // T[k - 2]:
994 make_T_matrix(s, verbose_level);
995
996 //P[k - 2]:
997 make_P_matrix(s, verbose_level);
998
999
1000 cout << "Gr[" << s << "]:" << endl;
1001 Int_matrix_print(Gr[s], N[s + 1], N[s + 1]);
1002 cout << endl;
1003 cout << "Dr[" << s << "]:" << endl;
1004 Int_matrix_print(Dr[s], N[s + 1], N[s + 1]);
1005 cout << endl;
1006 cout << "Dvr[" << s << "]:" << endl;
1007 Int_matrix_print(Dvr[s], N[s + 1], N[s + 1]);
1008 cout << endl;
1009 cout << "Tr[" << s << "]:" << endl;
1010 Int_matrix_print(Tr[s], N[s + 1], N[s + 1]);
1011 cout << endl;
1012 cout << "Tvr[" << s << "]:" << endl;
1013 Int_matrix_print(Tvr[s], N[s + 1], N[s + 1]);
1014 cout << endl;
1015 cout << "Pr[" << s << "]:" << endl;
1016 Int_matrix_print(Pr[s], N[s + 1], N[s + 1]);
1017 cout << endl;
1018
1019#if 0
1020 char fname_F[1000];
1021 char fname_Fv[1000];
1022 char fname_G[1000];
1023 char fname_D[1000];
1024 char fname_Dv[1000];
1025 char fname_T[1000];
1026 char fname_Tv[1000];
1027 char fname_P[1000];
1028
1029 snprintf(fname_F, 1000, "ntt_F_k%d.csv", s + 1);
1030 snprintf(fname_Fv, 1000, "ntt_Fv_k%d.csv", s + 1);
1031 snprintf(fname_G, 1000, "ntt_Gr_k%d.csv", s + 1);
1032 snprintf(fname_D, 1000, "ntt_Dr_k%d.csv", s + 1);
1033 snprintf(fname_Dv, 1000, "ntt_Dvr_k%d.csv", s + 1);
1034 snprintf(fname_T, 1000, "ntt_Tr_k%d.csv", s + 1);
1035 snprintf(fname_Tv, 1000, "ntt_Tvr_k%d.csv", s + 1);
1036 snprintf(fname_P, 1000, "ntt_Pr_k%d.csv", s + 1);
1037#else
1038 char str[1000];
1039 string fname_F;
1040 string fname_Fv;
1041 string fname_G;
1042 string fname_D;
1043 string fname_Dv;
1044 string fname_T;
1045 string fname_Tv;
1046 string fname_P;
1047
1048 sprintf(str, "ntt_F_k%d.csv", s + 1);
1049 fname_F.assign(str);
1050 sprintf(str, "ntt_Fv_k%d.csv", s + 1);
1051 fname_Fv.assign(str);
1052 sprintf(str, "ntt_Gr_k%d.csv", s + 1);
1053 fname_G.assign(str);
1054 sprintf(str, "ntt_Dr_k%d.csv", s + 1);
1055 fname_D.assign(str);
1056 sprintf(str, "ntt_Dvr_k%d.csv", s + 1);
1057 fname_Dv.assign(str);
1058 sprintf(str, "ntt_Tr_k%d.csv", s + 1);
1059 fname_T.assign(str);
1060 sprintf(str, "ntt_Tvr_k%d.csv", s + 1);
1061 fname_Tv.assign(str);
1062 sprintf(str, "ntt_Pr_k%d.csv", s + 1);
1063 fname_P.assign(str);
1064#endif
1065 Fio.int_matrix_write_csv(fname_F, A[s + 1], N[s + 1], N[s + 1]);
1066 Fio.int_matrix_write_csv(fname_Fv, Av[s + 1], N[s + 1], N[s + 1]);
1067 Fio.int_matrix_write_csv(fname_G, Gr[s], N[s + 1], N[s + 1]);
1068 Fio.int_matrix_write_csv(fname_D, Dr[s], N[s + 1], N[s + 1]);
1069 Fio.int_matrix_write_csv(fname_Dv, Dvr[s], N[s + 1], N[s + 1]);
1070 Fio.int_matrix_write_csv(fname_T, Tr[s], N[s + 1], N[s + 1]);
1071 Fio.int_matrix_write_csv(fname_Tv, Tvr[s], N[s + 1], N[s + 1]);
1072 Fio.int_matrix_write_csv(fname_P, Pr[s], N[s + 1], N[s + 1]);
1073
1074 cout << "Written file " << fname_F << " of size " << Fio.file_size(fname_F) << endl;
1075 cout << "Written file " << fname_Fv << " of size " << Fio.file_size(fname_Fv) << endl;
1076 cout << "Written file " << fname_G << " of size " << Fio.file_size(fname_G) << endl;
1077 cout << "Written file " << fname_D << " of size " << Fio.file_size(fname_D) << endl;
1078 cout << "Written file " << fname_Dv << " of size " << Fio.file_size(fname_Dv) << endl;
1079 cout << "Written file " << fname_T << " of size " << Fio.file_size(fname_T) << endl;
1080 cout << "Written file " << fname_Tv << " of size " << Fio.file_size(fname_Tv) << endl;
1081 cout << "Written file " << fname_P << " of size " << Fio.file_size(fname_P) << endl;
1082
1083
1084 F->Linear_algebra->mult_matrix_matrix(Gr[s], Dr[s], Tmp1, N[s + 1], N[s + 1], N[s + 1], 0 /* verbose_level*/);
1085 F->Linear_algebra->mult_matrix_matrix(Tmp1, Tr[s], Tmp2, N[s + 1], N[s + 1], N[s + 1], 0 /* verbose_level*/);
1086 F->Linear_algebra->mult_matrix_matrix(Tmp2, Pr[s], Tmp1, N[s + 1], N[s + 1], N[s + 1], 0 /* verbose_level*/);
1087
1088 for (i = 0; i < N[s + 1] * N[s + 1]; i++) {
1089 if (A[s + 1][i] != Tmp1[i]) {
1090 cout << "matrix product differs from the Fourier matrix, problem in component " << i << endl;
1091 exit(1);
1092 }
1093 }
1094
1095 paste(Gr, G, s, verbose_level);
1096 paste(Dr, D, s, verbose_level);
1097 paste(Dvr, Dv, s, verbose_level);
1098 paste(Tr, T, s, verbose_level);
1099 paste(Tvr, Tv, s, verbose_level);
1100 paste(Pr, P, s, verbose_level);
1101
1102 cout << "G[" << s << "]:" << endl;
1103 Int_matrix_print(G[s], N[k], N[k]);
1104 cout << endl;
1105 cout << "D[" << s << "]:" << endl;
1106 Int_matrix_print(D[s], N[k], N[k]);
1107 cout << endl;
1108 cout << "Dv[" << s << "]:" << endl;
1109 Int_matrix_print(Dv[s], N[k], N[k]);
1110 cout << endl;
1111 cout << "T[" << s << "]:" << endl;
1112 Int_matrix_print(T[s], N[k], N[k]);
1113 cout << endl;
1114 cout << "Tv[" << s << "]:" << endl;
1115 Int_matrix_print(Tv[s], N[k], N[k]);
1116 cout << endl;
1117 cout << "P[" << s << "]:" << endl;
1118 Int_matrix_print(P[s], N[k], N[k]);
1119 cout << endl;
1120
1121 //snprintf(fname_F, 1000, "ntt_F_k%d.csv", k - 1);
1122#if 0
1123 snprintf(fname_G, 1000, "ntt_G_k%d.csv", s + 1);
1124 snprintf(fname_D, 1000, "ntt_D_k%d.csv", s + 1);
1125 snprintf(fname_Dv, 1000, "ntt_Dv_k%d.csv", s + 1);
1126 snprintf(fname_T, 1000, "ntt_T_k%d.csv", s + 1);
1127 snprintf(fname_Tv, 1000, "ntt_Tv_k%d.csv", s + 1);
1128 snprintf(fname_P, 1000, "ntt_P_k%d.csv", s + 1);
1129#else
1130 sprintf(str, "ntt_G_k%d.csv", s + 1);
1131 fname_G.assign(str);
1132 sprintf(str, "ntt_D_k%d.csv", s + 1);
1133 fname_D.assign(str);
1134 sprintf(str, "ntt_Dv_k%d.csv", s + 1);
1135 fname_Dv.assign(str);
1136 sprintf(str, "ntt_T_k%d.csv", s + 1);
1137 fname_T.assign(str);
1138 sprintf(str, "ntt_Tv_k%d.csv", s + 1);
1139 fname_Tv.assign(str);
1140 sprintf(str, "ntt_P_k%d.csv", s + 1);
1141 fname_P.assign(str);
1142#endif
1143 //Fio.int_matrix_write_csv(fname_F, A[k - 1], N[k - 1], N[k - 1]);
1144 Fio.int_matrix_write_csv(fname_G, G[s], N[k], N[k]);
1145 Fio.int_matrix_write_csv(fname_D, D[s], N[k], N[k]);
1146 Fio.int_matrix_write_csv(fname_Dv, Dv[s], N[k], N[k]);
1147 Fio.int_matrix_write_csv(fname_T, T[s], N[k], N[k]);
1148 Fio.int_matrix_write_csv(fname_Tv, Tv[s], N[k], N[k]);
1149 Fio.int_matrix_write_csv(fname_P, P[s], N[k], N[k]);
1150
1151 cout << "Written file " << fname_F << " of size " << Fio.file_size(fname_F) << endl;
1152 cout << "Written file " << fname_G << " of size " << Fio.file_size(fname_G) << endl;
1153 cout << "Written file " << fname_D << " of size " << Fio.file_size(fname_D) << endl;
1154 cout << "Written file " << fname_Dv << " of size " << Fio.file_size(fname_Dv) << endl;
1155 cout << "Written file " << fname_T << " of size " << Fio.file_size(fname_T) << endl;
1156 cout << "Written file " << fname_Tv << " of size " << Fio.file_size(fname_Tv) << endl;
1157 cout << "Written file " << fname_P << " of size " << Fio.file_size(fname_P) << endl;
1158
1159
1160
1161}
1162
1163
1164void number_theoretic_transform::paste(int **Xr, int **X, int s, int verbose_level)
1165{
1166 int f_v = (verbose_level = 1);
1167 int i, j, i0, t, h, a;
1169
1170 if (f_v) {
1171 cout << "number_theoretic_transform::paste k=" << k << endl;
1172 }
1173 t = NT.i_power_j(2, k - 1 - s);
1174 if (f_v) {
1175 cout << "algebra_global::paste t=" << t << endl;
1176 cout << "algebra_global::paste N[s + 1]=" << N[s + 1] << endl;
1177 cout << "algebra_global::paste N[k]=" << N[k] << endl;
1178 }
1179 X[s] = NEW_int(N[k] * N[k]);
1180 Int_vec_zero(X[s], N[k] * N[k]);
1181 i0 = 0;
1182 for (h = 0; h < t; h++) {
1183 if (f_v) {
1184 cout << "h=" << h << " i0=" << i0 << endl;
1185 }
1186 for (i = 0; i < N[s + 1]; i++) {
1187 for (j = 0; j < N[s + 1]; j++) {
1188 a = Xr[s][i * N[s + 1] + j];
1189 X[s][(i0 + i) * N[k] + i0 + j] = a;
1190 }
1191 }
1192 i0 += N[s + 1];
1193 }
1194 if (f_v) {
1195 cout << "number_theoretic_transform::paste created matrix" << endl;
1196 Int_matrix_print(G[s], N[k], N[k]);
1197 }
1198 if (f_v) {
1199 cout << "number_theoretic_transform::paste done" << endl;
1200 }
1201}
1202
1203void number_theoretic_transform::make_G_matrix(int s, int verbose_level)
1204{
1205 int f_v = (verbose_level = 1);
1206 int i;
1207
1208 if (f_v) {
1209 cout << "number_theoretic_transform::make_G_matrix s=" << s << endl;
1210 }
1211
1212 Gr[s] = NEW_int(N[s + 1] * N[s + 1]);
1213 Int_vec_zero(Gr[s], N[s + 1] * N[s + 1]);
1214 for (i = 0; i < N[s]; i++) {
1215 Gr[s][i * N[s + 1] + i] = 1;
1216 Gr[s][i * N[s + 1] + N[s] + i] = 1;
1217 Gr[s][(N[s] + i) * N[s + 1] + i] = 1;
1218 Gr[s][(N[s] + i) * N[s + 1] + N[s] + i] = F->negate(1);
1219 }
1220
1221 if (f_v) {
1222 cout << "number_theoretic_transform::make_G_matrix done" << endl;
1223 }
1224}
1225
1226
1227void number_theoretic_transform::make_D_matrix(int s, int verbose_level)
1228{
1229 int f_v = (verbose_level = 1);
1230 int i, gamma, omega;
1231
1232 if (f_v) {
1233 cout << "number_theoretic_transform::make_D_matrix s=" << s << endl;
1234 }
1235
1236 Dr[s] = NEW_int(N[s + 1] * N[s + 1]);
1237 Int_vec_zero(Dr[s], N[s + 1] * N[s + 1]);
1238 omega = Omega[s + 1];
1239 gamma = 1;
1240 for (i = 0; i < N[s]; i++) {
1241
1242 Dr[s][i * N[s + 1] + i] = 1;
1243 Dr[s][(N[s] + i) * N[s + 1] + N[s] + i] = gamma;
1244
1245
1246 //Z[i] = F->add(Y1[i], F->mult(gamma, Y2[i]));
1247 //Z[N[n - 1] + i] = F->add(Y1[i], F->mult(minus_gamma, Y2[i]));
1248
1249 gamma = F->mult(gamma, omega);
1250 //minus_gamma = F->negate(gamma);
1251 }
1252
1253 Dvr[s] = NEW_int(N[s + 1] * N[s + 1]);
1254 Int_vec_zero(Dvr[s], N[s + 1] * N[s + 1]);
1255 omega = F->inverse(Omega[s + 1]);
1256 gamma = 1;
1257
1258 for (i = 0; i < N[s]; i++) {
1259
1260 Dvr[s][i * N[s + 1] + i] = 1;
1261 Dvr[s][(N[s] + i) * N[s + 1] + N[s] + i] = gamma;
1262
1263
1264 //Z[i] = F->add(Y1[i], F->mult(gamma, Y2[i]));
1265 //Z[N[n - 1] + i] = F->add(Y1[i], F->mult(minus_gamma, Y2[i]));
1266
1267 gamma = F->mult(gamma, omega);
1268 //minus_gamma = F->negate(gamma);
1269 }
1270
1271 if (f_v) {
1272 cout << "number_theoretic_transform::make_D_matrix done" << endl;
1273 }
1274}
1275
1276void number_theoretic_transform::make_T_matrix(int s, int verbose_level)
1277{
1278 int f_v = (verbose_level = 1);
1279
1280 if (f_v) {
1281 cout << "number_theoretic_transform::make_T_matrix s=" << s << endl;
1282 }
1283
1284 int sz;
1285 int Id2[] = {1,0,0,1};
1286
1287 Tr[s] = NEW_int(N[s + 1] * N[s + 1]);
1288 Int_vec_zero(Tr[s], N[s + 1] * N[s + 1]);
1290 N[s], 2, Tr[s], sz, 0 /*verbose_level */);
1291 if (sz != N[s + 1]) {
1292 cout << "sz != N[s + 1]" << endl;
1293 exit(1);
1294 }
1295
1296 Tvr[s] = NEW_int(N[s + 1] * N[s + 1]);
1297 Int_vec_zero(Tvr[s], N[s + 1] * N[s + 1]);
1299 N[s], 2, Tvr[s], sz, 0 /*verbose_level */);
1300 if (sz != N[s + 1]) {
1301 cout << "sz != N[s + 1]" << endl;
1302 exit(1);
1303 }
1304
1305 if (f_v) {
1306 cout << "number_theoretic_transform::make_T_matrix done" << endl;
1307 }
1308
1309}
1310
1311
1312void number_theoretic_transform::make_P_matrix(int s, int verbose_level)
1313{
1314 int f_v = (verbose_level = 1);
1315 int i;
1316
1317 if (f_v) {
1318 cout << "number_theoretic_transform::make_P_matrix s=" << s << endl;
1319 }
1320 Pr[s] = NEW_int(N[s + 1] * N[s + 1]);
1321 Int_vec_zero(Pr[s], N[s + 1] * N[s + 1]);
1322 for (i = 0; i < N[s]; i++) {
1323 Pr[s][i * N[s + 1] + 2 * i] = 1;
1324 Pr[s][(N[s] + i) * N[s + 1] + 2 * i + 1] = 1;
1325 }
1326 if (f_v) {
1327 cout << "number_theoretic_transform::make_P_matrix done" << endl;
1328 }
1329}
1330
1332 int **S,
1333 int nb, int sz, int *Result, int verbose_level)
1334{
1335 int f_v = (verbose_level = 1);
1336 int i;
1337
1338 if (f_v) {
1339 cout << "number_theoretic_transform::multiply_matrix_stack nb=" << nb << endl;
1340 }
1341 if (nb == 1) {
1342 Int_vec_copy(S[0], Result, sz * sz);
1343 }
1344 else {
1345 F->Linear_algebra->mult_matrix_matrix(S[0], S[1], Tmp1, sz, sz, sz, 0 /* verbose_level*/);
1346 for (i = 2; i < nb; i++) {
1347 F->Linear_algebra->mult_matrix_matrix(Tmp1, S[i], Tmp2, sz, sz, sz, 0 /* verbose_level*/);
1348 Int_vec_copy(Tmp2, Tmp1, sz * sz);
1349 }
1350 Int_vec_copy(Tmp1, Result, sz * sz);
1351 }
1352 if (f_v) {
1353 cout << "number_theoretic_transform::multiply_matrix_stack done" << endl;
1354 }
1355}
1356
1357
1358static void ntt4_forward(int *input, int *output, field_theory::finite_field *F)
1359{
1360 int t0[16];
1361 int t1[16];
1362 int t2[16];
1363 int t3[16];
1364 int t4[16];
1365 int t5[16];
1366
1367 t0[0] = F->add(input[0], input[8]);
1368 t0[1] = F->add(input[0], F->negate(input[8]));
1369 t0[2] = F->add(input[4], input[12]);
1370 t0[3] = F->add(input[4], F->negate(input[12]));
1371 t0[4] = F->add(input[2], input[10]);
1372 t0[5] = F->add(input[2], F->negate(input[10]));
1373 t0[6] = F->add(input[6], input[14]);
1374 t0[7] = F->add(input[6], F->negate(input[14]));
1375 t0[8] = F->add(input[1], input[9]);
1376 t0[9] = F->add(input[1], F->negate(input[9]));
1377 t0[10] = F->add(input[5], input[13]);
1378 t0[11] = F->add(input[5], F->negate(input[13]));
1379 t0[12] = F->add(input[3], input[11]);
1380 t0[13] = F->add(input[3], F->negate(input[11]));
1381 t0[14] = F->add(input[7], input[15]);
1382 t0[15] = F->add(input[7], F->negate(input[15]));
1383 t1[0] = t0[0];
1384 t1[1] = t0[1];
1385 t1[2] = t0[2];
1386 t1[3] = F->mult(13, t0[3]);
1387 t1[4] = t0[4];
1388 t1[5] = t0[5];
1389 t1[6] = t0[6];
1390 t1[7] = F->mult(13, t0[7]);
1391 t1[8] = t0[8];
1392 t1[9] = t0[9];
1393 t1[10] = t0[10];
1394 t1[11] = F->mult(13, t0[11]);
1395 t1[12] = t0[12];
1396 t1[13] = t0[13];
1397 t1[14] = t0[14];
1398 t1[15] = F->mult(13, t0[15]);
1399 t2[0] = F->add(t1[0], t1[2]);
1400 t2[1] = F->add(t1[1], t1[3]);
1401 t2[2] = F->add(t1[0], F->negate(t1[2]));
1402 t2[3] = F->add(t1[1], F->negate(t1[3]));
1403 t2[4] = F->add(t1[4], t1[6]);
1404 t2[5] = F->add(t1[5], t1[7]);
1405 t2[6] = F->add(t1[4], F->negate(t1[6]));
1406 t2[7] = F->add(t1[5], F->negate(t1[7]));
1407 t2[8] = F->add(t1[8], t1[10]);
1408 t2[9] = F->add(t1[9], t1[11]);
1409 t2[10] = F->add(t1[8], F->negate(t1[10]));
1410 t2[11] = F->add(t1[9], F->negate(t1[11]));
1411 t2[12] = F->add(t1[12], t1[14]);
1412 t2[13] = F->add(t1[13], t1[15]);
1413 t2[14] = F->add(t1[12], F->negate(t1[14]));
1414 t2[15] = F->add(t1[13], F->negate(t1[15]));
1415 t3[0] = t2[0];
1416 t3[1] = t2[1];
1417 t3[2] = t2[2];
1418 t3[3] = t2[3];
1419 t3[4] = t2[4];
1420 t3[5] = F->mult(9, t2[5]);
1421 t3[6] = F->mult(13, t2[6]);
1422 t3[7] = F->mult(15, t2[7]);
1423 t3[8] = t2[8];
1424 t3[9] = t2[9];
1425 t3[10] = t2[10];
1426 t3[11] = t2[11];
1427 t3[12] = t2[12];
1428 t3[13] = F->mult(9, t2[13]);
1429 t3[14] = F->mult(13, t2[14]);
1430 t3[15] = F->mult(15, t2[15]);
1431 t4[0] = F->add(t3[0], t3[4]);
1432 t4[1] = F->add(t3[1], t3[5]);
1433 t4[2] = F->add(t3[2], t3[6]);
1434 t4[3] = F->add(t3[3], t3[7]);
1435 t4[4] = F->add(t3[0], F->negate(t3[4]));
1436 t4[5] = F->add(t3[1], F->negate(t3[5]));
1437 t4[6] = F->add(t3[2], F->negate(t3[6]));
1438 t4[7] = F->add(t3[3], F->negate(t3[7]));
1439 t4[8] = F->add(t3[8], t3[12]);
1440 t4[9] = F->add(t3[9], t3[13]);
1441 t4[10] = F->add(t3[10], t3[14]);
1442 t4[11] = F->add(t3[11], t3[15]);
1443 t4[12] = F->add(t3[8], F->negate(t3[12]));
1444 t4[13] = F->add(t3[9], F->negate(t3[13]));
1445 t4[14] = F->add(t3[10], F->negate(t3[14]));
1446 t4[15] = F->add(t3[11], F->negate(t3[15]));
1447 t5[0] = t4[0];
1448 t5[1] = t4[1];
1449 t5[2] = t4[2];
1450 t5[3] = t4[3];
1451 t5[4] = t4[4];
1452 t5[5] = t4[5];
1453 t5[6] = t4[6];
1454 t5[7] = t4[7];
1455 t5[8] = t4[8];
1456 t5[9] = F->mult(3, t4[9]);
1457 t5[10] = F->mult(9, t4[10]);
1458 t5[11] = F->mult(10, t4[11]);
1459 t5[12] = F->mult(13, t4[12]);
1460 t5[13] = F->mult(5, t4[13]);
1461 t5[14] = F->mult(15, t4[14]);
1462 t5[15] = F->mult(11, t4[15]);
1463 output[0] = F->add(t5[0], t5[8]);
1464 output[1] = F->add(t5[1], t5[9]);
1465 output[2] = F->add(t5[2], t5[10]);
1466 output[3] = F->add(t5[3], t5[11]);
1467 output[4] = F->add(t5[4], t5[12]);
1468 output[5] = F->add(t5[5], t5[13]);
1469 output[6] = F->add(t5[6], t5[14]);
1470 output[7] = F->add(t5[7], t5[15]);
1471 output[8] = F->add(t5[0], F->negate(t5[8]));
1472 output[9] = F->add(t5[1], F->negate(t5[9]));
1473 output[10] = F->add(t5[2], F->negate(t5[10]));
1474 output[11] = F->add(t5[3], F->negate(t5[11]));
1475 output[12] = F->add(t5[4], F->negate(t5[12]));
1476 output[13] = F->add(t5[5], F->negate(t5[13]));
1477 output[14] = F->add(t5[6], F->negate(t5[14]));
1478 output[15] = F->add(t5[7], F->negate(t5[15]));
1479}
1480// nb_add = 64
1481// nb_negate = 32
1482// nb_mult = 17
1483
1484static void ntt4_backward(int *input, int *output, field_theory::finite_field *F)
1485{
1486 int t0[16];
1487 int t1[16];
1488 int t2[16];
1489 int t3[16];
1490 int t4[16];
1491 int t5[16];
1492
1493 t0[0] = F->add(input[0], input[8]);
1494 t0[1] = F->add(input[0], F->negate(input[8]));
1495 t0[2] = F->add(input[4], input[12]);
1496 t0[3] = F->add(input[4], F->negate(input[12]));
1497 t0[4] = F->add(input[2], input[10]);
1498 t0[5] = F->add(input[2], F->negate(input[10]));
1499 t0[6] = F->add(input[6], input[14]);
1500 t0[7] = F->add(input[6], F->negate(input[14]));
1501 t0[8] = F->add(input[1], input[9]);
1502 t0[9] = F->add(input[1], F->negate(input[9]));
1503 t0[10] = F->add(input[5], input[13]);
1504 t0[11] = F->add(input[5], F->negate(input[13]));
1505 t0[12] = F->add(input[3], input[11]);
1506 t0[13] = F->add(input[3], F->negate(input[11]));
1507 t0[14] = F->add(input[7], input[15]);
1508 t0[15] = F->add(input[7], F->negate(input[15]));
1509 t1[0] = t0[0];
1510 t1[1] = t0[1];
1511 t1[2] = t0[2];
1512 t1[3] = F->mult(4, t0[3]);
1513 t1[4] = t0[4];
1514 t1[5] = t0[5];
1515 t1[6] = t0[6];
1516 t1[7] = F->mult(4, t0[7]);
1517 t1[8] = t0[8];
1518 t1[9] = t0[9];
1519 t1[10] = t0[10];
1520 t1[11] = F->mult(4, t0[11]);
1521 t1[12] = t0[12];
1522 t1[13] = t0[13];
1523 t1[14] = t0[14];
1524 t1[15] = F->mult(4, t0[15]);
1525 t2[0] = F->add(t1[0], t1[2]);
1526 t2[1] = F->add(t1[1], t1[3]);
1527 t2[2] = F->add(t1[0], F->negate(t1[2]));
1528 t2[3] = F->add(t1[1], F->negate(t1[3]));
1529 t2[4] = F->add(t1[4], t1[6]);
1530 t2[5] = F->add(t1[5], t1[7]);
1531 t2[6] = F->add(t1[4], F->negate(t1[6]));
1532 t2[7] = F->add(t1[5], F->negate(t1[7]));
1533 t2[8] = F->add(t1[8], t1[10]);
1534 t2[9] = F->add(t1[9], t1[11]);
1535 t2[10] = F->add(t1[8], F->negate(t1[10]));
1536 t2[11] = F->add(t1[9], F->negate(t1[11]));
1537 t2[12] = F->add(t1[12], t1[14]);
1538 t2[13] = F->add(t1[13], t1[15]);
1539 t2[14] = F->add(t1[12], F->negate(t1[14]));
1540 t2[15] = F->add(t1[13], F->negate(t1[15]));
1541 t3[0] = t2[0];
1542 t3[1] = t2[1];
1543 t3[2] = t2[2];
1544 t3[3] = t2[3];
1545 t3[4] = t2[4];
1546 t3[5] = F->mult(2, t2[5]);
1547 t3[6] = F->mult(4, t2[6]);
1548 t3[7] = F->mult(8, t2[7]);
1549 t3[8] = t2[8];
1550 t3[9] = t2[9];
1551 t3[10] = t2[10];
1552 t3[11] = t2[11];
1553 t3[12] = t2[12];
1554 t3[13] = F->mult(2, t2[13]);
1555 t3[14] = F->mult(4, t2[14]);
1556 t3[15] = F->mult(8, t2[15]);
1557 t4[0] = F->add(t3[0], t3[4]);
1558 t4[1] = F->add(t3[1], t3[5]);
1559 t4[2] = F->add(t3[2], t3[6]);
1560 t4[3] = F->add(t3[3], t3[7]);
1561 t4[4] = F->add(t3[0], F->negate(t3[4]));
1562 t4[5] = F->add(t3[1], F->negate(t3[5]));
1563 t4[6] = F->add(t3[2], F->negate(t3[6]));
1564 t4[7] = F->add(t3[3], F->negate(t3[7]));
1565 t4[8] = F->add(t3[8], t3[12]);
1566 t4[9] = F->add(t3[9], t3[13]);
1567 t4[10] = F->add(t3[10], t3[14]);
1568 t4[11] = F->add(t3[11], t3[15]);
1569 t4[12] = F->add(t3[8], F->negate(t3[12]));
1570 t4[13] = F->add(t3[9], F->negate(t3[13]));
1571 t4[14] = F->add(t3[10], F->negate(t3[14]));
1572 t4[15] = F->add(t3[11], F->negate(t3[15]));
1573 t5[0] = t4[0];
1574 t5[1] = t4[1];
1575 t5[2] = t4[2];
1576 t5[3] = t4[3];
1577 t5[4] = t4[4];
1578 t5[5] = t4[5];
1579 t5[6] = t4[6];
1580 t5[7] = t4[7];
1581 t5[8] = t4[8];
1582 t5[9] = F->mult(6, t4[9]);
1583 t5[10] = F->mult(2, t4[10]);
1584 t5[11] = F->mult(12, t4[11]);
1585 t5[12] = F->mult(4, t4[12]);
1586 t5[13] = F->mult(7, t4[13]);
1587 t5[14] = F->mult(8, t4[14]);
1588 t5[15] = F->mult(14, t4[15]);
1589 output[0] = F->negate(F->add(t5[0], t5[8]));
1590 output[1] = F->negate(F->add(t5[1], t5[9]));
1591 output[2] = F->negate(F->add(t5[2], t5[10]));
1592 output[3] = F->negate(F->add(t5[3], t5[11]));
1593 output[4] = F->negate(F->add(t5[4], t5[12]));
1594 output[5] = F->negate(F->add(t5[5], t5[13]));
1595 output[6] = F->negate(F->add(t5[6], t5[14]));
1596 output[7] = F->negate(F->add(t5[7], t5[15]));
1597 output[8] = F->negate(F->add(t5[0], F->negate(t5[8])));
1598 output[9] = F->negate(F->add(t5[1], F->negate(t5[9])));
1599 output[10] = F->negate(F->add(t5[2], F->negate(t5[10])));
1600 output[11] = F->negate(F->add(t5[3], F->negate(t5[11])));
1601 output[12] = F->negate(F->add(t5[4], F->negate(t5[12])));
1602 output[13] = F->negate(F->add(t5[5], F->negate(t5[13])));
1603 output[14] = F->negate(F->add(t5[6], F->negate(t5[14])));
1604 output[15] = F->negate(F->add(t5[7], F->negate(t5[15])));
1605}
1606// nb_add = 64
1607// nb_negate = 48
1608// nb_mult = 17
1609
1610
1611
1612}}}
1613
void finite_field_init(int q, int f_without_tables, int verbose_level)
void make_Fourier_matrices(int omega, int k, int *N, int **A, int **Av, int *Omega, int verbose_level)
void mult_matrix_matrix(int *A, int *B, int *C, int m, int n, int o, int verbose_level)
void mult_vector_from_the_right(int *A, int *v, int *Av, int m, int n)
void Kronecker_product_square_but_arbitrary(int *A, int *B, int na, int nb, int *AB, int &N, int verbose_level)
void write_code_header(std::ostream &ost, std::string &fname_code, int verbose_level)
void init(field_theory::finite_field *F, int k, int q, int verbose_level)
void multiply_matrix_stack(field_theory::finite_field *F, int **S, int nb, int sz, int *Result, int verbose_level)
void write_code2(std::ostream &ost, int f_forward, int &nb_add, int &nb_negate, int &nb_mult, int verbose_level)
void int_matrix_write_csv(std::string &fname, int *M, int m, int n)
Definition: file_io.cpp:1300
homogeneous polynomials of a given degree in a given number of variables over a finite field GF(q)
Definition: ring_theory.h:88
void multiply_mod_negatively_wrapped(int *coeff1, int *coeff2, int *coeff3, int verbose_level)
void init(field_theory::finite_field *F, int nb_vars, int degree, int f_init_incidence_structure, monomial_ordering_type Monomial_ordering_type, int verbose_level)
void multiply_mod(int *coeff1, int *coeff2, int *coeff3, int verbose_level)
#define Int_vec_zero(A, B)
Definition: foundations.h:713
#define NEW_pint(n)
Definition: foundations.h:627
#define NEW_OBJECT(type)
Definition: foundations.h:638
#define NEW_int(n)
Definition: foundations.h:625
#define Int_matrix_print(A, B, C)
Definition: foundations.h:707
#define TRUE
Definition: foundations.h:231
#define FALSE
Definition: foundations.h:234
#define Int_vec_copy(A, B, C)
Definition: foundations.h:693
the orbiter library for the classification of combinatorial objects