delpi  0.0.1
DElta-complete LP solver
Loading...
Searching...
No Matches
gmp.h
1
11#pragma once
12
13#include <gmp.h> // IWYU pragma: export
14#include <gmpxx.h> // IWYU pragma: export
15
16#include <cctype>
17#include <cmath>
18#include <compare> // NOLINT (build/include_order): Standard library.
19#include <cstring>
20#include <string>
21#include <string_view>
22#include <vector>
23
24template <>
25struct std::hash<mpq_class> {
26 size_t operator()(const mpq_class &val) const noexcept;
27};
28
29namespace delpi {
30
31std::strong_ordering operator<=>(const mpq_class &lhs, const mpq_t &rhs);
32std::strong_ordering operator<=>(const mpq_t &lhs, const mpq_class &rhs);
33
34namespace gmp {
35
36inline const mpq_class infinity{mpz_class{0}, 0};
37
38inline std::size_t complexity(const mpq_class &val) {
39 return mpz_size(val.get_num().get_mpz_t()) + mpz_size(val.get_den().get_mpz_t());
40}
41
49std::vector<mpq_class> ToMpqVector(const mpq_t *x, int size);
50
56mpz_class floor(const mpq_class &val);
62mpz_class ceil(const mpq_class &val);
69inline bool sign(const mpq_class &val) { return val.get_num() >= 0; }
77inline bool IsInfinity(const mpq_class &val) { return mpz_sgn(val.get_den().get_mpz_t()) == 0; }
78
106inline const mpq_t &ToMpq(const mpq_class &cla) { return *reinterpret_cast<const mpq_t *>(cla.get_mpq_t()); }
107
108inline mpq_t &ToMpq(mpq_class &cla) { return *reinterpret_cast<mpq_t *>(cla.get_mpq_t()); } // NOLINT
109
117inline const mpq_class &ToMpqClass(const mpq_t &mpq) { return reinterpret_cast<const mpq_class &>(mpq); }
118
127inline mpq_class &ToMpqClass(mpq_t &mpq) { return reinterpret_cast<mpq_class &>(mpq); } // NOLINT
128
135inline bool IsDigitOrSign(const char c) { return std::isdigit(c) || c == '+' || c == '-'; }
136
169inline mpq_class StringToMpq(std::string_view input) {
170 if (input.empty()) return mpq_class{0};
171 // Remove leading + and - sign
172 const bool is_negative = input[0] == '-';
173 if (is_negative || input[0] == '+') input.remove_prefix(1);
174 if (input == "inf") return {is_negative ? -1e100 : 1e100};
175
176 constexpr std::size_t max_size = 1 << 10;
177 char str_buffer[max_size + 1];
178
179 const std::size_t buffer_size = std::min(input.size(), max_size);
180 std::memcpy(str_buffer, input.data(), buffer_size);
181 str_buffer[buffer_size] = '\0';
182 std::string_view str{str_buffer, buffer_size};
183
184 // case 1: string is given in integer format
185 const size_t symbol_pos = str.find_first_of("/.Ee");
186 if (symbol_pos == std::string::npos) {
187 const size_t start_pos = str.find_first_not_of('0');
188 if (start_pos == std::string_view::npos) return {0};
189 str.remove_prefix(start_pos);
190 return is_negative ? -mpq_class{str.data()} : mpq_class{str.data()};
191 }
192
193 // case 2: string is given in nom/denom format
194 if (str[symbol_pos] == '/') {
195 mpq_class res{str.data()};
196 res.canonicalize();
197 return is_negative ? -res : res;
198 }
199
200 const size_t e_pos = str[symbol_pos] == 'e' || str[symbol_pos] == 'E' ? symbol_pos : str.find_first_of("Ee");
201 mpz_class mult{is_negative ? -1 : 1};
202 bool is_exp_positive = true;
203
204 // case 3a: string is given as base-10 decimal number (e)
205 if (e_pos != std::string::npos) {
206 const long exponent = std::stol(str.data() + e_pos + 1); // NOLINT(runtime/int)
207 is_exp_positive = exponent >= 0;
208 mult = 10;
209 mpz_pow_ui(mult.get_mpz_t(), mult.get_mpz_t(), std::abs(exponent));
210 if (is_negative) mult = -mult;
211 // Remove the exponent
212 str = str.substr(0, e_pos);
213
214 if (str.empty()) return is_exp_positive ? mpq_class{mult} : is_negative ? mpq_class{-1, -mult} : mpq_class{1, mult};
215 }
216
217 const size_t len = str.length();
218
219 // case 3b: string does not contain a . , only an exponent E
220 if (str[symbol_pos] == 'e' || str[symbol_pos] == 'E') {
221 str_buffer[len] = '\0';
222 const mpq_class res{str.data(), 10};
223 return is_exp_positive ? mpq_class{res * mult} : mpq_class{res / mult};
224 }
225
226 const size_t &dot_pos = symbol_pos;
227
228 // case 3c: string contains a .
229 size_t start_pos = str.find_first_not_of('0');
230 size_t digits;
231
232 // case 4a: string starts with a . or the numbers before the . are all 0
233 if (start_pos == dot_pos) {
234 start_pos = str.find_first_not_of('0', dot_pos + 1);
235 // case 5: string contains only a .
236 if (start_pos == std::string_view::npos) {
237 return {0};
238 } else {
239 digits = len - start_pos;
240 }
241 } else { // case 4b: string does not start with a . and the numbers before the . are not all 0
242 digits = len - start_pos - 1;
243 }
244
245 const size_t n_decimals = len - dot_pos - 1;
246 char str_number[max_size * 2 + 4];
247
248 if (digits > n_decimals) {
249 memcpy(str_number, str.data() + start_pos, digits - n_decimals);
250 memcpy(str_number + dot_pos, str.data() + dot_pos + 1, n_decimals);
251 } else {
252 memcpy(str_number, str.data() + start_pos, n_decimals);
253 }
254
255 str_number[digits] = '/';
256 str_number[digits + 1] = '1';
257 memset(str_number + digits + 2, '0', n_decimals);
258 str_number[digits + 2 + n_decimals] = '\0';
259
260 mpq_class res{str_number, 10};
261 res.canonicalize();
262 return is_exp_positive ? mpq_class{res * mult} : res / mult;
263}
264
265} // namespace gmp
266
267} // namespace delpi
268
269#ifdef DELPI_INCLUDE_FMT
270
271#include "delpi/util/logging.h"
272
273OSTREAM_FORMATTER(mpq_class)
274
275#endif
Global namespace for the delpi library.
size_t operator()(const mpq_class &val) const noexcept
Hash a gmp rational.
Definition gmp.cpp:36