1 /*
2 * Normaliz
3 * Copyright (C) 2007-2021 W. Bruns, B. Ichim, Ch. Soeger, U. v. d. Ohe
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * As an exception, when this program is distributed through (i) the App Store
18 * by Apple Inc.; (ii) the Mac App Store by Apple Inc.; or (iii) Google Play
19 * by Google Inc., then that store may impose any digital rights management,
20 * device limits and/or redistribution restrictions that are required by its
21 * terms of service.
22 */
23
24 #ifndef LIBNORMALIZ_INTEGER_H_
25 #define LIBNORMALIZ_INTEGER_H_
26
27 #include <list>
28 #include <vector>
29 #include <string>
30 #include <climits>
31 #include <cmath>
32 #include <iosfwd>
33
34 #include <libnormaliz/general.h>
35
36 // Integer should (may) support:
37 // Integer abs(Integer); here implemented as Iabs
38 // Integer min(Integer, Integer); here we use the template min in <algorithm>
39 // It provides abs, gcd and lcm
40 //---------------------------------------------------------------------------
41
42 namespace libnormaliz {
43
44 using std::cerr;
45 using std::endl;
46 using std::istream;
47 using std::ostream;
48 using std::ostringstream;
49 using std::string;
50 using std::stringstream;
51 using std::vector;
52 using std::ws;
53
54 //---------------------------------------------------------------------------
55 // Basic functions
56 //---------------------------------------------------------------------------
57
58 // returns the absolute value of a
59 template <typename Integer>
Iabs(const Integer & a)60 inline Integer Iabs(const Integer& a) {
61 return (a >= 0) ? (a) : Integer(-a);
62 }
63
64 // returns gcd of a and b, if one is 0 returns the other integer
65 template <typename Integer>
66 Integer gcd(const Integer& a, const Integer& b);
67 template <>
68 mpz_class gcd<mpz_class>(const mpz_class& a, const mpz_class& b);
69
70 // returns lcm of a and b, returns 0 if one is 0
71 template <typename Integer>
72 Integer lcm(const Integer& a, const Integer& b);
73 template <>
74 mpz_class lcm(const mpz_class& a, const mpz_class& b);
75
76 // integer division a/b. Returns quot and rem = minimal remainder <= |b|/2
77 template <typename Integer>
78 void minimal_remainder(const Integer& a, const Integer& b, Integer& quot, Integer& rem);
79
80 // extended Euclidean algorithm: d=ua+vb
81 template <typename Integer>
82 Integer ext_gcd(const Integer& a, const Integer& b, Integer& u, Integer& v);
83
84 // minimizes u and v and makes d >= 0.
85 template <typename Integer>
86 void sign_adjust_and_minimize(const Integer& a, const Integer& b, Integer& d, Integer& u, Integer& v);
87
88 // the following functions behave like the C++ floating point functions with the same name
89 mpz_class floor(const mpq_class& q);
90 mpz_class ceil(const mpq_class& q);
91 mpz_class round(const mpq_class& q);
92
93 //---------------------------------------------------------------------------
94 // Conversions and checks
95 //---------------------------------------------------------------------------
96
97 // convert val to ret
98 // does the conversion and returns false if it fails
99 bool try_convert(long& ret, const long long& val);
try_convert(long long & ret,const long & val)100 inline bool try_convert(long long& ret, const long& val) {
101 ret = val;
102 return true;
103 }
104 bool try_convert(long& ret, const mpz_class& val);
105 bool try_convert(long long& ret, const mpz_class& val);
try_convert(mpz_class & ret,const long & val)106 inline bool try_convert(mpz_class& ret, const long& val) {
107 ret = val;
108 return true;
109 }
110 bool try_convert(mpz_class& ret, const long long& val);
111
112 bool try_convert(nmz_float& ret, const long& val);
113 bool try_convert(nmz_float& ret, const long long& val);
114 bool try_convert(nmz_float& ret, const mpz_class& val);
115
116 bool try_convert(long& ret, const nmz_float& val);
117 bool try_convert(long long& ret, const nmz_float& val);
118 bool try_convert(mpz_class& ret, const nmz_float& val);
119
120 nmz_float mpq_to_nmz_float(const mpq_class& val);
121
122 #ifdef ENFNORMALIZ
123 bool try_convert(renf_elem_class& ret, const mpz_class& val);
124 bool try_convert(mpz_class& ret, const renf_elem_class& val);
125 bool try_convert(renf_elem_class& ret, const long long& val);
126 bool try_convert(long long& ret, const renf_elem_class& val);
127 bool try_convert(renf_elem_class& ret, const long& val);
128 bool try_convert(long& ret, const renf_elem_class& val);
129 bool try_convert(mpq_class& ret, const renf_elem_class& val);
130 bool try_convert(nmz_float& ret, const renf_elem_class& val);
131 #endif
132
133 // template for same type "conversion"
134 template <typename Type>
try_convert(Type & ret,const Type & val)135 inline bool try_convert(Type& ret, const Type& val) {
136 ret = val;
137 return true;
138 }
139
try_convert(nmz_float & ret,const nmz_float & val)140 inline bool try_convert(nmz_float& ret, const nmz_float& val) {
141 ret = val;
142 return true;
143 }
144
145 bool fits_long_range(long long a);
146
147 //--------------------------------------------------------------------
148 template <typename Integer>
using_GMP()149 inline bool using_GMP() {
150 return false;
151 }
152
153 template <>
154 inline bool using_GMP<mpz_class>() {
155 return true;
156 }
157
158 template <>
159 inline bool using_GMP<mpq_class>() {
160 return true;
161 }
162
163 template <typename Integer>
using_mpq_class()164 inline bool using_mpq_class() {
165 return false;
166 }
167
168 template <>
169 inline bool using_mpq_class<mpq_class>() {
170 return true;
171 }
172 //--------------------------------------------------------------------
173
174 template <typename Integer>
using_float()175 inline bool using_float() {
176 return false;
177 }
178
179 template <>
180 inline bool using_float<nmz_float>() {
181 return true;
182 }
183
184 //--------------------------------------------------------------------
185
186 template <typename Number>
using_renf()187 inline bool using_renf() {
188 return false;
189 }
190
191 #ifdef ENFNORMALIZ
192 template <>
193 inline bool using_renf<renf_elem_class>() {
194 return true;
195 }
196 #endif
197
198 //--------------------------------------------------------------------
199
200 // for the interpretation of a string as a decimal fraction or floating point number
201 mpq_class dec_fraction_to_mpq(std::string s);
202
203 //--------------------------------------------------------------------
204
205 template <typename Integer>
206 Integer int_max_value_dual();
207
208 template <typename Integer>
209 Integer int_max_value_primary();
210
211 //---------------------------------------------------------------------------
212
213 /*template<typename Integer>
214 inline bool is_scalar_zero(const Integer& m){
215 return m==0;
216 }
217
218 template<>
219 inline bool is_scalar_zero<nmz_float>(const nmz_float& m){
220 return (Iabs(m) < 1000000.0*nmz_epsilon);
221 }*/
222
223 template <typename Integer>
check_range(const Integer & m)224 inline bool check_range(const Integer& m) {
225 const Integer max_primary = int_max_value_primary<Integer>();
226 return (Iabs(m) <= max_primary);
227 }
228
229 template <>
230 inline bool check_range<mpz_class>(const mpz_class& m) {
231 return true;
232 }
233
234 template <>
235 inline bool check_range<nmz_float>(const nmz_float& m) {
236 return true;
237 }
238
239 template <>
240 inline bool check_range<mpq_class>(const mpq_class& m) {
241 return true;
242 }
243
244 #ifdef ENFNORMALIZ
245 template <>
246 inline bool check_range<renf_elem_class>(const renf_elem_class& m) {
247 return true;
248 }
249 #endif
250 //---------------------------------------------------------------------------
251
252 template <typename Integer>
253 void check_range_list(const std::list<std::vector<Integer> >& ll);
254
255 template <typename Integer>
256 class CandidateList;
257 template <typename Integer>
258 class Candidate;
259
260 template <typename Integer>
261 void check_range_list(const CandidateList<Integer>& ll);
262 template <typename Integer>
263 void check_range_list(const std::list<Candidate<Integer> >& ll);
264
265 //---------------------------------------------------------------------------
266 // String conversion functions
267 //---------------------------------------------------------------------------
268
269 // forward declaration to silence clang error:
270 // 'operator<<' should be declared prior to the call site or in the global namespace
271 template <typename T>
272 std::ostream& operator<<(std::ostream& out, const vector<T>& vec);
273
274 template <typename Integer>
toString(Integer a)275 string toString(Integer a) {
276 ostringstream ostream;
277 ostream << a;
278 return ostream.str();
279 }
280 template <>
toString(mpz_class a)281 inline string toString(mpz_class a) {
282 return a.get_str();
283 }
284 template <>
toString(mpq_class a)285 inline string toString(mpq_class a) {
286 return a.get_str();
287 }
288
289 //----------------------------------------------------------------------
290 // the next functions produce an integer quotient of absolute values and determine whether
291 // there is a remainder
292
293 bool int_quotient(long long& Quot, const mpz_class& Num, const mpz_class& Den);
294 bool int_quotient(long& Quot, const long& Num, const long& Den);
295 bool int_quotient(long long& Quot, const long long& Num, const long long& Den);
296 bool int_quotient(mpz_class& Quot, const mpz_class& Num, const mpz_class& Den);
297 template <typename IntegerRet>
298 bool int_quotient(IntegerRet& Quot, const nmz_float& Num, const nmz_float& Den);
299
300 // find the floor and ceol of Num/Den
301 template <typename IntegerRet, typename IntegerVal>
302 IntegerRet floor_quot(const IntegerVal Num, IntegerVal Den);
303
304 template <typename IntegerRet, typename IntegerVal>
305 IntegerRet ceil_quot(const IntegerVal Num, IntegerVal Den);
306
307 //---------------------------------------------------------------------------
308 template <typename Integer>
minimal_remainder(const Integer & a,const Integer & b,Integer & quot,Integer & rem)309 void minimal_remainder(const Integer& a, const Integer& b, Integer& quot, Integer& rem) {
310 quot = a / b;
311 rem = a - quot * b;
312 if (rem == 0)
313 return;
314 Integer test = 2 * Iabs(rem) - Iabs(b);
315 if (test > 0) {
316 if ((rem < 0 && b > 0) || (rem > 0 && b < 0)) {
317 rem += b;
318 quot--;
319 }
320 else {
321 rem -= b;
322 quot++;
323 }
324 }
325 if (test == 0 && rem < 0) {
326 rem = -rem;
327 if (b > 0)
328 quot--;
329 else
330 quot++;
331 }
332 }
333
334 template <typename Integer>
sign_adjust_and_minimize(const Integer & a,const Integer & b,Integer & d,Integer & u,Integer & v)335 void sign_adjust_and_minimize(const Integer& a, const Integer& b, Integer& d, Integer& u, Integer& v) {
336 if (d < 0) {
337 d = -d;
338 u = -u;
339 v = -v;
340 }
341 // cout << u << " " << v << endl;
342 if (b == 0)
343 return;
344
345 Integer sign = 1;
346 if (a < 0)
347 sign = -1;
348 Integer u1 = (sign * u) % (Iabs(b) / d);
349 if (u1 == 0)
350 u1 += Iabs(b) / d;
351 u = sign * u1;
352 v = (d - a * u) / b;
353 }
354
355 template <typename Integer>
ext_gcd(const Integer & a,const Integer & b,Integer & u,Integer & v)356 Integer ext_gcd(const Integer& a, const Integer& b, Integer& u, Integer& v) {
357 u = 1;
358 v = 0;
359 Integer d = a;
360 if (b == 0) {
361 sign_adjust_and_minimize(a, b, d, u, v);
362 return (d);
363 }
364 Integer v1 = 0;
365 Integer v3 = b;
366 Integer q, t1, t3;
367 while (v3 != 0) {
368 q = d / v3;
369 t3 = d - q * v3;
370 t1 = u - q * v1;
371 u = v1;
372 d = v3;
373 v1 = t1;
374 v3 = t3;
375 }
376 sign_adjust_and_minimize(a, b, d, u, v);
377 return (d);
378 }
379
380 template <typename Integer>
decimal_length(Integer a)381 size_t decimal_length(Integer a) {
382 ostringstream test;
383 test << a;
384 return test.str().size();
385 }
386
387 //---------------------------------------------------------------------------
388 // Special functions
389 //---------------------------------------------------------------------------
390
391 // return the number of decimals, needed to write the Integer a
392 template <typename Integer>
393 size_t decimal_length(Integer a);
394
395 template <typename Integer>
396 mpz_class nmz_factorial(Integer n);
397
398 //---------------------------------------------------------------------------
399 // Input
400 //---------------------------------------------------------------------------
401
mpq_read(istream & in)402 inline mpq_class mpq_read(istream& in) {
403 const string numeric = "+-0123456789/.e";
404 in >> std::ws;
405 string s;
406 char c;
407 bool is_float = false;
408 while (in.good()) {
409 c = in.peek();
410 size_t pos = numeric.find(c);
411 if (pos == string::npos)
412 break;
413 if (pos > 12)
414 is_float = true;
415 in >> c;
416 s += c;
417 }
418
419 if (s == "") {
420 string t;
421 t += c;
422 throw BadInputException("Empty number string preceding character " + t +
423 ". Most likely mismatch of amb_space and matrix format or forgotten keyword.");
424 }
425
426 // cout << "t " << s << " f " << is_float << endl;
427
428 if (s[0] == '+')
429 s = s.substr(1); // must suppress + sign for mpq_class
430
431 try {
432 if (!is_float) {
433 return mpq_class(s);
434 }
435 else
436 return dec_fraction_to_mpq(s);
437 } catch (const std::exception& e) {
438 cerr << e.what() << endl;
439 throw BadInputException("Illegal number string " + s + " in input, Exiting.");
440 }
441 }
442
443 // To be used in input.cpp
string2coeff(mpq_class & coeff,istream & in,const string & s)444 inline void string2coeff(mpq_class& coeff, istream& in, const string& s) { // in here superfluous parameter
445
446 stringstream sin(s);
447 coeff = mpq_read(sin);
448 // coeff=mpq_class(s);
449 }
450
451 // To be used from other sources
string2coeff(mpq_class & coeff,const string & s)452 inline void string2coeff(mpq_class& coeff, const string& s) {
453
454 // cout << "SSSSSS " << s << endl;
455
456 const string numeric = "+-0123456789/.e "; // must allow blank
457 for(auto& c: s){
458 size_t pos = numeric.find(c);
459 if(pos == string::npos)
460 throw BadInputException("Illegal character in numerical string");
461 }
462
463
464 stringstream sin(s);
465 coeff = mpq_read(sin);
466 // coeff=mpq_class(s);
467 }
468
read_number(istream & in,mpq_class & number)469 inline void read_number(istream& in, mpq_class& number) {
470 number = mpq_read(in);
471 }
472
read_number(istream & in,long & number)473 inline void read_number(istream& in, long& number) {
474 in >> number;
475 }
476
read_number(istream & in,long long & number)477 inline void read_number(istream& in, long long& number) {
478 in >> number;
479 }
480
read_number(istream & in,nmz_float & number)481 inline void read_number(istream& in, nmz_float& number) {
482 in >> number;
483 }
484
read_number(istream & in,mpz_class & number)485 inline void read_number(istream& in, mpz_class& number) {
486 in >> number;
487 }
488
489 #ifdef ENFNORMALIZ
490
string2coeff(renf_elem_class & coeff,istream & in,const string & s)491 inline void string2coeff(renf_elem_class& coeff, istream& in, const string& s) { // we need in to access the renf
492
493 try {
494 coeff = renf_elem_class(*renf_class::get_pword(in), s);
495 } catch (const std::exception& e) {
496 cerr << e.what() << endl;
497 throw BadInputException("Illegal number string " + s + " in input, Exiting.");
498 }
499 }
500
read_number(istream & in,renf_elem_class & number)501 inline void read_number(istream& in, renf_elem_class& number) {
502 // in >> number;
503
504 char c;
505
506 in >> ws;
507 c = in.peek();
508 if (c != '(' && c != '\'' && c != '\"') { // rational number
509 mpq_class rat = mpq_read(in);
510 number = renf_elem_class(rat);
511 return;
512 }
513
514 // now we have a proper field element
515
516 in >> c; // read (
517
518 string num_string;
519 bool skip = false;
520 while (in.good()) {
521 c = in.peek();
522 if (c == ')' || c == '\'' || c == '\"') {
523 in >> c;
524 break;
525 }
526 if (c == '~' || c == '=' || c == '[') // skip the approximation
527 skip = true;
528 in.get(c);
529 if (in.fail())
530 throw BadInputException("Error in reading number: field element not terminated");
531 if (!skip)
532 num_string += c;
533 }
534 string2coeff(number, in, num_string);
535 }
536 #endif
537
538 // formerly conver.h
539 // conversion for integers, throws ArithmeticException if conversion fails
540 template <typename ToType, typename FromType>
convert(ToType & ret,const FromType & val)541 inline void convert(ToType& ret, const FromType& val) {
542 if (!try_convert(ret, val)) {
543 throw ArithmeticException(val);
544 }
545 }
546
547 // conversion of vectors
548 template <typename ToType, typename FromType>
convert(vector<ToType> & ret_vect,const vector<FromType> & from_vect)549 inline void convert(vector<ToType>& ret_vect, const vector<FromType>& from_vect) {
550 size_t s = from_vect.size();
551 ret_vect.resize(s);
552 for (size_t i = 0; i < s; ++i)
553 convert(ret_vect[i], from_vect[i]);
554 }
555
556 // general conversion with return, throws ArithmeticException if conversion fails
557 template <typename ToType, typename FromType>
convertTo(const FromType & val)558 ToType convertTo(const FromType& val) {
559 ToType copy;
560 convert(copy, val);
561 return copy;
562 }
563
564
try_convert(mpz_class & ret,const mpq_class & val)565 inline bool try_convert(mpz_class& ret, const mpq_class& val) {
566 assert(false); // must never be used
567 return false;
568 }
569
try_convert(mpq_class & ret,const mpz_class & val)570 inline bool try_convert(mpq_class& ret, const mpz_class& val) {
571 assert(false); // must never be used
572 return false;
573 }
574
575 #ifdef ENFNORMALIZ
try_convert(renf_elem_class & ret,const mpz_class & val)576 inline bool try_convert(renf_elem_class& ret, const mpz_class& val) {
577 ret = val;
578 return true;
579 }
580
try_convert(mpz_class & ret,const renf_elem_class & val)581 inline bool try_convert(mpz_class& ret, const renf_elem_class& val) {
582 renf_elem_class help = val;
583 if (!help.is_integer())
584 throw ArithmeticException("field element cannot be converted to integer");
585 ret = help.num();
586 return true;
587 }
588
try_convert(renf_elem_class & ret,const long long & val)589 inline bool try_convert(renf_elem_class& ret, const long long& val) {
590 ret = convertTo<long>(val);
591 return true;
592 }
593
try_convert(long long & ret,const renf_elem_class & val)594 inline bool try_convert(long long& ret, const renf_elem_class& val) {
595 mpz_class bridge;
596 try_convert(bridge, val);
597 return try_convert(ret, bridge);
598 }
599
try_convert(renf_elem_class & ret,const long & val)600 inline bool try_convert(renf_elem_class& ret, const long& val) {
601 ret = val;
602 return true;
603 }
604
try_convert(long & ret,const renf_elem_class & val)605 inline bool try_convert(long& ret, const renf_elem_class& val) {
606 mpz_class bridge;
607 try_convert(bridge, val);
608 return try_convert(ret, bridge);
609 }
610
try_convert(mpq_class & ret,const renf_elem_class & val)611 inline bool try_convert(mpq_class& ret, const renf_elem_class& val) {
612 nmz_float ret_double = static_cast<double>(val);
613 ret = mpq_class(ret_double);
614 return true;
615 }
616
try_convert(nmz_float & ret,const renf_elem_class & val)617 inline bool try_convert(nmz_float& ret, const renf_elem_class& val) {
618 ret = static_cast<double>(val);
619 return true;
620 }
621 #endif
622
try_convert(long & ret,const long long & val)623 inline bool try_convert(long& ret, const long long& val) {
624 if (fits_long_range(val)) {
625 ret = val;
626 return true;
627 }
628 return false;
629 }
630
try_convert(long & ret,const mpz_class & val)631 inline bool try_convert(long& ret, const mpz_class& val) {
632 if (!val.fits_slong_p()) {
633 return false;
634 }
635 ret = val.get_si();
636 return true;
637 }
638
try_convert(long long & ret,const mpz_class & val)639 inline bool try_convert(long long& ret, const mpz_class& val) {
640 if (val.fits_slong_p()) {
641 ret = val.get_si();
642 return true;
643 }
644 if (sizeof(long long) == sizeof(long)) {
645 return false;
646 }
647 mpz_class quot;
648 ret = mpz_fdiv_q_ui(quot.get_mpz_t(), val.get_mpz_t(), LONG_MAX); // returns remainder
649 if (!quot.fits_slong_p()) {
650 return false;
651 }
652 ret += ((long long)quot.get_si()) * ((long long)LONG_MAX);
653 return true;
654 }
655
try_convert(mpz_class & ret,const long long & val)656 inline bool try_convert(mpz_class& ret, const long long& val) {
657 if (fits_long_range(val)) {
658 ret = mpz_class(long(val));
659 }
660 else {
661 ret = mpz_class(long(val % LONG_MAX)) + mpz_class(LONG_MAX) * mpz_class(long(val / LONG_MAX));
662 }
663 return true;
664 }
665
try_convert(float & ret,const mpz_class & val)666 inline bool try_convert(float& ret, const mpz_class& val) {
667 if (!val.fits_slong_p())
668 return false;
669 long dummy = convertTo<long>(val);
670 ret = (float)dummy;
671 return true;
672 }
673
fits_long_range(long long a)674 inline bool fits_long_range(long long a) {
675 return sizeof(long long) == sizeof(long) || (a <= LONG_MAX && a >= LONG_MIN);
676 }
677
try_convert(nmz_float & ret,const long & val)678 inline bool try_convert(nmz_float& ret, const long& val) {
679 ret = (nmz_float)val;
680 return true;
681 }
682
try_convert(nmz_float & ret,const mpz_class & val)683 inline bool try_convert(nmz_float& ret, const mpz_class& val) {
684 ret = val.get_d();
685 return true;
686 }
687
try_convert(mpz_class & ret,const nmz_float & val)688 inline bool try_convert(mpz_class& ret, const nmz_float& val) {
689 ret = mpz_class(val);
690 return true;
691 }
692
try_convert(nmz_float & ret,const long long & val)693 inline bool try_convert(nmz_float& ret, const long long& val) {
694 ret = (nmz_float)val;
695 return true;
696 }
697
try_convert(long & ret,const nmz_float & val)698 inline bool try_convert(long& ret, const nmz_float& val) {
699 mpz_class bridge;
700 if (!try_convert(bridge, val))
701 return false;
702 return try_convert(ret, bridge);
703 }
704
try_convert(long long & ret,const nmz_float & val)705 inline bool try_convert(long long& ret, const nmz_float& val) {
706 mpz_class bridge;
707 if (!try_convert(bridge, val))
708 return false;
709 return try_convert(ret, bridge);
710 }
711 //---------------------------------------------------------------------------
712
713 template <typename Integer>
gcd(const Integer & a,const Integer & b)714 Integer gcd(const Integer& a, const Integer& b) {
715 if (a == 0) {
716 return Iabs<Integer>(b);
717 }
718 if (b == 0) {
719 return Iabs<Integer>(a);
720 }
721 Integer q0, q1, r;
722 q0 = Iabs<Integer>(a);
723 r = Iabs<Integer>(b);
724 do {
725 q1 = r;
726 r = q0 % q1;
727 q0 = q1;
728 } while (r != 0);
729 return q1;
730 }
731
732 template <>
gcd(const nmz_float & a,const nmz_float & b)733 inline nmz_float gcd(const nmz_float& a, const nmz_float& b) {
734 if (a == 0 && b == 0)
735 return 0;
736 return 1.0;
737 }
738
739 template <>
gcd(const mpz_class & a,const mpz_class & b)740 inline mpz_class gcd(const mpz_class& a, const mpz_class& b) {
741 mpz_class g;
742 mpz_gcd(g.get_mpz_t(), a.get_mpz_t(), b.get_mpz_t());
743 return g;
744 }
745
746 #ifdef ENFNORMALIZ
747 template <>
gcd(const renf_elem_class & a,const renf_elem_class & b)748 inline renf_elem_class gcd(const renf_elem_class& a, const renf_elem_class& b) {
749 if (a == 0 && b == 0)
750 return 0;
751 return 1;
752 }
753 #endif
754
755 //---------------------------------------------------------------------------
756
757 template <typename Integer>
lcm(const Integer & a,const Integer & b)758 Integer lcm(const Integer& a, const Integer& b) {
759 if ((a == 0) || (b == 0)) {
760 return 0;
761 }
762 else
763 return Iabs<Integer>(a * b / gcd<Integer>(a, b));
764 }
765
766 template <>
767 inline mpz_class lcm<mpz_class>(const mpz_class& a, const mpz_class& b) {
768 mpz_class g;
769 mpz_lcm(g.get_mpz_t(), a.get_mpz_t(), b.get_mpz_t());
770 return g;
771 }
772
773 #ifdef ENFNORMALIZ
774 template <>
775 inline renf_elem_class lcm<renf_elem_class>(const renf_elem_class& a, const renf_elem_class& b) {
776 return 1;
777 }
778 #endif
779
780 //---------------------------------------------------------------------------
781
782 template <typename Integer>
int_max_value_dual()783 Integer int_max_value_dual() {
784 Integer k = sizeof(Integer) * 8 - 2; // number of bytes convetred to number of bits
785 Integer test = 1;
786 test = test << k; // 2^k
787 return test;
788 }
789
790 // bool int_max_value_dual_long_computed = false;
791
792 template <>
int_max_value_dual()793 inline long int_max_value_dual() {
794 static long max_value;
795
796 if (int_max_value_dual_long_computed)
797 return max_value;
798
799 long k = sizeof(long) * 8 - 2; // number of bytes convetred to number of bits
800 long test = 1;
801 test = test << k; // 2^k
802 // test=0; // 10000;
803 max_value = test;
804 int_max_value_dual_long_computed = true;
805 return test;
806 }
807
808 // bool int_max_value_dual_long_long_computed = false;
809
810 template <>
int_max_value_dual()811 inline long long int_max_value_dual() {
812 static long long max_value;
813
814 if (int_max_value_dual_long_long_computed)
815 return max_value;
816
817 long long k = sizeof(long long) * 8 - 2; // number of bytes convetred to number of bits
818 long long test = 1;
819 test = test << k; // 2^k
820 // test=0; // 10000;
821 max_value = test;
822 int_max_value_dual_long_long_computed = true;
823 return test;
824 }
825
826 //---------------------------------------------------------------------------
827
828 template <>
829 inline mpz_class int_max_value_dual<mpz_class>() {
830 assert(false);
831 return 0;
832 }
833
834 //---------------------------------------------------------------------------
835
836 template <typename Integer>
int_max_value_primary()837 Integer int_max_value_primary() {
838 Integer k = sizeof(Integer) * 8 - 12; // number of bytes convetred to number of bits
839 Integer test = 1;
840 test = test << k; // 2^k
841 // test=0; // 10000;
842 return test;
843 }
844
845 // bool int_max_value_primary_long_computed = false;
846
847 template <>
int_max_value_primary()848 inline long int_max_value_primary() {
849 static long max_value;
850
851 if (int_max_value_primary_long_computed)
852 return max_value;
853
854 long k = sizeof(long) * 8 - 12; // number of bytes convetred to number of bits
855 long test = 1;
856 test = test << k; // 2^k
857 // test=0; // 10000;
858 int_max_value_primary_long_computed = true;
859 max_value = test;
860 return test;
861 }
862
863 // bool int_max_value_primary_long_long_computed = false;
864
865 template <>
int_max_value_primary()866 inline long long int_max_value_primary() {
867 static long long max_value;
868
869 if (int_max_value_primary_long_long_computed)
870 return max_value;
871
872 long long k = sizeof(long long) * 8 - 12; // number of bytes convetred to number of bits
873 long long test = 1;
874 test = test << k; // 2^k
875 #ifdef NMZ_EXTENDED_TESTS
876 if(test_linear_algebra_GMP)
877 test=0;
878 #endif
879 max_value = test;
880 int_max_value_primary_long_long_computed = true;
881 return test;
882 }
883
884 //---------------------------------------------------------------------------
885
886 template <>
887 inline mpz_class int_max_value_primary<mpz_class>() {
888 assert(false);
889 return 0;
890 }
891
892 #ifdef ENFNORMALIZ
893 template <>
894 inline renf_elem_class int_max_value_primary<renf_elem_class>() {
895 assert(false);
896 return 0;
897 }
898 #endif
899
900 //---------------------------------------------------------------------------
901
902 template <typename Integer>
check_range_list(const CandidateList<Integer> & ll)903 void check_range_list(const CandidateList<Integer>& ll) {
904 check_range_list(ll.Candidates);
905 }
906
907 //---------------------------------------------------------------------------
908
909 template <typename Integer>
check_range_list(const std::list<Candidate<Integer>> & ll)910 void check_range_list(const std::list<Candidate<Integer> >& ll) {
911 if (using_GMP<Integer>())
912 return;
913
914 Integer test = int_max_value_dual<Integer>();
915 // cout << "test " << test << endl;
916
917 for (const auto& v : ll) {
918 for (size_t i = 0; i < v.values.size(); ++i)
919 if (Iabs(v.values[i]) >= test) {
920 // cout << v;
921 // cout << "i " << i << " " << Iabs(v[i]) << endl;
922 throw ArithmeticException("Vector entry out of range. Imminent danger of arithmetic overflow.");
923 }
924 }
925 }
926
927 //---------------------------------------------------------------------------
928
dec_fraction_to_mpq(string s)929 inline mpq_class dec_fraction_to_mpq(string s) {
930 size_t skip = 0; // skip leading spaces
931 for (; skip < s.size(); ++skip) {
932 if (!isspace(s[skip]))
933 break;
934 }
935 s = s.substr(skip);
936
937 mpz_class sign = 1;
938 if (s[0] == '+')
939 s = s.substr(1);
940 else if (s[0] == '-') {
941 s = s.substr(1);
942 sign = -1;
943 }
944
945 if (s[0] == '+' || s[0] == '-')
946 throw BadInputException("Error in decimal fraction " + s);
947
948 string int_string, frac_string, exp_string;
949 size_t frac_part_length = 0;
950 size_t pos_point = s.find(".");
951 size_t pos_E = s.find("e");
952 if (pos_point != string::npos) {
953 int_string = s.substr(0, pos_point);
954 if (pos_E != string::npos) {
955 frac_part_length = pos_E - (pos_point + 1);
956 }
957 else
958 frac_part_length = s.size() - (pos_point + 1);
959 frac_string = s.substr(pos_point + 1, frac_part_length);
960 if (frac_string[0] == '+' || frac_string[0] == '-')
961 throw BadInputException("Error in decimal fraction " + s);
962 }
963 else
964 int_string = s.substr(0, pos_E);
965 if (pos_E != string::npos)
966 exp_string = s.substr(pos_E + 1, s.size() - (pos_E + 1));
967
968 /* cout << "int " << int_string << endl;
969 cout << "frac " << frac_string << endl;
970 cout << "exp " << exp_string << endl; */
971
972 // remove leading 0 and +
973 if (int_string.size() > 0 && int_string[0] == '+')
974 int_string = int_string.substr(1);
975 while (int_string.size() > 0 && int_string[0] == '0')
976 int_string = int_string.substr(1);
977 while (frac_string.size() > 0 && frac_string[0] == '0')
978 frac_string = frac_string.substr(1);
979 if (exp_string.size() > 0 && exp_string[0] == '+')
980 exp_string = exp_string.substr(1);
981 bool exponent_could_be_zero=false;
982 while (exp_string.size() > 0 && exp_string[0] == '0'){
983 exponent_could_be_zero = true;
984 exp_string = exp_string.substr(1);
985 }
986
987 if(pos_E != string::npos && exp_string == "" && !exponent_could_be_zero)
988 throw BadInputException("No exponent following character e in floating point number");
989
990 mpq_class int_part, frac_part, exp_part;
991 if (!int_string.empty())
992 int_part = mpz_class(int_string);
993
994 if (pos_E == 0)
995 int_part = 1;
996
997 // cout << "int_part " << int_part << endl;
998
999 mpz_class den = 1;
1000 if (!frac_string.empty()) {
1001 frac_part = mpz_class(frac_string);
1002 for (size_t i = 0; i < frac_part_length; ++i)
1003 den *= 10;
1004 }
1005 // cout << "frac_part " << frac_part << endl;
1006 mpq_class result = int_part;
1007 if (frac_part != 0)
1008 result += frac_part / den;
1009 if (!exp_string.empty()) {
1010 mpz_class expo(exp_string); // we take mpz_class because it has better error checking
1011 // long expo=stol(exp_string);
1012 mpz_class abs_expo = Iabs(expo);
1013 mpz_class factor = 1;
1014 for (long i = 0; i < abs_expo; ++i)
1015 factor *= 10;
1016 if (expo >= 0)
1017 result *= factor;
1018 else
1019 result /= factor;
1020 }
1021 /* cout <<" result " << sign*result << endl;
1022 cout << "==========" << endl; */
1023 return sign * result;
1024 }
1025
1026 //----------------------------------------------------------------------
1027 // the next function produce an integer quotient and determine whether
1028 // there is a remainder
1029
int_quotient(long & Quot,const long & Num,const long & Den)1030 inline bool int_quotient(long& Quot, const long& Num, const long& Den) {
1031 Quot = Iabs(Num) / Iabs(Den);
1032 return Quot * Iabs(Den) != Iabs(Num);
1033 }
1034
int_quotient(long long & Quot,const long long & Num,const long long & Den)1035 inline bool int_quotient(long long& Quot, const long long& Num, const long long& Den) {
1036 Quot = Iabs(Num) / Iabs(Den);
1037 return Quot * Iabs(Den) != Iabs(Num);
1038 }
1039
int_quotient(mpz_class & Quot,const mpz_class & Num,const mpz_class & Den)1040 inline bool int_quotient(mpz_class& Quot, const mpz_class& Num, const mpz_class& Den) {
1041 Quot = Iabs(Num) / Iabs(Den);
1042 return Quot * Iabs(Den) != Iabs(Num);
1043 }
1044
int_quotient(long long & Quot,const mpz_class & Num,const mpz_class & Den)1045 inline bool int_quotient(long long& Quot, const mpz_class& Num, const mpz_class& Den) {
1046 mpz_class mpz_Quot = (Iabs(Num) / Iabs(Den));
1047 convert(Quot, mpz_Quot);
1048 return mpz_Quot * Iabs(Den) != Iabs(Num);
1049 }
1050
1051 template <typename IntegerRet>
int_quotient(IntegerRet & Quot,const nmz_float & Num,const nmz_float & Den)1052 inline bool int_quotient(IntegerRet& Quot, const nmz_float& Num, const nmz_float& Den) {
1053 nmz_float FloatQuot = Iabs(Num) / Iabs(Den); // cout << "FF " << FloatQuot << endl;
1054 nmz_float IntQuot = trunc(FloatQuot + nmz_epsilon); // cout << "II " << IntQuot << endl;
1055 Quot = convertTo<IntegerRet>(IntQuot); // cout << "QQ " << Quot << endl;
1056 return FloatQuot - IntQuot > nmz_epsilon;
1057 }
1058
1059
1060 template <typename IntegerRet, typename IntegerVal>
floor_quot(const IntegerVal Num,IntegerVal Den)1061 IntegerRet floor_quot(const IntegerVal Num, IntegerVal Den) {
1062 IntegerRet Quot;
1063 bool frac = int_quotient(Quot, Num, Den);
1064 if ((Num >= 0 && Den >= 0) || (Num < 0 && Den < 0)) {
1065 return Quot;
1066 }
1067 else {
1068 if (frac) {
1069 return -Quot - 1;
1070 }
1071 return -Quot;
1072 }
1073 }
1074
1075 template <typename IntegerRet, typename IntegerVal>
ceil_quot(const IntegerVal Num,IntegerVal Den)1076 IntegerRet ceil_quot(const IntegerVal Num, IntegerVal Den) {
1077 IntegerRet Quot;
1078 bool frac = int_quotient(Quot, Num, Den);
1079 if ((Num >= 0 && Den >= 0) || (Num < 0 && Den < 0)) {
1080 if (frac)
1081 return Quot + 1;
1082 return Quot;
1083 }
1084 else {
1085 return -Quot;
1086 }
1087 }
1088
1089 #ifdef ENFNORMALIZ
1090 template <>
floor_quot(const renf_elem_class Num,renf_elem_class Den)1091 inline mpz_class floor_quot(const renf_elem_class Num, renf_elem_class Den) {
1092 return floor(Num / Den);
1093 }
1094
1095 template <>
ceil_quot(const renf_elem_class Num,renf_elem_class Den)1096 inline mpz_class ceil_quot(const renf_elem_class Num, renf_elem_class Den) {
1097 return ceil(Num / Den);
1098 }
1099 #endif
1100
1101 //----------------------------------------------------------------------
1102
floor(const mpq_class & q)1103 inline mpz_class floor(const mpq_class& q) {
1104 mpz_class num = q.get_num();
1105 mpz_class den = q.get_den();
1106 mpz_class ent = num / den;
1107 if (num < 0 && den * ent != num)
1108 ent--;
1109 return ent;
1110 }
1111
ceil(const mpq_class & q)1112 inline mpz_class ceil(const mpq_class& q) {
1113 mpz_class num = q.get_num();
1114 mpz_class den = q.get_den();
1115 mpz_class ent = num / den;
1116 if (num > 0 && den * ent != num)
1117 ent++;
1118 return ent;
1119 }
1120
round(const mpq_class & q)1121 inline mpz_class round(const mpq_class& q) {
1122 mpq_class work;
1123 if (q >= 0) {
1124 work = q - mpq_class(1, 2);
1125 return ceil(work);
1126 }
1127 work = q + mpq_class(1, 2);
1128 return floor(work);
1129 }
1130
1131 template <typename Integer>
nmz_factorial(Integer n)1132 mpz_class nmz_factorial(Integer n) {
1133 assert(n >= 0);
1134 mpz_class f = 1;
1135 long nlong = convertTo<long>(n);
1136 for (long i = 1; i <= nlong; ++i)
1137 f *= i;
1138 return f;
1139 }
1140
1141
1142 template <typename Integer>
nmz_binomial(Integer n,Integer k)1143 mpz_class nmz_binomial(Integer n, Integer k) {
1144 if (k > n)
1145 return 0;
1146 return nmz_factorial(n) / nmz_factorial(k);
1147 }
1148
1149
mpq_to_nmz_float(const mpq_class & val)1150 inline nmz_float mpq_to_nmz_float(const mpq_class& val) {
1151 mpz_class bound = 1;
1152 for (size_t i = 0; i < 60; ++i)
1153 bound *= 10;
1154 mpz_class gmp_num = val.get_num(), gmp_den = val.get_den();
1155 while (Iabs(gmp_num) > bound && Iabs(gmp_den) > bound) {
1156 gmp_num /= 10;
1157 gmp_den /= 10;
1158 }
1159 nmz_float num, den;
1160 convert(num, gmp_num);
1161 convert(den, gmp_den);
1162 return num / den;
1163 }
1164
1165 template <typename Integer>
convertToLong(const Integer & val)1166 long convertToLong(const Integer& val){
1167
1168 long ret;
1169 try{
1170 ret = convertTo<long>(val);
1171 }
1172 catch (const ArithmeticException& e){
1173 throw LongException(val);
1174 }
1175
1176 return ret;
1177
1178 }
1179
1180 template <typename Integer>
convertToLongLong(const Integer & val)1181 long convertToLongLong(const Integer& val){
1182
1183 long ret;
1184 try{
1185 ret = convertTo<long long>(val);
1186 }
1187 catch (const ArithmeticException& e){
1188 throw LongLongException(val);
1189 }
1190
1191 return ret;
1192
1193 }
1194 } // namespace libnormaliz
1195
1196 //---------------------------------------------------------------------------
1197 #endif /* INTEGER_H_ */
1198 //---------------------------------------------------------------------------
1199