dlinear  0.0.1
Delta-complete SMT solver for linear programming
Loading...
Searching...
No Matches
libgmp.h
1
12#pragma once
13
14#include <gmp.h> // IWYU pragma: export
15#include <gmpxx.h> // IWYU pragma: export
16
17#include <algorithm>
18#include <cctype>
19#include <cmath>
20#include <cstring>
21#include <string>
22#include <string_view>
23
24namespace std {
25
26template <>
27struct hash<mpq_class> {
28 size_t operator()(const mpq_class &val) const;
29};
30} // namespace std
31
32namespace dlinear {
33
34std::strong_ordering operator<=>(const mpq_class &lhs, const mpq_t &rhs);
35std::strong_ordering operator<=>(const mpq_t &lhs, const mpq_class &rhs);
36
37namespace gmp {
38
44mpz_class floor(const mpq_class &val);
50mpz_class ceil(const mpq_class &val);
51
81inline const mpq_t &ToMpq(const mpq_class &cla) { return *reinterpret_cast<const mpq_t *>(cla.get_mpq_t()); }
82
83inline mpq_t &ToMpq(mpq_class &cla) { return *reinterpret_cast<mpq_t *>(cla.get_mpq_t()); } // NOLINT
84
93inline const mpq_class &ToMpqClass(const mpq_t &mpq) { return reinterpret_cast<const mpq_class &>(mpq); }
94
103inline mpq_class &ToMpqClass(mpq_t &mpq) { return reinterpret_cast<mpq_class &>(mpq); } // NOLINT
104
111inline bool IsDigitOrSign(char c) { return std::isdigit(c) || c == '+' || c == '-'; }
112
143inline mpq_class StringToMpq(std::string_view str) {
144 // Remove leading + and - sign
145 const bool is_negative = str[0] == '-';
146 if (is_negative || str[0] == '+') str.remove_prefix(1);
147 if (str == "inf") return {1e100};
148 if (str == "-inf") return {-1e100};
149
150 // case 1: string is given in integer format
151 const size_t symbol_pos = str.find_first_of("/.Ee");
152 if (symbol_pos == std::string::npos) {
153 const size_t start_pos = str.find_first_not_of('0', str[0] == '+' ? 1 : 0);
154 if (start_pos == std::string_view::npos) return {0};
155 // DLINEAR_ASSERT_FMT(std::all_of(str.cbegin() + start_pos, str.cend(), IsDigitOrSign), "Invalid number: {}",
156 // str);
157 return is_negative ? -mpq_class{str.data() + start_pos} : mpq_class{str.data() + start_pos};
158 }
159
160 // case 2: string is given in nom/denom format
161 if (str[symbol_pos] == '/') {
162 mpq_class res{str.data()};
163 res.canonicalize();
164 return is_negative ? -res : res;
165 }
166
167 const size_t e_pos = str[symbol_pos] == 'e' || str[symbol_pos] == 'E' ? symbol_pos : str.find_first_of("Ee");
168 mpz_class mult{is_negative ? -1 : 1};
169 bool is_exp_positive = true;
170
171 // case 3a: string is given as base-10 decimal number (e)
172 if (e_pos != std::string::npos) {
173 const long exponent = std::stol(str.data() + e_pos + 1); // NOLINT(runtime/int)
174 is_exp_positive = exponent >= 0;
175 mult = 10;
176 mpz_pow_ui(mult.get_mpz_t(), mult.get_mpz_t(), std::abs(exponent));
177 if (is_negative) mult = -mult;
178 // Remove the exponent
179 str = str.substr(0, e_pos);
180
181 if (str.empty()) return is_exp_positive ? mpq_class{mult} : is_negative ? mpq_class{-1, -mult} : mpq_class{1, mult};
182 }
183
184 const size_t &len = str.length();
185
186 // case 3b: string does not contain a . , only an exponent E
187 if (str[symbol_pos] == 'e' || str[symbol_pos] == 'E') {
188 int plus_pos = str[0] == '+' ? 1 : 0;
189 // DLINEAR_ASSERT_FMT(std::all_of(str.cbegin() + plus_pos, str.cend(), IsDigitOrSign), "Invalid number: {}",
190 // str);
191
192 char *const str_number = new char[len - plus_pos + 1];
193 memcpy(str_number, str.data() + plus_pos, len - plus_pos);
194 str_number[len - plus_pos] = '\0';
195 mpq_class res{str_number, 10};
196 delete[] str_number;
197 return res * mult;
198 }
199
200 const size_t &dot_pos = symbol_pos;
201
202 // case 3c: string contains a .
203 size_t start_pos = str.find_first_not_of('0');
204 size_t digits;
205
206 // case 4a: string starts with a . or the numbers before the . are all 0
207 if (start_pos == dot_pos) {
208 start_pos = str.find_first_not_of('0', dot_pos + 1);
209 // case 5: string contains only a .
210 if (start_pos == std::string_view::npos) {
211 return {0};
212 } else {
213 digits = len - start_pos;
214 }
215 } else { // case 4b: string does not start with a . and the numbers before the . are not all 0
216 digits = len - start_pos - 1;
217 }
218
219 const size_t n_decimals = len - dot_pos - 1;
220 // DLINEAR_ASSERT_FMT(std::all_of(str.begin() + start_pos, str.begin() + dot_pos, IsDigitOrSign),
221 // "Invalid number: {}", str);
222 // DLINEAR_ASSERT_FMT(std::all_of(str.begin() + dot_pos + 1, str.cend(), IsDigitOrSign), "Invalid number: {}",
223 // str);
224 char *const str_number = new char[digits + n_decimals + 3];
225
226 if (digits > n_decimals) {
227 memcpy(str_number, str.data() + start_pos, digits - n_decimals);
228 memcpy(str_number + dot_pos, str.data() + dot_pos + 1, n_decimals);
229 } else {
230 memcpy(str_number, str.data() + start_pos, n_decimals);
231 }
232
233 str_number[digits] = '/';
234 str_number[digits + 1] = '1';
235 memset(str_number + digits + 2, '0', n_decimals);
236 str_number[digits + 2 + n_decimals] = '\0';
237
238 mpq_class res{str_number, 10};
239 delete[] str_number;
240 res.canonicalize();
241 return is_exp_positive ? mpq_class{res * mult} : res / mult;
242}
243
244} // namespace gmp
245
246} // namespace dlinear
247
248#ifdef DLINEAR_INCLUDE_FMT
249
250#include "dlinear/util/logging.h"
251
252OSTREAM_FORMATTER(mpq_class)
253
254#endif
Global namespace for the dlinear library.
STL namespace.