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 : Stefan Neis (SN)
14 // Changes : See CVS log
15 //
16 //==============================================================================================
17
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22 #include "LiDIA/alg_number.h"
23 #include "LiDIA/debug.h"
24 #include "LiDIA/base_vector.h"
25 #include <cctype>
26
27
28
29 #ifdef LIDIA_NAMESPACE
30 namespace LiDIA {
31 #endif
32
33
34
35 #ifdef LIDIA_IMPLICIT_CAST_EXPLICIT
36 #define alg_ideal_cast(O) alg_ideal(O)
37 #else
38 #define alg_ideal_cast(O) O
39 #endif
40
41 #ifdef LIDIA_DEBUG
42 int module::count = 0;
43 #endif
44
45 // Constructors & destructor:
46 // WILL BE REMOVED IN NEXT RELEASE:
module(const alg_number & a,const alg_number & b)47 module::module(const alg_number & a, const alg_number & b)
48 : base(a.degree(), 1),
49 den(a.den),
50 O(a.which_base()),
51 is_exp(true)
52 {
53 debug_handler_c("module", "in module(const a_n, const a_n)", 1,
54 count++;
55 std::cout << "\nNow we have " << count << " modules!\n");
56 O->inc_ref();
57 if (b.is_zero())
58 base.sto_column_vector(a.coeff, a.degree(), 0);
59 else if (a.is_zero()) {
60 base.sto_column_vector(b.coeff, b.degree(), 0);
61 den.assign(b.den);
62 }
63 else {
64 bigint d = gcd(a.den, b.den);
65 bigint e = b.den / d;
66 den *= e;
67 base.set_no_of_columns(2);
68 base.sto_column_vector((a.coeff) * e, a.degree(), 0);
69 base.sto_column_vector((b.coeff) * (a.den / d), a.degree(), 1);
70 }
71 debug_handler_c("module", "in module(const a_n, const a_n)", 3,
72 std::cout << " Now the module is " << (*this));
73 multiply(*this, *this, alg_ideal_cast(order(static_cast<const nf_base *>(O))));
74 debug_handler_c("module", "in module(const a_n, const a_n)", 3,
75 std::cout << " So the ideal is " << (*this));
76 }
77
78
79
module(const matrix<bigint> & B,const bigint & d,const nf_base * O1)80 module::module(const matrix< bigint > & B, const bigint & d,
81 const nf_base * O1)
82 : base(B),
83 den(d),
84 O(const_cast<nf_base *>(O1)),
85 is_exp(false)
86 {
87 debug_handler_c("module",
88 "in module(const matrix< bigint > &, const bigint &, "
89 "const nf_base *)", 1,
90 count++;
91 std::cout << "\nNow we have " << count << " modules!\n");
92 O->inc_ref();
93 if (B.get_no_of_rows() != O1->degree()) {
94 lidia_error_handler("module", "module(const matrix< bigint > &, ....):: "
95 "Dimension of matrix does not match degree of order");
96 assign(module());
97 }
98 base.image(base);
99 normalize();
100 // WILL BE REMOVED IN NEXT RELEASE:
101 if (B.get_no_of_columns() != O1->degree())
102 multiply(*this, *this, alg_ideal_cast(order(static_cast<const nf_base *>(O))));
103 }
104
105
106
module(const bigmod_matrix & B,const bigint & d,const nf_base * O1)107 module::module(const bigmod_matrix & B, const bigint & d,
108 const nf_base * O1)
109 : base(B),
110 den(d),
111 O(const_cast<nf_base *>(O1)),
112 is_exp(false)
113 {
114 debug_handler_c("module",
115 "in module(const bigmod_matrix &, const bigint &, "
116 "const nf_base *)", 1,
117 count++;
118 std::cout << "\nNow we have " << count << " modules!\n");
119 O->inc_ref();
120 if (B.get_no_of_rows() != O1->degree()) {
121 lidia_error_handler("module", "module(const bigmod_matrix &, ....):: "
122 "Dimension of matrix does not match degree of order");
123 assign(module());
124 }
125 base.image(base);
126 normalize();
127 }
128
129
130
module(const nf_base * O1)131 module::module(const nf_base * O1)
132 : base(O1->degree(), 1),
133 den(1),
134 O(const_cast<nf_base *>(O1)),
135 is_exp(true)
136 {
137 debug_handler_c("module", "in module(const nf_base *)", 1,
138 count++;
139 std::cout << "\nNow we have " << count << " modules!\n");
140 O->inc_ref();
141 }
142
143
144
module(const module & M)145 module::module(const module & M)
146 : base(M.base),
147 den(M.den),
148 O(M.O),
149 is_exp(M.is_exp)
150 {
151 debug_handler_c("module", "in module(const module &)", 1,
152 count++;
153 std::cout << "\nNow we have " << count << " modules!\n");
154 O->inc_ref();
155 }
156
157
158
~module()159 module::~module()
160 {
161 debug_handler_c("module", "in ~module()", 1,
162 count--;
163 std::cout << "\nNow we have only " << count << " modules!\n");
164 O->dec_ref();
165 }
166
167
168
169 // member-functions
is_zero() const170 bool module::is_zero() const
171 {
172 // if (base.is_matrix_zero() && base.get_no_of_columns() > 1)
173 // lidia_error_handler_c("module","is_zero()",
174 // std::cout <<"\nNon standard representation of zer "
175 // "found for "<<base<<std::endl);
176 return (base.get_modulus().is_zero()
177 && base.get_no_of_columns() == 1 && base.is_matrix_zero());
178 }
179
180
181
is_whole_order() const182 bool module::is_whole_order() const
183 {
184 if (!(den.is_one()))
185 return false;
186 if (base.get_modulus().is_one())
187 return true;
188 lidia_size_t n = base.get_no_of_rows();
189 if (base.get_no_of_columns() != n)
190 return false;
191 bigint_matrix A(n, n);
192 A.diag(1, 0);
193 return (A == base);
194 }
195
196
197
normalize()198 void module::normalize()
199 {
200 if (den.is_negative())
201 den.negate();
202 bigint d = gcd(den, base.get_modulus());
203 register lidia_size_t i, j;
204 for (i = 0; !(d.is_one()) && i < degree(); i++)
205 for (j = 0; !(d.is_one()) && j < base.get_no_of_columns(); j++)
206 d = gcd (base.member(i, j), d);
207 if (!(d.is_one())) {
208 den /= d;
209 base /= d;
210 base.reduce(base.get_modulus()/d);
211 }
212 }
213
214
215
invert()216 void module::invert()
217 {
218 debug_handler("module", "in member - function invert()");
219 lidia_size_t n = base.get_no_of_columns();
220 lidia_size_t m = base.get_no_of_rows();
221
222 if (base.get_modulus().is_zero() && n != m) {
223 lidia_error_handler("module", "invert():: Sorry, I can only "
224 "invert modules of full rank");
225 return;
226 }
227 bigint d = den;
228 den.assign_one(); //Multiply *this by den !!
229
230 //Now we have an integral Z -- module
231 // Compute and save the norm
232 bigint N = exponent(*this).numerator(); //it's anyway an integer!!
233 // Compute: O/(exp(M)) ---> Hom( M/(exp(M)) --> O/(exp(M)) )
234 // a ---> ( b --> a b )
235
236 alg_number a, b, y;
237 base.reduce(N);
238
239 n = base.get_no_of_columns();
240 bigmod_matrix Map(n*m, m, N);
241 bigint * tmp = new bigint[m], rem;
242
243 register lidia_size_t i;
244
245 base_vector< bigint > tmp_vec(a.degree(), a.degree());
246 for (i = 0; i < m; tmp[i++].assign_zero()) {
247 tmp[i].assign_one(); //tmp = e_i;
248 // compute the images of the basis of O
249 a = alg_number(tmp, 1, O);
250 //a=e_i
251 for (register lidia_size_t j = 0; j < n; j++) {
252 // compute the images of the basis of M
253 // under the MULT-with-a-homomorphism
254 base.get_column_vector(tmp_vec, j);
255 b = alg_number(tmp_vec, 1, O);
256 multiply(y, a, b); // the image under the MULT-with-a-homomorphism
257 tmp_vec = y.coeff_vector();
258 Map.sto_column_vector(y.coeff_vector(), m, i, j*m);
259 }
260 }
261 delete[] tmp;
262
263 // Computing the kernel of this matrix and selecting the right rows
264 debug_handler_c("module", "invert", 2,
265 std::cout << "Computing kernel of " << Map << std::endl);
266 base.kernel(Map);
267 debug_handler_c("module", "invert", 2,
268 std::cout << "Kernel is " << base << std::endl);
269 den.assign(N);
270 base.image(base);
271 if (!(d.is_one())) multiply(*this, *this, d);
272 normalize();
273 is_exp = false;
274 debug_handler_c("module", "invert", 2,
275 std::cout << "so the inverse is " << (*this) << std::endl);
276 }
277
278
279
assign_zero()280 void module::assign_zero()
281 {
282 base.set_no_of_columns(1);
283 base.set_modulus(0);
284 for (lidia_size_t i = 0; i < degree(); i++)
285 base.sto(i, 0, bigint(0));
286 den.assign_one();
287 is_exp = true;
288 }
289
290
291
292 // WILL BE REMOVED IN NEXT RELEASE:
assign(const bigint & a)293 void module::assign(const bigint & a)
294 {
295 debug_handler("module", "in member - function assign(const bigint &)");
296 base.set_no_of_rows(degree());
297 base.set_no_of_columns(1);
298 for (lidia_size_t i = 0; i < degree(); i++)
299 base.sto(i, 0, bigint(0));
300 base.set_modulus(abs(a));
301 den.assign_one();
302 is_exp = true;
303 }
304
305
306
307 // WILL BE REMOVED IN NEXT RELEASE:
assign(const alg_number & a)308 void module::assign(const alg_number & a)
309 {
310 debug_handler("module", "in member - function assign(a_n &)");
311 base.set_no_of_columns(1);
312 base.set_no_of_rows(a.degree());
313 base.set_modulus(0);
314 if (O != a.O) {
315 O->dec_ref();
316 O = a.O;
317 O->inc_ref();
318 }
319 base.sto_column_vector(a.coeff_vector(), degree(), 0);
320 den = a.den;
321 is_exp = false;
322 multiply(*this, *this, alg_ideal_cast(order(static_cast<const nf_base *>(O))));
323 }
324
325
326
assign(const module & a)327 void module::assign(const module & a)
328 {
329 debug_handler("module", "in member - function assign(module &)");
330 if (O != a.O) {
331 O->dec_ref();
332 O = a.O;
333 O->inc_ref();
334 }
335 base = a.base;
336 den = a.den;
337 is_exp = a.is_exp;
338 }
339
340
341
342 // Procedural versions:
add(module & c,const module & a,const module & b)343 void add(module & c, const module & a, const module & b)
344 {
345 debug_handler("module", "in function "
346 "add(module &, const module &, const module &)");
347 if (a.O != b.O) {
348 lidia_error_handler("module", "add(...):: Addition of modules from "
349 "different orders is not yet implemented");
350 return;
351 }
352
353 if (c.O != a.O) {
354 c.O->dec_ref();
355 c.O = a.O;
356 c.O->inc_ref();
357 }
358 c.is_exp = false;
359
360 bigint d = gcd(a.den, b.den);
361 bigint e = (a.den.is_zero())? bigint(1) : a.den / d;
362 bigint f = (b.den.is_zero())? bigint(1) : b.den / d;
363
364 debug_handler_c("module", "add", 0,
365 std::cout << "Adding " << a << "(" << a.base << ") and ";
366 std::cout << b << "(" << b.base << ")" << std::flush);
367
368 bigmod_matrix
369 multhelp1(a.base.get_no_of_rows(), a.base.get_no_of_columns(),
370 a.base.get_modulus() * f),
371 multhelp2(a.base.get_no_of_rows(), b.base.get_no_of_columns(),
372 b.base.get_modulus() * e);
373
374 debug_handler_c("module", "add", 5,
375 std::cout << "multiply a by " << f << " and b by " << e);
376
377 multiply(multhelp1, a.base, f);
378 multiply(multhelp2, b.base, e);
379
380 debug_handler_c("module", "add", 5,
381 std::cout << "results are " << multhelp1 << " and " << multhelp2);
382
383
384 d.assign(gcd(multhelp1.get_modulus(), multhelp2.get_modulus()));
385 multhelp1.reduce(d);
386 multhelp2.reduce(d);
387
388 debug_handler_c("module", "add", 5,
389 std::cout << "reduced results are " << multhelp1 << " and " << multhelp2);
390 debug_handler_c("module", "in add(...) -- tmp should be a ", 0,
391 std::cout << a.degree() << "x" << multhelp1.get_no_of_columns()
392 + multhelp2.get_no_of_columns() << "matrix");
393 bigmod_matrix tmp(a.degree(), multhelp1.get_no_of_columns()
394 + multhelp2.get_no_of_columns(), d);
395 debug_handler_c("module", "in add(...) -- tmp is", 0, std::cout << tmp);
396 tmp.compose_h(multhelp1, multhelp2);
397 // i.e. tmp.compose_h(a.base * f, b.base * e);
398 debug_handler_c("module", "in add(...) -- tmp is", 0, std::cout << tmp);
399
400 c.base.image(tmp);
401 debug_handler_c("module", "in add(...) -- reduced tmp is", 0, std::cout << c.base);
402
403 multiply(c.den, e, b.den);
404 c.normalize();
405 }
406
407
408
intersect(module & c,const module & a,const module & b)409 void intersect(module & c, const module & a, const module & b)
410 {
411 debug_handler("module", "in function intersect(module, "
412 "const & module, const & module)");
413 if (a.O != b.O) {
414 lidia_error_handler("module", "intersect(...):: "
415 "Intersection of modules from "
416 "different orders is not yet implemented");
417 return;
418 }
419
420 debug_handler_c("module", "intersect", 5,
421 std::cout << "process" << a << " and " << b;
422 std::cout << "represented by " << a.base << " and " << b.base);
423
424 if (c.O != a.O) {
425 c.O->dec_ref();
426 c.O = a.O;
427 c.O->inc_ref();
428 }
429 c.is_exp = false;
430
431 bigint d = gcd(a.den, b.den);
432 bigint e = a.den / d;
433 bigint f = b.den / d;
434 c.base.set_no_of_rows(a.degree());
435
436 bigmod_matrix kern,
437 tmp1(a.base.get_no_of_rows(), a.base.get_no_of_columns(),
438 a.base.get_modulus() * f),
439 tmp2(a.base.get_no_of_rows(), b.base.get_no_of_columns(),
440 b.base.get_modulus() * e);
441
442 debug_handler_c("module", "intersect", 5,
443 std::cout << "multiply a by " << f << " and b by " << -e);
444
445 multiply(tmp1, a.base, f);
446 multiply(tmp2, b.base, -e);
447
448 debug_handler_c("module", "intersect", 5,
449 std::cout << "results are " << tmp1 << " and " << tmp2);
450
451 d = lcm(a.base.get_modulus()*f, b.base.get_modulus()*e);
452 tmp1.lift(d);
453 tmp2.lift(d);
454
455 debug_handler_c("module", "intersect", 5,
456 std::cout << "Lifting mod " << d
457 << " results in " << tmp1 << " and " << tmp2);
458
459 bigmod_matrix tmp(a.degree(), tmp1.get_no_of_columns()
460 + tmp2.get_no_of_columns(), d);
461 debug_handler_c("module", "intersect", 5,
462 std::cout << "compose " << tmp1 << " and " << tmp2);
463 tmp.compose_h(tmp1, tmp2);
464 debug_handler_c("module", "intersect", 5,
465 std::cout << "compute kernel of " << tmp);
466 kern.kernel(tmp);
467 debug_handler_c("module", "intersect", 5,
468 std::cout << "kernel is " << kern);
469 tmp.set_no_of_columns(kern.get_no_of_columns());
470
471 math_vector< bigint > tmp_vec(a.degree(), a.degree());
472 for (lidia_size_t i = 0; i < kern.get_no_of_columns(); i++) {
473 kern.get_column_vector(tmp_vec, i);
474 tmp.sto_column_vector((tmp1 * tmp_vec), a.degree(), i);
475 }
476 c.base.image(tmp);
477 debug_handler_c("module", "intersect", 5,
478 std::cout << "base is " << c.base);
479 multiply(c.den, e, b.den);
480 c.normalize();
481 }
482
483
484
485 #if 0
486 void multiply2(module &c, const module & a, const module & b)
487 {
488 debug_handler("module","in function multiply2 (module, "
489 "const & module, const & module)");
490 c.O->dec_ref();
491 c.O = a.O;
492 c.O->inc_ref();
493
494 c.base.set_no_of_rows(a.degree());
495
496 bigmod_matrix tmp1;
497 tmp1.special_multiply(a.base, b.base, (a.O)->table);
498 tmp1.image(tmp1);
499 register lidia_size_t i = 0;
500 for (register lidia_size_t j = 0; j<tmp1.get_no_of_columns(); j++)
501 if (!tmp1.is_column_zero(j)) i++;
502 if (i==0){
503 c.base.set_no_of_columns(1);
504 }
505 else {
506 c.base.set_no_of_columns(i);
507 }
508 tmp1.split_h(tmp1, c.base);
509 c.den = a.den * b.den;
510 c.normalize();
511 }
512 #endif
513
514
515
multiply(module & c,const module & a,const module & b)516 void multiply(module & c, const module & a, const module & b)
517 {
518 debug_handler("module", "in function multiply(module, "
519 "const & module, const & module)");
520 if (a.O != b.O) {
521 lidia_error_handler("module", "multiply(...):: Multiplication of modules "
522 "from different orders is not yet implemented");
523 return;
524 }
525
526 if (c.O != a.O) {
527 c.O->dec_ref();
528 c.O = a.O;
529 c.O->inc_ref();
530 }
531 if (a.is_zero() || b.is_zero()) {
532 c.assign_zero();
533 return;
534 }
535 c.is_exp = false;
536
537 c.base.set_no_of_rows(a.degree());
538
539
540 // Obvious improvement: First lift the original moduls, if they don't have
541 // no_of_columns == rank and avoid appending b*a.modulus()*I,a*b.modulus()*I.
542
543 alg_number n1, n2;
544 bigint d;
545 multiply(d, a.base.get_modulus(), b.base.get_modulus());
546 lidia_size_t column_no1
547 = a.base.get_no_of_columns()*b.base.get_no_of_columns();
548 lidia_size_t column_no = column_no1;
549 lidia_size_t column_no2 = column_no1;
550 if (!(a.base.get_modulus().is_zero()))
551 column_no2 =
552 (column_no += a.base.get_no_of_rows() * b.base.get_no_of_columns());
553 if (!(b.base.get_modulus().is_zero()))
554 column_no += b.base.get_no_of_rows() * a.base.get_no_of_columns();
555
556 bigmod_matrix tmp1(a.degree(), column_no, d);
557
558 register lidia_size_t i;
559
560 debug_handler_c("module", "multiply(...)", 1,
561 std::cout << a << " and " << b;
562 std::cout << "represented by" << a.base << " and " << b.base);
563
564 math_vector< bigint > tmp_vec(a.degree(), a.degree());
565 for (i = 0; i < a.base.get_no_of_columns(); i++) {
566 a.base.get_column_vector(tmp_vec, i);
567 alg_number n1(tmp_vec, 1, a.which_base());
568 for (register lidia_size_t j = 0; j < b.base.get_no_of_columns(); j++) {
569 b.base.get_column_vector(tmp_vec, j);
570 alg_number n2(tmp_vec, 1, b.which_base());
571 debug_handler_c("module", "multiply::multiply elements", 0,
572 std::cout << i << " " << j << " " << i*b.base.get_no_of_columns()+j);
573 tmp1.sto_column_vector((n1*n2).coeff_vector(),
574 b.degree(), i*b.base.get_no_of_columns()+j);
575 }
576 }
577
578 // append b*a.modulus()*I
579 bigint * tmp2 = new bigint[b.base.get_no_of_rows()];
580 if (!(a.base.get_modulus().is_zero())) {
581 d.assign(a.base.get_modulus());
582 for (i = 0; i < b.base.get_no_of_columns(); i++) {
583 b.base.get_column_vector(tmp_vec, i);
584 alg_number n1(tmp_vec, 1, b.which_base());
585 for (register lidia_size_t j = 0; j < a.base.get_no_of_rows();
586 tmp2[j++].assign_zero()) {
587 tmp2[j].assign(d);
588 alg_number n2(tmp2, 1, a.which_base());
589 debug_handler_c("module", "multiply::multiply elements", 0,
590 std::cout << n1 << " " << n2 << " " << column_no1+i*a.base.get_no_of_rows()+j);
591 tmp1.sto_column_vector((n1*n2).coeff_vector(), b.degree(),
592 column_no1 + i * a.base.get_no_of_rows() + j);
593 }
594 }
595 }
596
597 // append a*b.modulus()*I
598 if (!(b.base.get_modulus().is_zero())) {
599 d.assign(b.base.get_modulus());
600 for (i = 0; i < a.base.get_no_of_columns(); i++) {
601 a.base.get_column_vector(tmp_vec, i);
602 alg_number n1(tmp_vec, 1, a.which_base());
603 for (register lidia_size_t j = 0; j < b.base.get_no_of_rows();
604 tmp2[j++].assign_zero()) {
605 tmp2[j].assign(d);
606 alg_number n2(tmp2, 1, b.which_base());
607 debug_handler_c("module", "multiply::multiply elements", 0,
608 std::cout << n1 << " " << n2 << " " << column_no2 + i*b.base.get_no_of_rows()+j);
609 tmp1.sto_column_vector((n1*n2).coeff_vector(), b.degree(),
610 column_no2 + i * b.base.get_no_of_rows() + j);
611 }
612 }
613 }
614 delete[] tmp2;
615
616 c.base.image(tmp1);
617 c.den = a.den * b.den;
618 c.normalize();
619 debug_handler_c("module", "multiply::end of call", 1,
620 std::cout << "Product is " << c << "represented by " << c.base << std::endl);
621 }
622
623
624
multiply(module & c,const module & a,const bigint & b)625 void multiply(module &c, const module &a, const bigint & b)
626 {
627 bigint d = gcd(a.den, b);
628 if (c.O != a.O) {
629 c.O->dec_ref();
630 c.O = a.O;
631 c.O->inc_ref();
632 }
633
634 if (!(b.is_zero())) {
635 bigint e;
636 divide(e, b, d);
637 e.absolute_value();
638 c.is_exp = a.is_exp;
639 c.den = a.den / d; // Might change value of b, if &b == &c.den !!
640 c.base.set_modulus(a.base.get_modulus()*e);
641 multiply(c.base, a.base, e);
642 }
643 else c.assign_zero();
644 }
645
646
647
multiply(module & c,const bigint & b,const module & a)648 void multiply(module &c, const bigint &b, const module &a)
649 {
650 bigint d = gcd(a.den, b);
651
652 if (c.O != a.O) {
653 c.O->dec_ref();
654 c.O = a.O;
655 c.O->inc_ref();
656 }
657 if (!(b.is_zero())) {
658 bigint e;
659 divide(e, b, d);
660 e.absolute_value();
661 c.is_exp = a.is_exp;
662 c.den = a.den / d; // Might change value of b, if &b == &c.den !!
663 c.base.set_modulus(a.base.get_modulus()*e);
664 multiply(c.base, a.base, e);
665 }
666 else c.assign_zero();
667 }
668
669
670
divide(module & c,const module & a,const bigint & b)671 void divide(module &c, const module &a, const bigint & b)
672 {
673 debug_handler("alg_numbers", "in function divide(module &, "
674 "const module &, const bigint &)");
675 if (c.O != a.O) {
676 c.O->dec_ref();
677 c.O = a.O;
678 c.O->inc_ref();
679 }
680 c.is_exp = a.is_exp;
681
682 c.base = a.base;
683
684 if (&c != &a) {
685 c.den = b;
686 c.normalize();
687 c.den *= a.den;
688 }
689 else {
690 bigint tmp = a.den;
691 c.den = b;
692 c.normalize();
693 c.den *= tmp;
694 }
695 }
696
697
698
divide(module & c,const module & a,const module & bb)699 void divide(module & c, const module & a, const module & bb)
700 {
701 debug_handler_c("module", "in function divide(module &, const module &, "
702 "const module &", 2, std::cout << "Divide " << a << " by " << bb);
703 if (a.O != bb.O) {
704 lidia_error_handler("module", "divide(...):: Division of modules from "
705 "different orders is not yet implemented");
706 return;
707 }
708 if (bb.base.get_modulus().is_zero() &&
709 bb.base.get_no_of_columns() != bb.base.get_no_of_rows()) {
710 lidia_error_handler("module", "divide():: Sorry, I can only "
711 "divide by modules of full rank");
712 return;
713 }
714
715 if (c.O != a.O) {
716 c.O->dec_ref();
717 c.O = a.O;
718 c.O->inc_ref();
719 }
720
721 if (a.is_zero()) {
722 c.base.set_no_of_rows(a.base.get_no_of_rows());
723 c.assign_zero();
724 return;
725 }
726 c.is_exp = false;
727
728 module b(bb);
729
730 bigint d = b.den;
731 b.den.assign_one(); // Multiply b by den !!
732
733 //Now 'b' is an integral Z -- modules.
734 // Compute and save the exponent of B (which is an integer !!)
735 bigint N = exponent(b).numerator();
736 b.base.lift(0);
737 bigmod_matrix tmp(a.base);
738 tmp.lift(0);
739
740 lidia_size_t m = tmp.get_no_of_columns();
741 lidia_size_t n = b.base.get_no_of_columns();
742
743 //Now we consider two integral Z -- modules, where 'b' has full rank.
744 // Compute: A ---> Hom( B --> O / (exp(B) A) )
745 // a ---> ( b --> a b )
746
747 alg_number x, y, z;
748
749 bigint_matrix Map(a.degree() * n, m * (n+1));
750
751 register lidia_size_t i;
752
753 base_vector< bigint > tmp_vec(a.degree(), a.degree());
754 for (i = 0; i < m; i++) {
755 // compute the images of the basis of A
756 tmp.get_column_vector(tmp_vec, i);
757 x = alg_number(tmp_vec, 1, a.O);
758 for (register lidia_size_t j = 0; j < n; j++) {
759 // compute the images of the basis of B
760 // under the MULT-with-x-homomorphism
761 b.base.get_column_vector(tmp_vec, j);
762 y = alg_number(tmp_vec, 1, b.O);
763 multiply(z, x, y); // the image under the MULT-with-a-homomorphism
764 tmp_vec = z.coeff_vector();
765 // Put the image in the matrix of the map
766 Map.sto_column_vector(tmp_vec, a.degree(), i, j*a.degree());
767 }
768 }
769
770 // Complete initialization of map by use of a
771 // (n*degree())x(m*n) diagonal matrix,
772 // containing N(B)* A ... on the diagonal.
773 if (N.is_negative()) {
774 lidia_error_handler_c("module", "divide",
775 std::cout << "Norm of B < 0 for B = " << b << ": " << N << std::endl);
776 return;
777 }
778 bigint_matrix NtimesA;
779 multiply(NtimesA, *(static_cast<bigint_matrix *>(&tmp)), N);
780
781 register lidia_size_t j = m;
782 for (i = 0; i < n * m; i++, j++)
783 for (register lidia_size_t k = 0; k < a.degree(); k++)
784 Map.sto(k + (i/n) * n, j, NtimesA.member(k, i % m));
785
786 // Computing the kernel of this matrix and selecting the right rows
787 debug_handler_c("module", "divide", 2,
788 std::cout << "Computing kernel of " << Map << std::endl);
789 bigint_matrix tmp2;
790 tmp2.kernel(Map);
791 debug_handler_c("module", "divide", 2,
792 std::cout << "Verify kernel: " << Map*tmp2 << std::endl);
793 tmp2.set_no_of_rows(m);
794 debug_handler_c("module", "divide", 2,
795 std::cout << "Kernel is " << tmp2 << std::endl);
796 bigint reduction_para;
797 multiply(reduction_para, a.base.get_modulus(), N);
798 c.base.set_modulus(0);
799 multiply(*(static_cast<bigint_matrix *>(&c.base)),
800 *(static_cast<bigint_matrix *>(&tmp)), tmp2); //bigint_matrix - Multiplikation !!
801 if (reduction_para.is_zero())
802 c.base.image(c.base);
803 else
804 c.base.reduce(reduction_para);
805 debug_handler_c("module", "divide", 2,
806 std::cout << "so c.base is " << c.base << std::endl);
807 if (!(a.den.is_one()))
808 multiply(c.den, a.den, N);
809 else
810 c.den.assign(N);
811 if (!(d.is_one())) multiply(c, c, d);
812 c.normalize();
813 debug_handler_c("module", "divide", 2,
814 std::cout << "so c is " << c << std::endl);
815 debug_handler_c("module", "divide", 2,
816 std::cout << "Verify: " << bb*c << a << std::endl);
817 }
818
819
820
remainder(module & c,const module & a,const bigint & p)821 void remainder(module &c, const module &a, const bigint &p)
822 {
823 if (!(a.den.is_one())) {
824 lidia_error_handler("module", "remainder:: Reducing mod p for a "
825 "fractional ideal ??");
826 return;
827 }
828 c.assign(a);
829 bigint new_mod = a.base.get_modulus() %p;
830 if (new_mod.is_zero()) new_mod.assign(p);
831 c.base.set_modulus(new_mod << 1);
832 c.base.reduce(new_mod);
833 c.base.image(c.base);
834 }
835
836
837
power(module & c,const module & a,const bigint & b)838 void power(module & c, const module & a, const bigint & b)
839 {
840 debug_handler("module", "in function power(module &, "
841 "const module &, const bigint &)");
842 bigint expo;
843 nf_base * O = a.which_base();
844 module multiplier(O);
845
846 if (c.O != a.O) {
847 c.O->dec_ref();
848 c.O = a.O;
849 c.O->inc_ref();
850 }
851 if (b.is_negative())
852 power(c, inverse(a), -b);
853 else if (b.is_zero() || a.is_one())
854 c.assign_one();
855 else {
856 expo.assign(b);
857 multiplier.assign(a);
858 c.assign_one();
859 while (expo.is_gt_zero()) {
860 if (!(expo.is_even()))
861 multiply(c, c, multiplier);
862 square(multiplier, multiplier);
863 expo.divide_by_2();
864 }
865 }
866 }
867
868
869
870 // Comparision:
871 // By now, only comparision of modules over the same order is implemented.
872 // One function to compute the needed information:
873
compare(const module & a,bool & equal,bool & a_in_this) const874 void module::compare(const module & a,
875 bool & equal,
876 bool & a_in_this) const
877 {
878 debug_handler("module", "in member - function compare(...)");
879 if (equal = (this == &a))return;
880 if (O != (a.O)) { //we should use *O != *(a.O)
881 lidia_error_handler("module", "compare::You tried to compare modules over "
882 "different bases!");
883 return;
884 }
885
886 debug_handler_c("module", "compare", 9,
887 std::cout << "comparing" << (*this) << " and " << a;
888 std::cout << "represented by " << base << " and " << a.base);
889 debug_handler_c("module", "compare", 9,
890 std::cout << " and these are true exponents: ";
891 std::cout << is_exp << " " << a.is_exp << std::endl);
892
893 if (den != a.den) {
894 bigint d = gcd(den, a.den);
895 ((*this)*(a.den/d)*den).compare(a*(den/d)*a.den, equal, a_in_this);
896 return;
897 }
898
899 // First compute exponents
900 bigint expo = base.get_modulus(),
901 aexpo = a.base.get_modulus();
902
903 if (!is_exp) {
904 base.exponent(expo);
905 base.reduce(expo);
906 is_exp = true;
907 }
908 if (!a.is_exp) { // Wouldn't change, if &a = this, so check
909 a.base.exponent(aexpo); // at beginning is necessary!!!
910 a.base.reduce(aexpo);
911 a.is_exp = true;
912 }
913
914 // Check for equality - also useful, in case you're not checking
915 // for equality since either fast or sufficient
916 debug_handler_c("module", "compare", 9,
917 std::cout << "Reduced to " << (*this) << " and " << a;
918 std::cout << "represented by " << base << " and " << a.base);
919 bigmod_matrix cmp1(base), cmp2(a.base);
920 if (aexpo == expo) {
921 if (equal = (den == a.den && base == a.base)) return;
922 if (den == a.den) {
923 cmp1.unique_image(cmp1);
924 cmp2.unique_image(cmp2);
925 if (equal = (cmp1 == cmp2)) return;
926 }
927 }
928 else equal = false;
929
930 //Check for inclusion - useless, if you check for (in-)equality!!!
931 bigint rem;
932 if (expo.is_zero()) {
933 if (!aexpo.is_zero()) {
934 a_in_this = false;
935 return;
936 }
937 }
938 else {
939 remainder(rem, aexpo, expo);
940 if (!(rem.is_zero())) {
941 a_in_this = false;
942 return;
943 }
944 }
945 cmp1.lift(0);
946 bigint_matrix T;
947 debug_handler_c("module", "compare", 9,
948 std::cout << "Trying to solve " << cmp1 << a.base << std::endl);
949 if (cmp1.get_no_of_columns() == cmp1.get_no_of_rows()) {
950 T.reginvimage(cmp1, a.base);
951 debug_handler_c("module", "compare", 9,
952 std::cout << "Solution is " << T << std::endl);
953 a_in_this = true;
954 for (lidia_size_t i = 0; a_in_this && (i < T.get_no_of_columns()); i++)
955 if (!(T.member(degree(), i).is_one())) a_in_this = false;
956 }
957 else {
958 a_in_this = true;
959 for (lidia_size_t i = 0; a_in_this && (i < a.base.get_no_of_columns()); i++) {
960 debug_handler_c("module", "compare", 9,
961 std::cout << " Calling solve for " << cmp1 << " and ";
962 std::cout << a.base.get_column_vector(i) << std::endl);
963 T.solve(cmp1, a.base.get_column_vector(i));
964 debug_handler_c("module", "compare", 9,
965 std::cout << "Solution for column " << i << " is:" << T << std::endl);
966 if (T.get_no_of_columns() == 1) a_in_this = false;
967 }
968 }
969 }
970
971
972
operator ==(const module & a,const module & b)973 bool operator == (const module & a, const module & b)
974 {
975 bool equal, b_in_a;
976 debug_handler_l("module", "operator == ", 2);
977 a.compare(b, equal, b_in_a);
978 return equal;
979 }
980
981
982
operator !=(const module & a,const module & b)983 bool operator != (const module & a, const module & b)
984 {
985 bool equal, b_in_a;
986 a.compare(b, equal, b_in_a);
987 return !equal;
988 }
989
990
991
operator <=(const module & a,const module & b)992 bool operator <= (const module & a, const module & b) // Same as divisibility!!!!
993 {
994 bool equal, a_in_b;
995 b.compare(a, equal, a_in_b);
996 return (equal || a_in_b);
997 }
998
999
1000
operator <(const module & a,const module & b)1001 bool operator < (const module & a, const module & b)
1002 {
1003 bool equal, a_in_b;
1004 b.compare(a, equal, a_in_b);
1005 return (!equal && a_in_b);
1006 }
1007
1008
1009
operator >=(const module & a,const module & b)1010 bool operator >= (const module & a, const module & b)
1011 {
1012 bool equal, b_in_a;
1013 a.compare(b, equal, b_in_a);
1014 return (equal || b_in_a);
1015 }
1016
1017
1018
operator >(const module & a,const module & b)1019 bool operator > (const module & a, const module & b)
1020 {
1021 bool equal, b_in_a;
1022 a.compare(b, equal, b_in_a);
1023 return (!equal && b_in_a);
1024 }
1025
1026
1027
1028 // Some number-theoretic functions:
norm(const module & a)1029 bigrational norm(const module & a) // Norm
1030 {
1031 if (a.base.get_modulus().is_zero() &&
1032 a.base.get_no_of_columns() != a.degree()) {
1033 return 0;
1034 }
1035 bigmod_matrix tmp (a.base);
1036 tmp.lift(0);
1037 bigint normdenominator;
1038 power(normdenominator, a.den, bigint(a.degree()));
1039 return bigrational((bigint_matrix(tmp)).det(), normdenominator);
1040 }
1041
1042
1043
exponent(const module & a)1044 bigrational exponent(const module & a)
1045 {
1046
1047 debug_handler_c("module",
1048 "in function exp(const & module)", 3,
1049 std::cout << "Computing exponent of " << a << std::endl);
1050 if (!a.is_exp) {
1051 bigint e(a.base.exponent());
1052 a.base.reduce(e);
1053 a.is_exp = true;
1054 }
1055 return bigrational(a.base.get_modulus(), a.den);
1056 }
1057
1058
1059
ring_of_multipliers(const bigint & p) const1060 order module::ring_of_multipliers(const bigint &p) const
1061 {
1062 // We are here in a member function of `Ip'
1063 // Consider the kernel C of the map:
1064 // O/pO -> End(Ip/pIp)
1065 // a -> (b -> ab)
1066 // then the result O' fullfills: O' =1/p * C
1067 // quite similar to `pseudo-radical', but more complicated, since
1068 // now we have matrices for each (b -> ab).
1069
1070 debug_handler("module", "in member - function ring_of_multipliers(const bigint &, bigint &)");
1071 register lidia_size_t i, j, k;
1072 register lidia_size_t n = base.get_no_of_columns();
1073 register lidia_size_t m = degree();
1074 alg_number a, b, y;
1075
1076 bigint_matrix init(m, n*m);
1077 bigmod_matrix B(base);
1078 bigmod_matrix C;
1079 bigmod_matrix VW(n * m, m, p);
1080 bigint_matrix v;
1081 bigint * tmp = new bigint[m];
1082 bigint rem;
1083
1084 if (base.get_modulus().is_zero() && n != base.get_no_of_rows()) {
1085 lidia_error_handler("module", "ring_of_multipliers(const bigint &):: "
1086 "Sorry, I can compute this only for "
1087 "modules of full rank");
1088 delete [] tmp;
1089 return order();
1090 }
1091
1092 math_vector< bigint > tmp_vec(a.degree(), a.degree());
1093 for (i = 0; i < m; tmp[i++].assign_zero()) {
1094 tmp[i].assign_one(); //tmp = e_i;
1095 // compute the images of the basis of O/pO
1096 a = alg_number(tmp, 1, O);
1097 //a=e_i
1098 for (j = 0; j < n; j++) {
1099 // compute the images of the basis of A+pO
1100 // under the MULT-with-a-homomorphism
1101 B.get_column_vector(tmp_vec, j);
1102 b = alg_number(tmp_vec, 1, O);
1103 y = a*b; // the image under the MULT-with-a-homomorphism
1104 init.sto_column_vector(y.coeff_vector(), m, i*n+j);
1105 }
1106 }
1107 delete[] tmp;
1108
1109 // the image must be written relative to base;
1110 B.lift(0);
1111 debug_handler_c("module", "in member - function ring_of_multipliers(...)",
1112 1, std::cout << "solve " << B << init << std::endl << std::flush);
1113 v.reginvimage(B, init);
1114 debug_handler_c("module", "in member - function ring_of_multipliers(...)",
1115 1, std::cout << "solution is " << v << std::endl << std::flush);
1116 // move the result to the Matrix VW
1117 for (i = 0; i < m; i++) {
1118 for (j = 0; j < n; j++) {
1119 for (k = 0; k < m; k++) {
1120 VW.sto(k+j*m, i, v.member(k, i*n+j));
1121 }
1122 }
1123 }
1124 debug_handler_c("module", "in member - function ring_of_multipliers(...)",
1125 1, std::cout << "Compute kernel of" << VW);
1126 C.kernel(VW);
1127 debug_handler_c("module", "in member - function ring_of_multipliers(...)",
1128 1, std::cout << "Kernel is " << C << std::flush);
1129
1130 // interpret C as a module M and lift it into the order!!
1131 init.set_no_of_columns(k = C.get_no_of_columns());
1132 for (j = 0; j < n; j++) {
1133 C.get_row_vector(tmp_vec, j);
1134 init.sto_row_vector(tmp_vec, k, j);
1135 }
1136 module M(init, 1, O);
1137 M += p * order(static_cast<const nf_base *>(O)); // hopefully interpreted as module-mult.
1138 debug_handler_c("module", "in member - function ring_of_multipliers(...)",
1139 4, std::cout << "Module is" << M << std::flush);
1140
1141 // Instead of creating the multiplication table, we create the base:
1142 if (!(O->f.is_zero())) {
1143 M.den *= p;
1144 M.normalize();
1145 debug_handler_c("module", "ring_of_multipliers(...)", 4,
1146 std::cout << "Transformation is 1/" << M.den << " * ";
1147 std::cout << M.base << std::endl << std::flush);
1148
1149 order result(M.z_basis(), M.den, O);
1150 debug_handler_c("module", "ring_of_multipliers(...)", 4,
1151 std::cout << "So the new order has the following table";
1152 std::cout << result << std::endl << std::flush;
1153 std::cout << "and the Discriminant is" << disc(result);
1154 std::cout << std::endl << std::flush);
1155 return result;
1156 }
1157 else {
1158 // If we can't create the base (because there is no field)
1159 // create the MT instead.
1160 base_vector< bigint > tmp;
1161 n = M.base.get_no_of_rows();
1162 bigint_matrix help = M.z_basis();
1163 init.set_no_of_columns((n*(n+1))/2);
1164 for (i = 0; i < n; i++) {
1165 help.get_column_vector(tmp, i);
1166 a = alg_number(tmp, 1, O);
1167 for (j = 0; j <= i; j++) {
1168 help.get_column_vector(tmp, j);
1169 b = alg_number(tmp, 1, O);
1170 init.sto_column_vector((a*b).coeff_vector(), n, (i*(i+1))/2+j);
1171 }
1172 }
1173 debug_handler_c("module",
1174 "in member - function ring_of_multipliers(...)", 3,
1175 std::cout << "solve " << help << init << std::endl << std::flush);
1176
1177 init.reginvimage(help, init);
1178 init.set_no_of_rows(n);
1179
1180 debug_handler_c("module",
1181 "in member - function ring_of_multipliers(...)", 3,
1182 std::cout << "p * MT is" << trans(init) << std::flush);
1183
1184 for (i = 0; i < init.get_no_of_rows(); i++)
1185 for (j = 0; j < init.get_no_of_columns(); j++) {
1186 bigint q, r;
1187 div_rem(q, r, init.member(i, j), p);
1188 if (!(r.is_zero())) {
1189 lidia_error_handler("module", "ring_of multipliers::internal error::"
1190 "division by p unsuccesful");
1191 return order();
1192 }
1193 init.sto(i, j, q);
1194 }
1195 debug_handler_c("module",
1196 "in member - function ring_of_multipliers(...)", 3,
1197 std::cout << "MT is" << trans(init) << std::flush);
1198 return order(trans(init));
1199 }
1200 }
1201
1202
1203
1204 // Other functions:
invert(module & c,const module & a)1205 void invert(module &c, const module & a)
1206 {
1207 c.assign(a);
1208 c.invert();
1209 }
1210
1211
1212
inverse(const module & a)1213 module inverse(const module & a)
1214 {
1215 module c = a;
1216 c.invert();
1217 return c;
1218 }
1219
1220
1221
square(module & a,const module & b)1222 void square(module & a, const module & b)
1223 {
1224 debug_handler("modules",
1225 "in function square(a_n &, const a_n &)");
1226 multiply(a, b, b);
1227 }
1228
1229
1230
swap(module & a,module & b)1231 void swap(module & a, module & b)
1232 {
1233 swap (a.den, b.den);
1234 swap(a.base, b.base);
1235 nf_base * O = a.O;
1236 a.O = b.O;
1237 b.O = O;
1238 bool help = a.is_exp;
1239 a.is_exp = b.is_exp;
1240 b.is_exp = help;
1241 }
1242
1243
1244
1245 // random modules
randomize(const bigint & b)1246 void module::randomize(const bigint & b)
1247 {
1248 debug_handler("module", "in member-function "
1249 "randomize(const bigint &)");
1250 den.assign_one();
1251 base.set_no_of_columns(degree());
1252 base.set_modulus(0);
1253 bigint tmp;
1254 for (register lidia_size_t i = 0; i < degree(); i++) {
1255 tmp.assign(LiDIA::randomize(b));
1256 base.sto(i, i, tmp);
1257 if (!tmp.is_zero())
1258 for (register lidia_size_t j = i + 1; j < degree(); j++)
1259 base.sto(i, j, LiDIA::randomize(tmp));
1260 else
1261 for (register lidia_size_t j = i + 1; j < degree(); j++)
1262 base.sto(i, j, LiDIA::randomize(b));
1263 }
1264 add(den, LiDIA::randomize(b), 1);
1265 is_exp = false;
1266 base.image(base);
1267 normalize();
1268 }
1269
1270
1271
1272 // In-/Output:
operator <<(std::ostream & s,const module & a)1273 std::ostream& operator << (std::ostream & s, const module & a)
1274 {
1275 debug_handler("module", "in function "
1276 "std::ostream& operator << (std::ostream &, const module &)");
1277 s << a.z_basis();
1278 if (!(a.is_zero() || a.den.is_one()))
1279 s << " / " << a.den;
1280 return s;
1281 }
1282
1283
1284
operator >>(std::istream & s,module & a)1285 std::istream& operator >> (std::istream & s, module & a)
1286 {
1287 debug_handler("module", "in function "
1288 "std::istream& operator >> (std::istream &, module &)");
1289 bigint_matrix tmp;
1290 if (nf_base::current_base == nf_base::dummy_base) {
1291 lidia_error_handler ("module", "operator >>::No number_field or order!");
1292 return s;
1293 }
1294 if (a.O != nf_base::current_base) {
1295 a.O->dec_ref();
1296 a.O = nf_base::current_base;
1297 a.O->inc_ref();
1298 }
1299 s >> tmp;
1300 a.base.assign(bigmod_matrix(tmp, 0));
1301 a.is_exp = false;
1302 a.base.image(a.base);
1303 char c;
1304 do {
1305 s.get(c);
1306 } while (isspace(c) && c != '\n');
1307 if (c == '/') {
1308 s >> a.den;
1309 }
1310 else {
1311 a.den.assign_one();
1312 if (c != '\n' && c != '\r')
1313 s.putback(c);
1314 }
1315 a.normalize();
1316 return s;
1317 }
1318
1319
1320
1321 #ifdef LIDIA_NAMESPACE
1322 } // end of namespace LiDIA
1323 #endif
1324