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