LAL: Linear Arrangement Library 23.01.00
A library focused on algorithms on linear arrangements of graphs.
Loading...
Searching...
No Matches
rational.hpp
1/*********************************************************************
2 *
3 * Linear Arrangement Library - A library that implements a collection
4 * algorithms for linear arrangments of graphs.
5 *
6 * Copyright (C) 2019 - 2023
7 *
8 * This file is part of Linear Arrangement Library. The full code is available
9 * at:
10 * https://github.com/LAL-project/linear-arrangement-library.git
11 *
12 * Linear Arrangement Library is free software: you can redistribute it
13 * and/or modify it under the terms of the GNU Affero General Public License
14 * as published by the Free Software Foundation, either version 3 of the
15 * License, or (at your option) any later version.
16 *
17 * Linear Arrangement Library is distributed in the hope that it will be
18 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Affero General Public License for more details.
21 *
22 * You should have received a copy of the GNU Affero General Public License
23 * along with Linear Arrangement Library. If not, see <http://www.gnu.org/licenses/>.
24 *
25 * Contact:
26 *
27 * LluĂ­s Alemany Puig (lalemany@cs.upc.edu)
28 * LARCA (Laboratory for Relational Algorithmics, Complexity and Learning)
29 * CQL (Complexity and Quantitative Linguistics Lab)
30 * Jordi Girona St 1-3, Campus Nord UPC, 08034 Barcelona. CATALONIA, SPAIN
31 * Webpage: https://cqllab.upc.edu/people/lalemany/
32 *
33 * Ramon Ferrer i Cancho (rferrericancho@cs.upc.edu)
34 * LARCA (Laboratory for Relational Algorithmics, Complexity and Learning)
35 * CQL (Complexity and Quantitative Linguistics Lab)
36 * Office S124, Omega building
37 * Jordi Girona St 1-3, Campus Nord UPC, 08034 Barcelona. CATALONIA, SPAIN
38 * Webpage: https://cqllab.upc.edu/people/rferrericancho/
39 *
40 ********************************************************************/
41
42#pragma once
43
44// C includes
45#include <gmp.h>
46
47// C++ includes
48#include <cstdint>
49#include <string>
50
51// lal includes
52#include <lal/numeric/integer.hpp>
53
54namespace lal {
55namespace numeric {
56
63class rational {
64public:
65 /* CONSTRUCTORS */
66
68 rational() noexcept { mpq_init(m_val); }
74 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
75 rational(T n, uint64_t d = 1) noexcept
76 { mpq_init(m_val); set_number(n, d); }
82 rational(const integer& n, const integer& d = 1) noexcept
83 { mpq_init(m_val); set_integer(n, d); }
88 rational(const std::string& s) noexcept
89 { mpq_init(m_val); set_str(s); }
94 rational(const rational& r) noexcept
95 { mpq_init(m_val); mpq_set(m_val, r.m_val); }
96#ifndef SWIG
101 rational(integer&& i) noexcept {
102 // move i's contents into numerator
103 m_val[0]._mp_num = *i.m_val;
104 // set the denominator to 1
105 mpz_init_set_ui(&m_val[0]._mp_den, 1);
106 // we must canonicalize
107 mpq_canonicalize(m_val);
108
109 // invalidate i's contents
110 i.m_val->_mp_alloc = 0;
111 i.m_val->_mp_size = 0;
112 i.m_val->_mp_d = nullptr;
113 i.m_initialized = false;
114 }
121 rational(integer&& n, integer&& d) noexcept {
122 // move n's contents into numerator
123 m_val[0]._mp_num = *n.m_val;
124 // move d's contents into denominator
125 m_val[0]._mp_den = *d.m_val;
126 // we must canonicalize
127 mpq_canonicalize(m_val);
128
129 // invalidate n's contents
130 n.m_val->_mp_alloc = 0;
131 n.m_val->_mp_size = 0;
132 n.m_val->_mp_d = nullptr;
133 n.m_initialized = false;
134
135 // invalidate d's contents
136 d.m_val->_mp_alloc = 0;
137 d.m_val->_mp_size = 0;
138 d.m_val->_mp_d = nullptr;
139 d.m_initialized = false;
140 }
146 rational(rational&& r) noexcept {
147 *m_val = *r.m_val;
148
149 // invalidate r's contents
150 r.m_val->_mp_num._mp_alloc = 0;
151 r.m_val->_mp_num._mp_size = 0;
152 r.m_val->_mp_num._mp_d = nullptr;
153 r.m_val->_mp_den._mp_alloc = 0;
154 r.m_val->_mp_den._mp_size = 0;
155 r.m_val->_mp_den._mp_d = nullptr;
156 r.m_initialized = false;
157 }
158#endif
160 ~rational() noexcept { mpq_clear(m_val); }
161
162 /* SETTERS */
163
169 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
170 void set_number(T n, uint64_t d = 1) noexcept {
171 if (not is_initialized()) { mpq_init(m_val); }
172 if constexpr (std::is_signed_v<T>) { mpq_set_si(m_val, n, d); }
173 else { mpq_set_ui(m_val, n, d); }
174 mpq_canonicalize(m_val);
175 m_initialized = true;
176 }
181 void set_str(const std::string& s) noexcept {
182 if (not is_initialized()) { mpq_init(m_val); }
183 mpq_set_str(m_val, s.c_str(), 10);
184 mpq_canonicalize(m_val);
185 m_initialized = true;
186 }
192 void set_integer(const integer& n, const integer& d) noexcept {
193 if (not is_initialized()) { mpq_init(m_val); }
194 mpq_set_num(m_val, n.get_raw_value());
195 mpq_set_den(m_val, d.get_raw_value());
196 mpq_canonicalize(m_val);
197 m_initialized = true;
198 }
203 void set_rational(const rational& r) noexcept {
204 if (not is_initialized()) { mpq_init(m_val); }
205 mpq_set(m_val, r.m_val);
206 }
207
214 void invert() noexcept { mpq_inv(m_val, m_val); }
215
216 /* OPERATORS */
217
218 // -- ASSIGNMENT
219
224 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
225 rational& operator= (T i) noexcept
226 { set_number(i); return *this; }
231 rational& operator= (const std::string& s) noexcept
232 { set_str(s); return *this; }
237 rational& operator= (const integer& i) noexcept
238 { set_integer(i, 1); return *this; }
243 rational& operator= (const rational& r) noexcept
244 { set_rational(r); return *this; }
245#ifndef SWIG
251 rational& operator= (integer&& i) noexcept {
252 // clear this's contents
253 mpq_clear(m_val);
254 m_initialized = true;
255
256 // move i's contents into numerator
257 m_val[0]._mp_num = *i.m_val;
258 // set the denominator to 1
259 mpz_init_set_ui(&m_val[0]._mp_den, 1);
260 // we must canonicalize
261 mpq_canonicalize(m_val);
262
263 // invalidate i's contents
264 i.m_val->_mp_alloc = 0;
265 i.m_val->_mp_size = 0;
266 i.m_val->_mp_d = nullptr;
267 i.m_initialized = false;
268
269 return *this;
270 }
276 rational& operator= (rational&& r) noexcept {
277 // clear this's contents
278 mpq_clear(m_val);
279 m_initialized = true;
280
281 // move r's contents into this's
282 *m_val = *r.m_val;
283
284 // invalidate r's contents
285 r.m_val->_mp_num._mp_alloc = 0;
286 r.m_val->_mp_num._mp_size = 0;
287 r.m_val->_mp_num._mp_d = nullptr;
288 r.m_val->_mp_den._mp_alloc = 0;
289 r.m_val->_mp_den._mp_size = 0;
290 r.m_val->_mp_den._mp_d = nullptr;
291 r.m_initialized = false;
292
293 return *this;
294 }
295#endif
296
297 // -- EQUALITY
298
303 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
304 bool operator== (T i) const noexcept {
305 return
306 (std::is_signed_v<T> ? mpq_cmp_si(m_val, i, 1) : mpq_cmp_ui(m_val, i, 1)) == 0;
307 }
308#ifndef SWIG
314 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
315 friend bool operator== (T i, const rational& r) noexcept
316 { return r == i; }
317#endif
322 bool operator== (const integer& i) const noexcept
323 { rational r(i); return mpq_equal(m_val, r.m_val); }
324#ifndef SWIG
330 friend bool operator== (const integer& i, const rational& r) noexcept
331 { return r == i; }
332#endif
337 bool operator== (const rational& r) const noexcept {
338 // this function returns non-zero if parameters are equal!
339 return mpq_equal(m_val, r.m_val);
340 }
341
342 // -- NON-EQUALITY
343
348 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
349 bool operator!= (T i) const noexcept
350 { return not (*this == i); }
351#ifndef SWIG
357 friend bool operator!= (int64_t i, const rational& r) noexcept
358 { return r != i; }
359#endif
364 bool operator!= (const integer& i) const noexcept
365 { return not (*this == i); }
366#ifndef SWIG
372 friend bool operator!= (const integer& i, const rational& r) noexcept
373 { return r != i; }
374#endif
379 bool operator!= (const rational& r) const noexcept
380 { return not (*this == r); }
381
382 // -- LESS THAN
383
388 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
389 bool operator< (T i) const noexcept {
390 return
391 (std::is_signed_v<T> ? mpq_cmp_si(m_val, i, 1) : mpq_cmp_ui(m_val, i, 1)) < 0;
392 }
393#ifndef SWIG
399 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
400 friend bool operator< (T i, const rational& r) noexcept
401 { return r > i; }
402#endif
407 bool operator< (const integer& i) const noexcept
408 { rational r(i); return mpq_cmp(m_val, r.m_val) < 0; }
409#ifndef SWIG
415 friend bool operator< (const integer& i, const rational& r) noexcept
416 { return r > i; }
417#endif
422 bool operator< (const rational& r) const noexcept
423 { return mpq_cmp(m_val, r.m_val) < 0; }
424
425 // -- LESS THAN OR EQUAL TO
426
431 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
432 bool operator<= (T i) const noexcept {
433 return
434 (std::is_signed_v<T> ? mpq_cmp_si(m_val, i, 1) : mpq_cmp_ui(m_val, i, 1)) <= 0;
435 }
436#ifndef SWIG
442 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
443 friend bool operator<= (T i, const rational& r) noexcept
444 { return r >= i; }
445#endif
450 bool operator<= (const integer& i) const noexcept
451 { rational r(i); return mpq_cmp(m_val, r.m_val) <= 0; }
452#ifndef SWIG
458 friend bool operator<= (const integer& i, const rational& r) noexcept
459 { return r >= i; }
460#endif
465 bool operator<= (const rational& r) const noexcept
466 { return mpq_cmp(m_val, r.m_val) <= 0; }
467
468 // -- GREATER THAN
469
474 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
475 bool operator> (T i) const noexcept {
476 return
477 (std::is_signed_v<T> ? mpq_cmp_si(m_val, i, 1) : mpq_cmp_ui(m_val, i, 1)) > 0;
478 }
479#ifndef SWIG
485 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
486 friend bool operator> (T i, const rational& r) noexcept
487 { return r < i; }
488#endif
493 bool operator> (const integer& i) const noexcept
494 { rational r(i); return mpq_cmp(m_val, r.m_val) > 0; }
495#ifndef SWIG
501 friend bool operator> (const integer& i, const rational& r) noexcept
502 { return r < i; }
503#endif
508 bool operator> (const rational& r) const noexcept
509 { return mpq_cmp(m_val, r.m_val) > 0; }
510
511 // -- GREATER THAN OR EQUAL TO
512
517 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
518 bool operator>= (T i) const noexcept {
519 return
520 (std::is_signed_v<T> ? mpq_cmp_si(m_val, i, 1) : mpq_cmp_ui(m_val, i, 1)) >= 0;
521 }
522#ifndef SWIG
528 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
529 friend bool operator>= (T i, const rational& r) noexcept
530 { return r <= i; }
531#endif
536 bool operator>= (const integer& i) const noexcept
537 { rational r(i); return mpq_cmp(m_val, r.m_val) >= 0; }
538#ifndef SWIG
544 friend bool operator>= (const integer& i, const rational& r) noexcept
545 { return r <= i; }
546#endif
551 bool operator>= (const rational& r) const noexcept
552 { return mpq_cmp(m_val, r.m_val) >= 0; }
553
554 // -- ADDITION
555
560 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
561 rational operator+ (T i) const noexcept
562 { rational r(*this); r += i; return r; }
563#ifndef SWIG
569 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
570 friend rational operator+ (T i, const rational& r) noexcept
571 { return r + i; }
572#endif
577 rational operator+ (const integer& i) const noexcept
578 { rational r(*this); r += i; return r; }
579#ifndef SWIG
585 friend rational operator+ (const integer& i, const rational& r) noexcept
586 { return r + i; }
587#endif
592 rational operator+ (const rational& r) const noexcept
593 { rational k(*this); k += r; return k; }
594
599 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
600 rational& operator+= (T i) noexcept
601 { rational r(i); mpq_add(m_val, m_val, r.m_val); return *this; }
606 rational& operator+= (const integer& i) noexcept
607 { rational r(i); mpq_add(m_val, m_val, r.m_val); return *this; }
612 rational& operator+= (const rational& r) noexcept
613 { mpq_add(m_val, m_val, r.m_val); return *this; }
614
615 // -- SUBSTRACTION
616
618 rational operator- () const noexcept
619 { rational r(*this); mpq_neg(r.m_val, r.m_val); return r; }
624 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
625 rational operator- (T i) const noexcept
626 { rational r(*this); r -= i; return r; }
627#ifndef SWIG
633 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
634 friend rational operator- (T i, const rational& r) noexcept
635 { return -r + i; }
636#endif
641 rational operator- (const integer& i) const noexcept
642 { rational r(*this); r -= i; return r; }
643#ifndef SWIG
649 friend rational operator- (const integer& i, const rational& r) noexcept
650 { return -r + i; }
651#endif
656 rational operator- (const rational& r) const noexcept
657 { rational k(*this); k -= r; return k; }
658
663 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
664 rational& operator-= (T i) noexcept
665 { rational r(i); mpq_sub(m_val, m_val, r.m_val); return *this; }
670 rational& operator-= (const integer& i) noexcept
671 { rational r(i); mpq_sub(m_val, m_val, r.m_val); return *this; }
676 rational& operator-= (const rational& r) noexcept
677 { mpq_sub(m_val, m_val, r.m_val); return *this; }
678
679 // -- MULTIPLICATION
680
685 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
686 rational operator* (T i) const noexcept
687 { rational r(*this); r *= i; return r; }
688#ifndef SWIG
694 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
695 friend rational operator* (T i, const rational& r) noexcept
696 { return r*i; }
697#endif
702 rational operator* (const integer& i) const noexcept
703 { rational r(*this); r *= i; return r; }
704#ifndef SWIG
710 friend rational operator* (const integer& i, const rational& r) noexcept
711 { return r*i; }
712#endif
717 rational operator* (const rational& r) const noexcept
718 { rational k(*this); k *= r; return k; }
719
724 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
725 rational& operator*= (T i) noexcept
726 { rational r(i); mpq_mul(m_val, m_val, r.m_val); return *this; }
731 rational& operator*= (const integer& i) noexcept
732 { rational r(i); mpq_mul(m_val, m_val, r.m_val); return *this; }
737 rational& operator*= (const rational& r) noexcept
738 { mpq_mul(m_val, m_val, r.m_val); return *this; }
739
740 // -- DIVISION
741
746 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
747 rational operator/ (T i) const noexcept
748 { rational r(*this); r /= i; return r; }
749#ifndef SWIG
755 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
756 friend rational operator/ (T i, const rational& r) noexcept
757 { rational inv(r); inv.invert(); return inv*i; }
758#endif
759
764 rational operator/ (const integer& i) const noexcept
765 { rational r(*this); r /= i; return r; }
770 rational operator/ (const rational& r) const noexcept
771 { rational k(*this); k /= r; return k; }
772
777 template <typename T,std::enable_if_t<std::is_integral_v<T>, bool> = true>
778 rational& operator/= (T i) noexcept {
779 integer I(i); *this /= I; return *this;
780 }
785 rational& operator/= (const integer& i) noexcept;
790 rational& operator/= (const rational& r) noexcept;
791
792 // -- EXPONENTIATION
793
798 rational power(uint64_t i) const noexcept;
803 rational power(const integer& i) const noexcept;
804
809 rational& powt(uint64_t i) noexcept;
814 rational& powt(const integer& i) noexcept;
815
816 /* GETTERS */
817
819 bool is_initialized() const noexcept { return m_initialized; }
821 int64_t get_sign() const noexcept { return mpq_sgn(m_val); }
822
824 std::size_t bytes() const noexcept;
825
826 /* CONVERTERS */
827
835 integer to_integer() const noexcept {
836 integer i;
837 as_integer(i);
838 return i;
839 }
847 void as_integer(integer& i) const noexcept;
848
850 double to_double() const noexcept { return mpq_get_d(m_val); }
852 void as_double(double& d) const noexcept { d = mpq_get_d(m_val); }
853
855 std::string to_string() const noexcept {
856 std::string k;
857 as_string(k);
858 return k;
859 }
861 void as_string(std::string& s) const noexcept {
862 char *buf = nullptr;
863 buf = mpq_get_str(buf, 10, m_val);
864 s = std::string(buf);
865 free(buf);
866 }
867
869 integer get_numerator() const noexcept {
870 mpz_t numerator;
871 mpz_init(numerator);
872 mpq_get_num(numerator, m_val);
873 return integer(std::move(numerator));
874 }
875
877 integer get_denominator() const noexcept {
878 mpz_t denominator;
879 mpz_init(denominator);
880 mpq_get_den(denominator, m_val);
881 return integer(std::move(denominator));
882 }
883
884 /* OTHERS */
885
895 void swap(rational& r) noexcept { mpq_swap(m_val, r.m_val); }
896
897#ifndef SWIG
903 friend void swap(rational& r1, rational& r2) noexcept { r1.swap(r2); }
904#endif
905
906private:
908 mpq_t m_val;
910 bool m_initialized = true;
911};
912
913} // -- namespace numeric
914} // -- namespace lal
Arbitrary precision integer.
Definition: integer.hpp:60
Exact rational number.
Definition: rational.hpp:63
rational(integer &&n, integer &&d) noexcept
Move constructor with numerator and denominator.
Definition: rational.hpp:121
rational power(const integer &i) const noexcept
Exponentiation operator.
void swap(rational &r) noexcept
Swaps the value of this rational with rational r's value.
Definition: rational.hpp:895
void set_str(const std::string &s) noexcept
Overwrites the value in the string s.
Definition: rational.hpp:181
bool is_initialized() const noexcept
Returns whether this object is initialised or not.
Definition: rational.hpp:819
std::string to_string() const noexcept
Converts this integer to a string.
Definition: rational.hpp:855
rational & operator+=(T i) noexcept
Addition operator.
Definition: rational.hpp:600
void set_integer(const integer &n, const integer &d) noexcept
Overwrites the value of this rational with the value .
Definition: rational.hpp:192
friend bool operator==(T i, const rational &r) noexcept
Equality operator.
Definition: rational.hpp:315
rational(integer &&i) noexcept
Move constructor.
Definition: rational.hpp:101
void as_double(double &d) const noexcept
Converts this rational to a double-precision floating-point value.
Definition: rational.hpp:852
friend bool operator<(T i, const rational &r) noexcept
Less than operator.
Definition: rational.hpp:400
rational(const std::string &s) noexcept
Constructor with string.
Definition: rational.hpp:88
void as_string(std::string &s) const noexcept
Converts this integer to a string.
Definition: rational.hpp:861
rational & operator-=(T i) noexcept
Substraction operator.
Definition: rational.hpp:664
rational(const rational &r) noexcept
Copy constructor.
Definition: rational.hpp:94
rational & powt(const integer &i) noexcept
Exponentiation operator.
rational operator-() const noexcept
Substraction unary operator.
Definition: rational.hpp:618
rational() noexcept
Empty constructor.
Definition: rational.hpp:68
void as_integer(integer &i) const noexcept
Converts this rational to an integer value.
void set_rational(const rational &r) noexcept
Overwrites the value of this rational with the value .
Definition: rational.hpp:203
rational & operator/=(T i) noexcept
Division operator.
Definition: rational.hpp:778
rational(T n, uint64_t d=1) noexcept
Constructor with numerator and denominator.
Definition: rational.hpp:75
friend bool operator!=(int64_t i, const rational &r) noexcept
Non-equality operator.
Definition: rational.hpp:357
rational & operator*=(T i) noexcept
Multiplication operator.
Definition: rational.hpp:725
friend rational operator*(T i, const rational &r) noexcept
Multiplication operator.
Definition: rational.hpp:695
friend bool operator>=(T i, const rational &r) noexcept
Greater than or equal to operator.
Definition: rational.hpp:529
integer get_denominator() const noexcept
Returns the denominator of this rational number.
Definition: rational.hpp:877
rational power(uint64_t i) const noexcept
Exponentiation operator.
friend rational operator/(T i, const rational &r) noexcept
Division operator.
Definition: rational.hpp:756
bool m_initialized
Is this rational initialised?
Definition: rational.hpp:910
friend rational operator+(T i, const rational &r) noexcept
Addition operator.
Definition: rational.hpp:570
integer to_integer() const noexcept
Converts this rational to an integer value.
Definition: rational.hpp:835
rational(rational &&r) noexcept
Move constructor.
Definition: rational.hpp:146
rational & powt(uint64_t i) noexcept
Exponentiation operator.
void invert() noexcept
Changes numerator and denominator.
Definition: rational.hpp:214
friend void swap(rational &r1, rational &r2) noexcept
Swaps two rationals.
Definition: rational.hpp:903
std::size_t bytes() const noexcept
Returns the amount of bytes this integer occupies.
double to_double() const noexcept
Converts this rational to a double-precision floating-point value.
Definition: rational.hpp:850
void set_number(T n, uint64_t d=1) noexcept
Overwrites the value of this rational with .
Definition: rational.hpp:170
rational(const integer &n, const integer &d=1) noexcept
Constructor with numerator and denominator.
Definition: rational.hpp:82
integer get_numerator() const noexcept
Returns the numerator of this rational number.
Definition: rational.hpp:869
friend bool operator>(T i, const rational &r) noexcept
Greater than operator.
Definition: rational.hpp:486
int64_t get_sign() const noexcept
Returns the sign of this rational.
Definition: rational.hpp:821
~rational() noexcept
Destructor.
Definition: rational.hpp:160
rational & operator=(T i) noexcept
Assignment operator.
Definition: rational.hpp:225
friend bool operator<=(T i, const rational &r) noexcept
Less than or equal to operator.
Definition: rational.hpp:443
mpq_t m_val
Structure from GMP storing the rational's value.
Definition: rational.hpp:908
Main namespace of the library.
Definition: basic_types.hpp:50