1 //==============================================================================================
2 //
3 // This file is part of LiDIA --- a library for computational number theory
4 //
5 // Copyright (c) 1994--2001 the LiDIA Group. All rights reserved.
6 //
7 // See http://www.informatik.tu-darmstadt.de/TI/LiDIA/
8 //
9 //----------------------------------------------------------------------------------------------
10 //
11 // $Id$
12 //
13 // Author : Patrick Theobald (PT)
14 // Changes : See CVS log
15 //
16 //==============================================================================================
17
18
19 #ifndef LIDIA_MODULAR_ARITHMETIC_CC_GUARD_
20 #define LIDIA_MODULAR_ARITHMETIC_CC_GUARD_
21
22
23 #ifndef LIDIA_INFO_H_GUARD_
24 # include "LiDIA/info.h"
25 #endif
26 #include "LiDIA/matrix/crt_and_prime_handling.h"
27
28
29 #ifdef LIDIA_NAMESPACE
30 # ifndef IN_NAMESPACE_LIDIA
31 namespace LiDIA {
32 # endif
33 #endif
34
35
36
37 //
38 // debug defines / error defines
39 //
40
41
42 extern const char *matrix_error_msg[];
43
44 #define DMESSAGE "modular_arithmetic" // Debug message
45 #define EMESSAGE matrix_error_msg // Error message
46
47
48
49 //
50 // Chinese remaindering theorem for matrices
51 //
52
53 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
54 void
chinrest(matrix<bigint> & RES,const matrix<bigint> * v,const bigint * prim) const55 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::chinrest (matrix< bigint > &RES,
56 const matrix< bigint > *v,
57 const bigint *prim) const
58 {
59 register lidia_size_t i, j, l;
60
61 long len;
62 prim[0].longify(len);
63 bigint M, X, mod;
64 bigint TMP, TMP0, TMP1, TMP2;
65 bigint dummy;
66
67 register bigint *e = new bigint[len];
68 memory_handler(e, DMESSAGE, "chinrest :: "
69 "Error in memory allocation (e)");
70
71 lidia_size_t r = v[0].rows;
72 lidia_size_t c = v[0].columns;
73
74 // new dimensions
75 if (RES.rows != r)
76 this->rep_modul.set_no_of_rows(RES, r);
77 if (RES.columns != c)
78 this->rep_modul.set_no_of_columns(RES, c);
79
80 register bigint *m = new bigint[len];
81 memory_handler(m, DMESSAGE, "chinrest :: "
82 "Error in memory allocation (m)");
83
84 // precomputation
85 bigint L = 1;
86 for (i = 0; i < len; i++)
87 LiDIA::multiply(L, L, prim[i + 1]);
88
89 for (i = 0; i < len; i++) {
90 mod.assign(prim[i + 1]);
91 LiDIA::divide(M, L, mod);
92 best_remainder(TMP, M, mod);
93 dummy = xgcd_right(TMP1, mod, TMP);
94 LiDIA::multiply(e[i], TMP1, M);
95 }
96
97
98 // crt for all elements
99 for (i = 0; i < r; i++)
100 for (j = 0; j < c; j++) {
101 X.assign_zero();
102
103 for (l = 0; l < len; l++)
104 m[l].assign(this->rep_modul.member(v[l], i, j));
105
106 for (l = 0; l < len; l++) {
107 LiDIA::multiply(TMP, e[l], m[l]);
108 LiDIA::add(X, X, TMP);
109 }
110
111 best_remainder(X, X, L);
112 LiDIA::subtract(TMP0, L, bigint(1));
113 shift_left(TMP1, X, 1);
114 shift_left(TMP2, L, 1);
115 if (!(TMP1 >= -TMP0 && TMP1 <= TMP0))
116 if (TMP1 - TMP2 <= TMP0 || TMP1 - TMP2 >= -TMP0)
117 LiDIA::subtract(X, X, L);
118 else
119 lidia_error_handler("void matrix< bigint >::"
120 "chinrest(const matrix< bigint > * v, "
121 "const bigint * prim)", DMESSAGE, EMESSAGE[8]);
122
123 this->rep_modul.sto(RES, i, j, X);
124 }
125 delete[] e;
126 delete[] m;
127 }
128
129
130
131 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
132 inline void
chinese_remainder(matrix<bigint> & RES,const bigint & m1,const matrix<bigint> & b,const bigint & m2) const133 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::chinese_remainder (matrix< bigint > &RES,
134 const bigint & m1,
135 const matrix< bigint > &b,
136 const bigint & m2) const
137 {
138 bigint mm1(abs(m1)), mm2(abs(m2)), u, d, t;
139 lidia_size_t i, j;
140
141 d = xgcd_left (u, mm1, mm2); // determine lcm(m1, m2)
142
143 LiDIA::divide(mm2, mm2, d);
144
145 for (i = 0; i < RES.rows; ++i)
146 for (j = 0; j < RES.columns; ++j) {
147 best_remainder(t, (this->rep_modul.member(b, i, j) - this->rep_modul.member(RES, i, j))/d*u, mm2);
148 best_remainder(t, this->rep_modul.member(RES, i, j) + t*mm1, mm1*mm2);
149
150 this->rep_modul.sto(RES, i, j, t);
151 }
152 }
153
154
155
156 //
157 // rank
158 //
159
160 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
161 lidia_size_t
rank(const matrix<bigint> & M,const bigint & H) const162 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::rank (const matrix< bigint > &M,
163 const bigint &H) const
164 {
165 // read primelist from file
166 long Number_of_primes;
167 register bigint *PRIM = get_primes(bigint(2) * H, bigint(1));
168 PRIM[0].longify(Number_of_primes);
169
170 // Compute the rank for all primes
171 lidia_size_t RANG = 0;
172
173 lidia_size_t i, No;
174 bigint Gmod;
175 for (i = 1; i <= Number_of_primes; i++) {
176 Gmod = PRIM[i];
177 if (Gmod.bit_length() > bigint::bits_per_digit()) {
178 // bigint part
179 matrix< bigint > A(M.rows, M.columns, M.bitfield);
180 remainder(A, M, Gmod);
181
182 No = this->bigint_modul.rank(A, Gmod);
183 }
184 else {
185 // long part
186 long mod;
187 Gmod.longify(mod);
188
189 matrix< long > A(M.rows, M.columns, M.bitfield);
190 A.set_zero_element(0);
191 remainder(A, M, mod);
192
193 No = this->long_modul.rank(A, mod);
194 }
195
196 if (RANG < No)
197 RANG = No;
198
199 // shortcut full rank
200 if (RANG == M.rows || RANG == M.columns)
201 return RANG;
202 }
203 return RANG;
204 }
205
206
207
208 //
209 // rank and linearly independent rows
210 //
211
212 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
213 lidia_size_t *
lininr1(const matrix<bigint> & M,const bigint & H) const214 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::lininr1 (const matrix< bigint > &M,
215 const bigint &H) const
216 {
217 register lidia_size_t i, j;
218 bigint Gmod;
219
220 // read primelist from file
221 long Number_of_primes;
222 register bigint *PRIM = get_primes(bigint(2) * H, bigint(1));
223 PRIM[0].longify(Number_of_primes);
224
225 // compute the rank and the linear independent rows for all primes
226 lidia_size_t *res_vector = new lidia_size_t[M.rows + 1];
227 memory_handler(res_vector, DMESSAGE, "lininr :: "
228 "Error in memory allocation (res_vector)");
229
230 for (i = 0; i <= M.rows; res_vector[i] = 0, i++);
231
232 lidia_size_t *v = NULL;
233 for (i = 1; i <= Number_of_primes; i++) {
234 Gmod = PRIM[i];
235 if (Gmod.bit_length() > bigint::bits_per_digit()) {
236 // bigint part
237 matrix< bigint > A(M.rows, M.columns, M.bitfield);
238 remainder(A, M, Gmod);
239
240 v = this->bigint_modul.lininr(A, Gmod);
241 }
242 else {
243 // long part
244 long mod;
245 Gmod.longify(mod);
246
247 matrix< long > A(M.rows, M.columns, M.bitfield);
248 A.set_zero_element(0);
249 remainder(A, M, mod);
250
251 v = this->long_modul.lininr(A, mod);
252 }
253
254 for (j = 0; j <= v[0]; j++)
255 if (res_vector[j] < v[j])
256 res_vector[j] = v[j];
257 delete[] v;
258
259 // full dimension
260 if (res_vector[0] == M.rows || res_vector[0] == M.columns)
261 return res_vector;
262 }
263 return res_vector;
264 }
265
266
267
268 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
269 lidia_size_t *
lininr2(const matrix<bigint> & M,const bigint & H) const270 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::lininr2 (const matrix< bigint > &M,
271 const bigint &H) const
272 {
273 register lidia_size_t i;
274 bigint Gmod;
275
276 // read primelist form file
277 bigint *PRIM = get_primes(bigint(2) * H, bigint(1));
278 long Number_of_primes;
279 PRIM[0].longify(Number_of_primes);
280
281 // init
282 lidia_size_t *res_vector = NULL;
283 lidia_size_t *v = NULL, RANG = 0;
284
285 for (i = 1; i <= Number_of_primes; i++) {
286 Gmod = PRIM[i];
287 if (Gmod.bit_length() > bigint::bits_per_digit()) {
288 // bigint part
289 matrix< bigint > A(M.rows, M.columns, M.bitfield);
290 remainder(A, M, Gmod);
291
292 v = this->bigint_modul.lininr(A, Gmod);
293 }
294 else {
295 // long part
296 long mod;
297 Gmod.longify(mod);
298
299 matrix< long > A(M.rows, M.columns, M.bitfield);
300 A.set_zero_element(0);
301 remainder(A, M, mod);
302
303 v = this->long_modul.lininr(A, mod);
304 }
305
306 if (RANG < v[0]) {
307 RANG = v[0];
308 if (res_vector != NULL)
309 delete[] res_vector;
310 res_vector = v;
311 }
312
313 // shortcut full rank
314 if (RANG == M.rows || RANG == M.columns)
315 return res_vector;
316 }
317 return res_vector;
318 }
319
320
321
322 //
323 // rank linearly independent columns
324 //
325
326 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
327 lidia_size_t *
lininc1(const matrix<bigint> & M,const bigint & H) const328 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::lininc1 (const matrix< bigint > &M,
329 const bigint &H) const
330 {
331 const bigint_matrix_algorithms< REP, REP, REP > modul;
332
333 register lidia_size_t i, j;
334 bigint Gmod;
335
336 // read primlist from file
337 register bigint *PRIM = get_primes(bigint(2) * H, bigint(1));
338 long Number_of_primes;
339 PRIM[0].longify(Number_of_primes);
340
341 // compute the rank and the linear independent columns for all primes
342 lidia_size_t *res_vector = new lidia_size_t[M.columns + 1];
343 memory_handler(res_vector, DMESSAGE, "lininc :: "
344 "Error in memory allocation (res_vector)");
345
346 for (i = 0; i <= M.columns; res_vector[i] = 0, i++);
347
348 lidia_size_t *v = NULL;
349
350 for (i = 1; i <= Number_of_primes; i++) {
351 Gmod = PRIM[i];
352 if (Gmod.bit_length() > bigint::bits_per_digit()) {
353 // bigint part
354 matrix< bigint > A(M.columns, M.rows, M.bitfield);
355 modul.trans_remainder(A, M, Gmod);
356
357 v = this->bigint_modul.lininc(A, Gmod);
358 }
359 else {
360 // long part
361 long mod;
362 Gmod.longify(mod);
363
364 matrix< long > A(M.columns, M.rows, M.bitfield);
365 A.set_zero_element(0);
366 modul.trans_remainder(A, M, mod);
367
368 v = this->long_modul.lininc(A, mod);
369 }
370
371 for (j = 0; j <= v[0]; j++)
372 if (res_vector[j] < v[j])
373 res_vector[j] = v[j];
374 delete[] v;
375
376 // full dimension
377 if (res_vector[0] == M.rows || res_vector[0] == M.columns)
378 return res_vector;
379 }
380 return res_vector;
381 }
382
383
384
385 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
386 lidia_size_t *
lininc2(const matrix<bigint> & M,const bigint & H) const387 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::lininc2 (const matrix< bigint > &M,
388 const bigint &H) const
389 {
390 const bigint_matrix_algorithms< REP, REP, REP > modul;
391
392 register lidia_size_t i;
393 bigint Gmod;
394
395 // read primelist from file
396 register bigint *PRIM = get_primes(bigint(2) * H, bigint(1));
397 long Number_of_primes;
398 PRIM[0].longify(Number_of_primes);
399
400 // Init
401 lidia_size_t *res_vector = NULL;
402 lidia_size_t *v = NULL, RANG = 0;
403
404 for (i = 1; i <= Number_of_primes; i++) {
405 Gmod = PRIM[i];
406 if (Gmod.bit_length() > bigint::bits_per_digit()) {
407 // bigint part
408 matrix< bigint > A(M.columns, M.rows, M.bitfield);
409 modul.trans_remainder(A, M, Gmod);
410
411 v = this->bigint_modul.lininc(A, Gmod);
412 }
413 else {
414 // long part
415 long mod;
416 Gmod.longify(mod);
417
418 matrix< long > A(M.columns, M.rows, M.bitfield);
419 A.set_zero_element(0);
420 modul.trans_remainder(A, M, mod);
421
422 v = this->long_modul.lininc(A, mod);
423 }
424
425 if (RANG < v[0]) {
426 RANG = v[0];
427 if (res_vector != NULL)
428 delete[] res_vector;
429 res_vector = v;
430 }
431
432 // full dimension
433 if (RANG == M.rows || RANG == M.columns)
434 return res_vector;
435 }
436 return res_vector;
437 }
438
439
440
441 //
442 // adjoint matrix
443 //
444
445 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
446 void
adj1(matrix<bigint> & RES,const matrix<bigint> & A,const bigint & H,const bigint & DET) const447 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::adj1 (matrix< bigint > &RES,
448 const matrix< bigint > & A,
449 const bigint &H,
450 const bigint &DET) const
451 {
452 register lidia_size_t i, z1, z2;
453
454 // read primelist from file
455 register bigint *PRIM = get_primes(bigint(2)*H, DET, true);
456 long n;
457 PRIM[0].longify(n);
458
459 // compute adj for all primes
460 bigint MOD;
461 long Modlong;
462 matrix< bigint > *chininput = new matrix< bigint > [n];
463 memory_handler(chininput, DMESSAGE, "adj :: "
464 "Error in memory allocation (chininput)");
465
466 for (i = 1; i <= n; i++) {
467 debug_handler_c(DMESSAGE, "adj(const matrix< bigint > &)", DVALUE + 7,
468 std::cout << "In Iteration " << i << std::endl;);
469
470 MOD.assign(PRIM[i]);
471
472 if (MOD.bit_length() > bigint::bits_per_digit()) {
473 matrix< bigint > B(A.rows, A.columns, A.bitfield);
474 remainder(B, A, MOD);
475
476 this->bigint_modul.adj(B, MOD);
477
478 chininput[i - 1] = B;
479 }
480 else {
481 MOD.longify(Modlong);
482 matrix< long > B(A.rows, A.columns, A.bitfield);
483 remainder(B, A, Modlong);
484
485 this->long_modul.adj(B, Modlong);
486
487 chininput[i - 1].set_no_of_rows(A.rows);
488 chininput[i - 1].set_no_of_columns(A.columns);
489
490 for (z1 = 0; z1 < A.rows; z1++)
491 for (z2 = 0; z2 < A.columns; z2++)
492 this->rep_modul.sto(chininput[i-1], z1, z2, B(z1, z2));
493 }
494 }
495
496 // CRT
497 this->chinrest(RES, chininput, PRIM);
498
499 delete[] PRIM;
500 delete[] chininput;
501 }
502
503
504
505 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
506 void
adj2(matrix<bigint> & RES,const matrix<bigint> & A,const bigint & H,const bigint & DET) const507 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::adj2 (matrix< bigint > &RES,
508 const matrix< bigint > & A,
509 const bigint &H,
510 const bigint & DET) const
511 {
512 register lidia_size_t i, ii, jj, kk, z1, z2;
513 bigint val, val2;
514 bool done;
515
516 register bigint *PRIM = get_primes(bigint(2)*H, abs(DET), true);
517 long n;
518 PRIM[0].longify(n);
519
520 lidia_qo_info_handler(std::cout << "(adj) " << n << " primes required!" << std::endl;);
521
522 // Step 4
523 bigint MODULUS, MOD;
524 long Modlong;
525 memory_handler(chininput, DMESSAGE, "adj :: "
526 "Error in memory allocation (chininput)");
527
528 matrix< bigint > B(A.rows, A.columns, A.bitfield);
529
530 for (i = 1; i <= n; i++) {
531 debug_handler_c(DMESSAGE, "in function "
532 "adj(const matrix< bigint > &)", DVALUE + 7,
533 std::cout << "In Iteration " << i << std::endl;);
534
535 MOD.assign(PRIM[i]);
536
537 if (MOD.bit_length() > bigint::bits_per_digit()) {
538 lidia_qo_xinfo_handler("adjoint [bigint]", i, n);
539
540 remainder(B, A, MOD);
541
542 this->bigint_modul.adj(B, MOD);
543 }
544 else {
545 lidia_qo_xinfo_handler("adjoint [long]", i, n);
546
547 MOD.longify(Modlong);
548 matrix< long > Blong(A.rows, A.columns, A.bitfield);
549 remainder(Blong, A, Modlong);
550
551 this->long_modul.adj(Blong, Modlong);
552
553 for (z1 = 0; z1 < A.rows; z1++)
554 for (z2 = 0; z2 < A.columns; z2++)
555 this->rep_modul.sto(B, z1, z2, Blong(z1, z2));
556 }
557
558 if (i == 1) {
559 RES = B;
560 MODULUS = MOD;
561 }
562 else {
563 this->chinese_remainder(RES, MODULUS, B, MOD);
564 MODULUS *= MOD;
565 }
566
567 // perform test (A*RES = det I)
568 done = true;
569 for (ii = 0; (ii < A.rows) && done; ++ii)
570 for (jj = 0; (jj < A.columns) && done; ++jj) {
571 val.assign_zero();
572 for (kk = 0; kk < A.columns; ++kk)
573 add(val, val, A.member(ii, kk)* RES.member(kk, jj));
574 if (ii == jj)
575 done = (val == DET);
576 else
577 done = val.is_zero();
578 }
579
580 if (done) {
581 lidia_qo_info_handler(std::cout << "\n(adj) Only " << i << " primes required!\n" << std::flush;);
582 break;
583 }
584 }
585
586 if (qo_special) {
587 if (i == n+1) --i;
588 std::cout << " " << i << std::flush;
589 }
590
591 delete[] PRIM;
592 }
593
594
595
596 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
597 void
adj2(matrix<bigint> & RES,const matrix<bigint> & A,const bigint & H,const bigint & DET,int num_mod) const598 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::adj2 (matrix< bigint > &RES,
599 const matrix< bigint > & A,
600 const bigint &H,
601 const bigint & DET,
602 int num_mod) const
603 {
604 register lidia_size_t i, z1, z2, ii, kk;
605 bigint val, val2;
606
607 register bigint *PRIM = get_primes(bigint(2)*H, abs(DET), true);
608 long n;
609 PRIM[0].longify(n);
610
611 lidia_qo_info_handler(std::cout << "(adj) " << num_mod << " primes required!";
612 std::cout << std::endl;);
613
614 // Step 4
615 bigint MODULUS, MOD;
616 long Modlong;
617 memory_handler(chininput, DMESSAGE, "adj :: "
618 "Error in memory allocation (chininput)");
619
620 matrix< bigint > B(A.rows, A.columns, A.bitfield);
621
622 bool done = false;
623 for (i = 1; (i <= num_mod) || !done; i++) {
624 debug_handler_c(DMESSAGE, "in function "
625 "adj(const matrix< bigint > &)", DVALUE + 7,
626 std::cout << "In Iteration " << i << std::endl;);
627
628 MOD.assign(PRIM[i]);
629
630 if (MOD.bit_length() > bigint::bits_per_digit()) {
631 lidia_qo_xinfo_handler("adjoint [bigint]", i, n);
632
633 remainder(B, A, MOD);
634
635 this->bigint_modul.adj(B, MOD);
636 }
637 else {
638 lidia_qo_xinfo_handler("adjoint [long]", i, n);
639
640 MOD.longify(Modlong);
641 matrix< long > Blong(A.rows, A.columns, A.bitfield);
642 remainder(Blong, A, Modlong);
643
644 this->long_modul.adj(Blong, Modlong);
645
646 for (z1 = 0; z1 < A.rows; z1++)
647 for (z2 = 0; z2 < A.columns; z2++)
648 this->rep_modul.sto(B, z1, z2, Blong(z1, z2));
649 }
650
651 if (i == 1) {
652 RES = B;
653 MODULUS = MOD;
654 }
655 else {
656 this->chinese_remainder(RES, MODULUS, B, MOD);
657 MODULUS *= MOD;
658 }
659
660
661 if (i >= num_mod) {
662 // perform test (A*RES = det I), only check diagonals
663 done = true;
664 for (ii = 0; (ii < A.rows) && done; ++ii) {
665 val.assign_zero();
666 for (kk = 0; kk < A.columns; ++kk)
667 add(val, val, A.member(ii, kk)* RES.member(kk, ii));
668 done = (val == DET);
669
670 if (done && (ii > 0)) {
671 val.assign_zero();
672 for (kk = 0; kk < A.columns; ++kk)
673 add(val, val, A.member(ii, kk)* RES.member(kk, 0));
674 done = (val.is_zero());
675 }
676 }
677 }
678
679 if ((i >= num_mod) && done) {
680 lidia_qo_info_handler(std::cout << "\n(adj) Only " << i << " primes required!" << std::endl;);
681 }
682 }
683
684 if (qo_special) {
685 std::cout << " " << i-1 << std::flush;
686 }
687
688 delete[] PRIM;
689 }
690
691
692
693 //
694 // lattice determinant
695 //
696
697 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
698 void
latticedet1(const matrix<bigint> & RES,bigint & DET,const bigint & H) const699 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::latticedet1 (const matrix< bigint > &RES,
700 bigint & DET,
701 const bigint &H) const
702 {
703 register lidia_size_t i, j;
704
705 // Step 1
706 lidia_size_t *linuz = lininr1(RES, H);
707 lidia_size_t r = linuz[0];
708
709 // Step 2
710 matrix< bigint > C(r, RES.columns, RES.bitfield);
711 for (i = 0; i < r; i++)
712 for (j = 0; j < RES.columns; j++)
713 this->rep_modul.sto(C, i, j, this->rep_modul.member(RES, linuz[i+1], j));
714
715 delete[] linuz;
716
717 // Step 3
718 if (r == RES.columns)
719 det(C, DET, H);
720 else {
721 linuz = lininc1(C, H);
722
723 matrix< bigint > D(r, r, RES.bitfield);
724 for (i = 0; i < r; i++)
725 for (j = 0; j < r; j++)
726 this->rep_modul.sto(D, j, i, this->rep_modul.member(C, j, linuz[i + 1]));
727 det(D, DET, H);
728 delete[] linuz;
729 }
730
731 if (DET.is_lt_zero())
732 DET.negate();
733 }
734
735
736
737 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
738 void
latticedet2(const matrix<bigint> & RES,bigint & DET,const bigint & H) const739 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::latticedet2 (const matrix< bigint > &RES,
740 bigint & DET,
741 const bigint &H) const
742 {
743 register lidia_size_t i, j;
744 bigint TMP, TMP1;
745
746 // Step 1
747 lidia_size_t *linu = lininr1(RES, H);
748 lidia_size_t r = linu[0];
749
750 // Step 2
751 matrix< bigint > C(r, RES.columns, RES.bitfield);
752 matrix< bigint > C1(r, RES.columns, RES.bitfield);
753
754 for (i = 0; i < r; i++)
755 for (j = 0; j < RES.columns; j++) {
756 this->rep_modul.sto(C, i, j, this->rep_modul.member(RES, linu[i+1], j));
757 this->rep_modul.sto(C1, i, RES.columns - 1 - j, this->rep_modul.member(RES, linu[i+1], j));
758 }
759 delete[] linu;
760
761 // Step 3
762 if (r == RES.columns)
763 C.det(DET, H);
764 else {
765 linu = lininc1(C, H);
766 matrix< bigint > D(r, r, RES.bitfield);
767
768 for (i = 0; i < r; i++)
769 for (j = 0; j < r; j++)
770 this->rep_modul.sto(D, j, i, this->rep_modul.member(C, j, linu[i + 1]));
771 D.det(TMP, H);
772 delete[] linu;
773
774 linu = lininc1(C1, H);
775 for (i = 0; i < r; i++)
776 for (j = 0; j < r; j++)
777 this->rep_modul.sto(D, j, i, this->rep_modul.member(C1, j, linu[i + 1]));
778 D.det(TMP1, H);
779 delete[] linu;
780 DET = gcd(TMP, TMP1);
781 }
782 if (DET.is_lt_zero())
783 DET.negate();
784 }
785
786
787
788 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
789 void
latticedet2(const matrix<bigint> & RES,bigint & DET,bigint & H,int num_same) const790 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::latticedet2 (const matrix< bigint > &RES,
791 bigint & DET,
792 bigint &H,
793 int num_same) const
794 {
795 register lidia_size_t i, j;
796 bigint TMP, TMP1, *tmp, *tmp1, *tmp2;
797
798 // Step 1
799 lidia_size_t *linu = lininr1(RES, H);
800 lidia_size_t r = linu[0];
801
802 // Step 2
803 matrix< bigint > C(r, RES.columns);
804 matrix< bigint > C1(r, RES.columns);
805
806 for (i = 0; i < r; i++) {
807 tmp = C.value[i];
808 tmp1 = RES.value[linu[i+1]];
809 tmp2 = C1.value[i];
810 for (j = 0; j < RES.columns; j++) {
811 tmp[j].assign(tmp1[j]);
812 tmp2[RES.columns - 1 - j].assign(tmp1[j]);
813 }
814 }
815 delete[] linu;
816
817 // Step 3
818 if (r == RES.columns)
819 C.det(DET, H, num_same);
820 else {
821 linu = lininc1(C, H);
822 matrix< bigint > D(r, r);
823
824 for (i = 0; i < r; i++)
825 for (j = 0; j < r; j++)
826 D.value[j][i].assign(C.value[j][linu[i + 1]]);
827 D.det(TMP, H, num_same);
828 delete[] linu;
829
830 linu = lininc1(C1, H);
831 for (i = 0; i < r; i++)
832 for (j = 0; j < r; j++)
833 D.value[j][i].assign(C1.value[j][linu[i + 1]]);
834 D.det(TMP1, H, num_same);
835 delete[] linu;
836
837 DET = gcd(TMP, TMP1);
838 }
839 if (DET.is_lt_zero())
840 DET.negate();
841 }
842
843
844
845 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
846 void
latticedet3(const matrix<bigint> & RES,bigint & DET,const bigint & H) const847 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::latticedet3 (const matrix< bigint > &RES,
848 bigint & DET,
849 const bigint &H) const
850 {
851 register lidia_size_t i, j;
852 register bigint *tmp, *tmp1;
853
854 // Step 1
855 lidia_size_t *linuz = lininr1(RES, H);
856 lidia_size_t r = linuz[0];
857
858 // Step 2
859 if (r == RES.columns) {
860 matrix< bigint > C(r, RES.columns);
861 for (i = 0; i < r; i++) {
862 tmp = C.value[i];
863 tmp1 = RES.value[linuz[i+1]];
864 for (j = 0; j < RES.columns; j++)
865 tmp[j].assign(tmp1[j]);
866 }
867 C.det(DET, H);
868 }
869 else {
870 lidia_size_t *linuz1 = lininc1(RES, H);
871
872 matrix< bigint > D(r, r);
873 for (i = 0; i < r; i++)
874 for (j = 0; j < r; j++)
875 D.value[j][i].assign(RES.value[linuz[j+1]][linuz1[i + 1]]);
876 D.det(DET, H);
877 delete[] linuz1;
878 }
879 delete[] linuz;
880 if (DET.is_lt_zero())
881 DET.negate();
882 }
883
884
885
886 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
887 void
latticedet4(const matrix<bigint> & RES,bigint & DET,bigint & H,int num_same) const888 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::latticedet4 (const matrix< bigint > &RES,
889 bigint & DET,
890 bigint &H,
891 int num_same) const
892 {
893 register lidia_size_t i, j;
894 bigint TMP, TMP1, *tmp, *tmp1, *tmp2;
895
896 // Step 1
897 lidia_size_t *linu2, *linu = lininr2(RES, H);
898 lidia_size_t r = linu[0];
899
900 matrix< bigint > C(r, RES.columns);
901 for (i = 0; i < r; i++) {
902 tmp = C.value[i];
903 tmp1 = RES.value[linu[i+1]];
904 for (j = 0; j < RES.columns; j++)
905 tmp[j].assign(tmp1[j]);
906 }
907
908 linu2 = lininc1(C, H);
909 for (i = 0; i < r; i++)
910 for (j = 0; j < r; j++)
911 C.value[j][i].assign(C.value[j][linu2[r-i]]);
912 C.resize(r, r);
913 delete[] linu2;
914 linu2 = NULL;
915 det(C, TMP, H, num_same);
916
917
918 // second submatrix
919 C.resize(r, RES.columns);
920 for (i = 0; i < r; i++) {
921 tmp1 = RES.value[linu[i+1]];
922 tmp2 = C.value[i];
923 for (j = 0; j < RES.columns; j++)
924 tmp2[RES.columns - 1 - j].assign(tmp1[j]);
925 }
926 delete[] linu;
927
928 linu2 = lininc1(C, H);
929 for (i = 0; i < r; i++)
930 for (j = 0; j < r; j++)
931 C.value[j][i].assign(C.value[j][linu2[r-i]]);
932 C.resize(r, r);
933 delete[] linu2;
934 det(C, TMP1, H, num_same);
935 DET = gcd(TMP, TMP1);
936
937 if (DET.is_lt_zero())
938 DET.negate();
939 lidia_info_handler(std::cout << "Det mult = " << DET << std::endl;);
940 }
941
942
943
944 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
945 lidia_size_t *
latticedet5(matrix<bigint> & RES,bigint & DET,bigint & H,int num_same) const946 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::latticedet5 (matrix< bigint > &RES,
947 bigint & DET,
948 bigint &H,
949 int num_same) const
950 {
951 register lidia_size_t i;
952 bigint TMP, TMP1;
953
954 lidia_size_t *linu1 = lininr1(RES, H);
955 if (linu1[0] < RES.rows)
956 return linu1;
957
958 if (RES.rows == RES.columns) {
959 det(RES, DET, H, num_same);
960 if (qo_special) {
961 std::cout << " 0" << std::flush;
962 }
963 lidia_qo_info_handler(std::cout << "Det mult = " << DET << std::endl;);
964
965 return NULL;
966 }
967
968 for (i = 0; i < linu1[0]; ++i)
969 RES.swap_rows(i, linu1[linu1[0] - i]);
970
971 // Step 1
972 lidia_size_t *linu = lininc1(RES, H);
973 lidia_size_t r = linu[0];
974 for (i = 0; i < r; i++)
975 RES.swap_columns(i, linu[r-i]);
976
977 lidia_size_t old_columns = RES.columns;
978 RES.columns = linu[0];
979 lidia_size_t old_rows = RES.rows;
980 RES.rows = linu1[0];
981
982 det(RES, TMP, H, num_same);
983
984 RES.columns = old_columns;
985 RES.rows = old_rows;
986 for (i = r-1; i >= 0; i--)
987 RES.swap_columns(i, linu[r-i]);
988 for (i = 0; i < RES.columns/2; i++)
989 RES.swap_columns(i, RES.columns-i-1);
990 delete [] linu;
991
992 linu = lininc1(RES, H);
993 for (i = 0; i < r; i++)
994 RES.swap_columns(i, linu[r-i]);
995 RES.columns = linu[0];
996 RES.rows = linu1[0];
997
998 det(RES, TMP1, H, num_same);
999
1000 RES.rows = old_rows;
1001 RES.columns = old_columns;
1002 for (i = r-1; i >= 0; i--)
1003 RES.swap_columns(i, linu[r-i]);
1004 for (i = 0; i < RES.columns/2; i++)
1005 RES.swap_columns(i, RES.columns-i-1);
1006
1007 delete[] linu;
1008 DET = gcd(TMP, TMP1);
1009
1010 if (DET.is_lt_zero())
1011 DET.negate();
1012 lidia_qo_info_handler(std::cout << "Det mult = " << DET << std::endl;);
1013
1014 for (i = linu1[0]-1; i >= 0; --i)
1015 RES.swap_rows(i, linu1[linu1[0]-i]);
1016 delete [] linu1;
1017
1018 linu1 = NULL;
1019 return linu1;
1020 }
1021
1022
1023
1024 //
1025 // lattice determinant special
1026 //
1027
1028 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
1029 void
latticedet_special(const matrix<bigint> & C,bigint & DET,const bigint & H,int num_same) const1030 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::latticedet_special (const matrix< bigint > &C,
1031 bigint & DET,
1032 const bigint &H,
1033 int num_same) const
1034 {
1035 matrix< bigint > B = C;
1036
1037 // Step 1, 2
1038 lidia_size_t num = 0;
1039 bigint *PRIM = get_primes(bigint(2) * H, bigint(1));
1040
1041 lidia_size_t *linu = lininc1(B, H);
1042 lidia_size_t r = linu[0];
1043 lidia_size_t i;
1044 for (i = 0; i < r; i++)
1045 B.swap_columns(B.columns - B.rows + i, linu[r-i]);
1046 delete[] linu;
1047
1048 long n, Modlong;
1049 PRIM[0].longify(n);
1050 lidia_info_handler(std::cout << n << " primes required for modulo lattice determinant computation.\n" << std::flush;);
1051
1052 bigint MODULUS = 1;
1053
1054 lidia_size_t diff = B.columns - B.rows;
1055 bigint *RES = new bigint[diff + 1];
1056
1057 const bigint *bigintRES = NULL;
1058 bigint Gmod, DETOLD;
1059 const long *longRES = NULL;
1060
1061 matrix< bigint > Abigint(B.rows, B.columns, B.bitfield);
1062 matrix< long > Along(B.rows, B.columns, B.bitfield);
1063 Along.set_zero_element(0);
1064
1065 DET = 0;
1066
1067 // Step 3
1068 lidia_size_t j;
1069 for (i = 1; i <= n; i++) {
1070 Gmod.assign(PRIM[i]);
1071 if (Gmod.bit_length() >= bigint::bits_per_digit()) {
1072 // bigint part
1073 lidia_qo_xinfo_handler("lattice determinante [bigint]", i, n);
1074
1075 remainder(Abigint, B, Gmod);
1076
1077 bigintRES = this->bigint_modul.STF_extended(Abigint, Gmod);
1078
1079 if (i == 1) {
1080 for (j = 0; j <= diff; j++)
1081 RES[j] = bigintRES[j];
1082 MODULUS = Gmod;
1083 }
1084 else {
1085 for (j = 0; j <= diff; j++)
1086 RES[j] = LiDIA::chinese_remainder(RES[j], MODULUS, bigintRES[j], Gmod);
1087 MODULUS *= Gmod;
1088 for (j = 0; j <= diff; j++)
1089 best_remainder(RES[j], RES[j], MODULUS);
1090
1091 }
1092 delete[] bigintRES;
1093 }
1094 else {
1095 // long part
1096 lidia_qo_xinfo_handler("lattice determinante [long]", i, n);
1097
1098 Gmod.longify(Modlong);
1099 remainder(Along, B, Modlong);
1100
1101 longRES = this->long_modul.STF_extended(Along, Modlong);
1102 Gmod = Modlong;
1103
1104 if (i == 1) {
1105 for (j = 0; j <= diff; j++)
1106 RES[j] = longRES[j];
1107 MODULUS = Gmod;
1108 }
1109 else {
1110 for (j = 0; j <= diff; j++)
1111 RES[j] = LiDIA::chinese_remainder(RES[j], MODULUS, longRES[j], Gmod);
1112 MODULUS *= Gmod;
1113 for (j = 0; j <= diff; j++)
1114 best_remainder(RES[j], RES[j], MODULUS);
1115 }
1116 delete[] longRES;
1117 }
1118
1119 DET = RES[diff];
1120 if (DETOLD == DET) {
1121 num++;
1122 if (num == num_same) {
1123 lidia_info_handler(std::cout << "\nOnly " << i << " primes required!\n" << std::flush;);
1124 break;
1125 }
1126 }
1127 else {
1128 num = 0;
1129 DETOLD = DET;
1130 }
1131 }
1132 DET = RES[0];
1133 for (j = 1; j <= diff; j++)
1134 DET = gcd(DET, RES[j]);
1135 delete[] RES;
1136 }
1137
1138
1139
1140 //
1141 // determinant
1142 //
1143
1144 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
1145 void
det(const matrix<bigint> & B,bigint & DET,const bigint & H) const1146 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::det (const matrix< bigint > &B,
1147 bigint & DET,
1148 const bigint &H) const
1149 {
1150 // read primes from file
1151 bigint *PRIM = get_primes(bigint(2) * H, bigint(1));
1152 long n, Modlong;
1153 PRIM[0].longify(n);
1154
1155 bigint Gmod;
1156
1157 // init
1158 bigint *chininput = new bigint[n];
1159 memory_handler(chininput, DMESSAGE, "det :: "
1160 "Error in memory allocation (chininput)");
1161
1162 matrix< bigint > Abigint(B.rows, B.columns, B.bitfield);
1163 matrix< long > Along(B.rows, B.columns, B.bitfield);
1164 Along.set_zero_element(0);
1165
1166 for (lidia_size_t i = 1; i <= n; i++) {
1167 Gmod.assign(PRIM[i]);
1168 if (Gmod.bit_length() >= bigint::bits_per_digit()) {
1169 // bigint part
1170 lidia_qo_xinfo_handler("determinante [bigint]", i, n);
1171
1172 remainder(Abigint, B, Gmod);
1173
1174 chininput[i - 1] = this->bigint_modul.det(Abigint, Gmod);
1175 }
1176 else {
1177 // long part
1178 lidia_qo_xinfo_handler("determinante [long]", i, n);
1179
1180 Gmod.longify(Modlong);
1181 remainder(Along, B, Modlong);
1182
1183 chininput[i - 1] = this->long_modul.det(Along, Modlong);
1184 }
1185 best_remainder(chininput[i - 1], chininput[i - 1], Gmod);
1186 }
1187
1188 // CRT
1189 LiDIA::chinrest(DET, (const bigint *)chininput, (const bigint *)PRIM);
1190 delete[] chininput;
1191 }
1192
1193
1194
1195 //
1196 // determinant (with iterative chinese remaindering)
1197 //
1198
1199 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
1200 int
det(const matrix<bigint> & B,bigint & DET,const bigint & H,int num_same) const1201 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::det (const matrix< bigint > &B,
1202 bigint & DET,
1203 const bigint &H,
1204 int num_same) const
1205 {
1206 // read primes from file
1207 lidia_size_t i, num = 0;
1208 bigint *PRIM = get_primes(bigint(2) * H, bigint(1));
1209 long n, Modlong;
1210 PRIM[0].longify(n);
1211 lidia_qo_info_handler(std::cout << n << " primes required for modulo determinant computation.\n"
1212 << std::flush;);
1213
1214 bigint MODULUS = 1;
1215 bigint RES, Gmod, DETOLD;
1216
1217 matrix< bigint > Abigint(B.rows, B.columns, B.bitfield);
1218 matrix< long > Along(B.rows, B.columns, B.bitfield);
1219 Along.set_zero_element(0);
1220
1221 // compute determinante for all finite fields
1222 for (i = 1; i <= n; i++) {
1223 Gmod.assign(PRIM[i]);
1224 if (Gmod.bit_length() >= bigint::bits_per_digit()) {
1225 // bigint part
1226 lidia_qo_xinfo_handler("determinante [bigint]", i, n);
1227
1228 remainder(Abigint, B, Gmod);
1229
1230 RES = this->bigint_modul.det(Abigint, Gmod);
1231 }
1232 else {
1233 // long part
1234 lidia_qo_xinfo_handler("determinante [long]", i, n);
1235
1236 Gmod.longify(Modlong);
1237 remainder(Along, B, Modlong);
1238
1239 RES = this->long_modul.det(Along, Modlong);
1240 Gmod = Modlong;
1241 }
1242
1243 if (i == 1) {
1244 DET = RES;
1245 MODULUS = Gmod;
1246 }
1247 else {
1248 DET = LiDIA::chinese_remainder(DET, MODULUS, RES, Gmod);
1249 MODULUS *= Gmod;
1250 best_remainder(DET, DET, MODULUS);
1251 }
1252
1253 if (DETOLD == DET) {
1254 num++;
1255 if (num == num_same) {
1256 lidia_qo_info_handler(std::cout << "\nOnly " << i << " primes required!\n" << std::flush;);
1257 break;
1258 }
1259 }
1260 else {
1261 num = 0;
1262 DETOLD = DET;
1263 }
1264
1265 }
1266
1267 if (qo_special) {
1268 if (i == n+1) --i;
1269 std::cout << " " << i << std::flush;
1270 }
1271
1272 return i;
1273 }
1274
1275
1276
1277 //
1278 // characteristic polynomial
1279 //
1280
1281 template< class REP, class SINGLE_MODUL, class MULTI_MODUL >
1282 void
charpoly(const matrix<bigint> & A,bigint * RES,const bigint & H) const1283 modular_arithmetic< REP, SINGLE_MODUL, MULTI_MODUL >::charpoly (const matrix< bigint > &A,
1284 bigint *RES,
1285 const bigint &H) const
1286 {
1287 register lidia_size_t i, j;
1288 bigint TMP = H, TMP1;
1289 long len;
1290
1291 // Computing bound
1292 j = static_cast<lidia_size_t>(A.columns) / 2;
1293
1294 TMP1.assign_one();
1295 for (i = A.columns; i > A.columns - j; i--)
1296 LiDIA::multiply(TMP, TMP, (i*i));
1297 for (i = j; i > 0; i--)
1298 LiDIA::multiply(TMP1, TMP1, (i*i));
1299 LiDIA::divide(TMP, TMP, TMP1);
1300
1301 if (TMP.is_zero())
1302 RES[A.columns].assign((A.columns % 2 == 0) ? 1 : -1);
1303
1304 // read primes from file
1305 shift_left(TMP, TMP, 1);
1306 bigint *PRIM = get_primes(TMP, bigint(1));
1307 PRIM[0].longify(len);
1308
1309 // Init
1310 matrix< bigint > U(A.columns + 1, static_cast<int>(len));
1311
1312 bigint MOD;
1313 long Modlong;
1314
1315 // computing charpoly
1316 for (i = 1; i <= len; i++) {
1317 MOD.assign(PRIM[i]);
1318 if (MOD.bit_length() > bigint::bits_per_digit()) {
1319 matrix< bigint > B(A.rows, A.columns);
1320 remainder(B, A, MOD);
1321
1322 bigint *zwbigint = this->bigint_modul.charpoly(B, MOD);
1323
1324 for (j = 0; j < A.columns + 1; j++)
1325 U.value[j][i - 1].assign(zwbigint[j]);
1326 delete[] zwbigint;
1327 }
1328 else {
1329 MOD.longify(Modlong);
1330 matrix< long > B(A.rows, A.columns);
1331 B.set_zero_element(0);
1332 remainder(B, A, Modlong);
1333
1334 long *zwlong = this->long_modul.charpoly(B, Modlong);
1335 for (j = 0; j < A.columns + 1; j++)
1336 U.value[j][i - 1].assign(zwlong[j]);
1337 delete[] zwlong;
1338 }
1339
1340 }
1341
1342 // CRT
1343 for (i = 0; i < A.columns + 1; i++)
1344 LiDIA::chinrest(RES[i], U.value[i], PRIM);
1345 }
1346
1347
1348
1349 #undef DMESSAGE
1350 #undef EMESSAGE
1351
1352
1353
1354 #ifdef LIDIA_NAMESPACE
1355 # ifndef IN_NAMESPACE_LIDIA
1356 } // end of namespace LiDIA
1357 # endif
1358 #endif
1359
1360
1361
1362 #endif // LIDIA_MODULAR_ARITHMETIC_CC_GUARD_
1363