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