1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2 /* */ 3 /* This file is part of the class library */ 4 /* SoPlex --- the Sequential object-oriented simPlex. */ 5 /* */ 6 /* Copyright (c) 1996-2023 Zuse Institute Berlin (ZIB) */ 7 /* */ 8 /* Licensed under the Apache License, Version 2.0 (the "License"); */ 9 /* you may not use this file except in compliance with the License. */ 10 /* You may obtain a copy of the License at */ 11 /* */ 12 /* http://www.apache.org/licenses/LICENSE-2.0 */ 13 /* */ 14 /* Unless required by applicable law or agreed to in writing, software */ 15 /* distributed under the License is distributed on an "AS IS" BASIS, */ 16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ 17 /* See the License for the specific language governing permissions and */ 18 /* limitations under the License. */ 19 /* */ 20 /* You should have received a copy of the Apache-2.0 license */ 21 /* along with SoPlex; see the file LICENSE. If not email to soplex@zib.de. */ 22 /* */ 23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 24 25 /**@file spxdefines.h 26 * @brief Debugging, floating point type and parameter definitions. 27 * 28 * In optimized code with \c NDEBUG defined, only 29 * \ref soplex::SPxOut::INFO1 "INFO1", 30 * \ref soplex::SPxOut::INFO2 "INFO2", and 31 * \ref soplex::SPxOut::INFO3 "INFO3" are set. 32 * If \c NDEBUG is not defined, the code within \#TRACE is used. 33 * If \c SOPLEX_DEBUG is defined, the code within 34 * \ref soplex::SPxOut::DEBUG "DEBUG" is also used. 35 * 36 * If \c WITH_LONG_DOUBLE is defined, all Real numbers are of type 37 * long double instead of just double. 38 */ 39 #ifndef _SPXDEFINES_H_ 40 #define _SPXDEFINES_H_ 41 #include <cmath> 42 43 #ifdef _MSC_VER 44 #include <float.h> 45 #endif 46 47 #include <assert.h> 48 #include <stdarg.h> 49 #include <stdio.h> 50 #include <iostream> 51 52 #include <cstdlib> 53 #include <memory> 54 55 /* 56 * include build configuration flags 57 */ 58 #ifndef SOPLEX_NO_CONFIG_HEADER 59 #include "soplex/config.h" 60 #endif 61 62 #ifdef SOPLEX_WITH_BOOST 63 #include "boost/multiprecision/number.hpp" 64 #ifdef SOPLEX_WITH_FLOAT128 65 #include <boost/multiprecision/float128.hpp> 66 #endif 67 68 #ifdef SOPLEX_WITH_MPFR 69 // For multiple precision 70 #include <boost/multiprecision/mpfr.hpp> 71 #ifndef NDEBUG 72 #include "boost/multiprecision/debug_adaptor.hpp" // For debuging mpf numbers 73 #endif // NDEBUG 74 #endif // SOPLEX_WITH_MPFR 75 #ifdef SOPLEX_WITH_CPPMPF 76 #include <boost/serialization/nvp.hpp> 77 #include <boost/multiprecision/cpp_dec_float.hpp> 78 #endif // SOPLEX_WITH_CPPMPF 79 80 #ifdef SOPLEX_WITH_GMP 81 #include <boost/multiprecision/gmp.hpp> 82 #else 83 #include <boost/multiprecision/cpp_int.hpp> 84 using mpq_t = double; 85 #endif 86 87 #endif 88 89 namespace soplex 90 { 91 // Overloaded EQ function 92 bool EQ(int a, int b); 93 94 #define SOPLEX_VERSION 603 95 #define SOPLEX_SUBVERSION 5 96 #define SOPLEX_APIVERSION 14 97 #define SOPLEX_COPYRIGHT "Copyright (c) 1996-2023 Zuse Institute Berlin (ZIB)" 98 99 /*----------------------------------------------------------------------------- 100 * Assertion Macros etc. 101 *----------------------------------------------------------------------------- 102 */ 103 104 /** 105 \brief Macro to turn some assertions into warnings. 106 107 If both \c NDEBUG and \c WITH_WARNINGS are defined then the failed 108 assertion is converted to a warning. In all other cases this macro is 109 equivalent to assert(). 110 111 @param prefix Short string for grepping in source code. 112 @param expr Expression that must be satisfied. 113 */ 114 #if defined (NDEBUG) && defined (WITH_WARNINGS) 115 #define SOPLEX_ASSERT_WARN( prefix, expr ) \ 116 if ( !( expr ) ) \ 117 { \ 118 std::cerr \ 119 << prefix \ 120 << " failed assertion on line " << __LINE__ \ 121 << " in file " << __FILE__ << ": " \ 122 << #expr \ 123 << std::endl; \ 124 } 125 #else // just a normal assert 126 #define SOPLEX_ASSERT_WARN( prefix, expr ) ( assert( expr ) ) 127 #endif 128 129 130 131 /*----------------------------------------------------------------------------- 132 * Debugging Macros etc. 133 *----------------------------------------------------------------------------- 134 */ 135 136 /** 137 Prints/Executes \p stream with verbosity level \p verbosity, resetting 138 the old verbosity level afterwards. 139 Usually the parameter \p stream prints something out. 140 This is an internal define used by SPX_MSG_ERROR, SPX_MSG_WARNING, etc. 141 */ 142 #ifdef DISABLE_VERBOSITY 143 #define SOPLEX_DO_WITH_TMP_VERBOSITY( verbosity, spxout, do_something ) {} 144 #define SOPLEX_DO_WITH_ERR_VERBOSITY( do_something ) {} 145 #else 146 #define SOPLEX_DO_WITH_TMP_VERBOSITY( verbosity, spxout, do_something ) \ 147 { \ 148 if( &spxout != NULL ) \ 149 { \ 150 if( verbosity <= spxout.getVerbosity() ) \ 151 { \ 152 const SPxOut::Verbosity old_verbosity = spxout.getVerbosity(); \ 153 spxout.setVerbosity( verbosity ); \ 154 do_something; \ 155 spxout.setVerbosity( old_verbosity ); \ 156 } \ 157 } \ 158 } 159 #define SOPLEX_DO_WITH_ERR_VERBOSITY( do_something ) { do_something; } 160 #endif 161 162 /// Prints out message \p x if the verbosity level is at least SPxOut::ERROR. 163 #define SPX_MSG_ERROR(x) { SOPLEX_DO_WITH_ERR_VERBOSITY( x ) } 164 /// Prints out message \p x if the verbosity level is at least SPxOut::WARNING. 165 #define SPX_MSG_WARNING(spxout, x) { SOPLEX_DO_WITH_TMP_VERBOSITY( SPxOut::WARNING, spxout, x ) } 166 /// Prints out message \p x if the verbosity level is at least SPxOut::INFO1. 167 #define SPX_MSG_INFO1(spxout, x) { SOPLEX_DO_WITH_TMP_VERBOSITY( SPxOut::INFO1, spxout, x ) } 168 /// Prints out message \p x if the verbosity level is at least SPxOut::INFO2. 169 #define SPX_MSG_INFO2(spxout, x) { SOPLEX_DO_WITH_TMP_VERBOSITY( SPxOut::INFO2, spxout, x ) } 170 /// Prints out message \p x if the verbosity level is at least SPxOut::INFO3. 171 #define SPX_MSG_INFO3(spxout, x) { SOPLEX_DO_WITH_TMP_VERBOSITY( SPxOut::INFO3, spxout, x ) } 172 173 extern bool msginconsistent(const char* name, const char* file, int line); 174 175 #define SPX_MSG_INCONSISTENT(name) msginconsistent(name, __FILE__, __LINE__) 176 177 #if defined(SOPLEX_DEBUG) 178 // print output in any case, regardless of _tolerances->verbose(): 179 #define SPX_MSG_DEBUG(x) { x; } 180 #define SPX_DEBUG(x) { x; } 181 #else 182 #define SPX_MSG_DEBUG(x) /**/ 183 #define SPX_DEBUG(x) /**/ 184 #endif //!SOPLEX_DEBUG 185 186 187 /*----------------------------------------------------------------------------- 188 * multi-thread support 189 *----------------------------------------------------------------------------- 190 */ 191 // enable the user to compile without thread_local by setting USRCXXFLAGS=-DTHREADLOCAL="" 192 #if !defined(SOPLEX_THREADLOCAL) 193 #if defined(_MSC_VER) && _MSC_VER < 1900 194 #define SOPLEX_THREADLOCAL 195 #else 196 #define SOPLEX_THREADLOCAL thread_local 197 #endif 198 #endif 199 200 /*----------------------------------------------------------------------------- 201 * Long double support, Parameters and Epsilons 202 *----------------------------------------------------------------------------- 203 */ 204 205 206 #ifdef WITH_LONG_DOUBLE 207 208 209 typedef long double Real; 210 211 #ifndef SOPLEX_REAL 212 #define SOPLEX_REAL(x) x##L 213 #define SOPLEX_REAL_FORMAT "Lf" 214 #endif 215 /// default allowed bound violation 216 #ifndef SOPLEX_DEFAULT_BND_VIOL 217 #define SOPLEX_DEFAULT_BND_VIOL 1e-12L 218 #endif 219 /// default allowed additive zero: 1.0 + EPS_ZERO == 1.0 220 #ifndef SOPLEX_DEFAULT_EPS_ZERO 221 #define SOPLEX_DEFAULT_EPS_ZERO 1e-28L 222 #endif 223 /// epsilon for factorization 224 #ifndef SOPLEX_DEFAULT_EPS_FACTOR 225 #define SOPLEX_DEFAULT_EPS_FACTOR 1e-30L 226 #endif 227 /// epsilon for factorization update 228 #ifndef SOPLEX_DEFAULT_EPS_UPDATE 229 #define SOPLEX_DEFAULT_EPS_UPDATE 1e-26L 230 #endif 231 #ifndef SOPLEX_DEFAULT_EPS_PIVOR 232 #define SOPLEX_DEFAULT_EPS_PIVOR 1e-20L 233 #endif 234 /// 235 #define SOPLEX_DEFAULT_INFINITY 1e100L 236 237 238 #else 239 240 #ifdef WITH_FLOAT 241 242 typedef float Real; 243 244 #ifndef SOPLEX_REAL 245 #define SOPLEX_REAL(x) x 246 #define SOPLEX_REAL_FORMAT "f" 247 #endif 248 /// default allowed bound violation 249 #ifndef SOPLEX_DEFAULT_BND_VIOL 250 #define SOPLEX_DEFAULT_BND_VIOL 1e-1f 251 #endif 252 /// default allowed additive zero: 1.0 + EPS_ZERO == 1.0 253 #ifndef SOPLEX_DEFAULT_EPS_ZERO 254 #define SOPLEX_DEFAULT_EPS_ZERO 1e-7f 255 #endif 256 #ifndef SOPLEX_DEFAULT_EPS_FACTOR 257 #define SOPLEX_DEFAULT_EPS_FACTOR 1e-7f 258 #endif 259 #ifndef SOPLEX_DEFAULT_EPS_UPDATE 260 #define SOPLEX_DEFAULT_EPS_UPDATE 1e-6f 261 #endif 262 #ifndef SOPLEX_DEFAULT_EPS_PIVOR 263 #define SOPLEX_DEFAULT_EPS_PIVOR 1e-6f 264 #endif 265 #define SOPLEX_DEFAULT_INFINITY 1e35f 266 267 #else 268 269 typedef double Real; 270 271 #ifndef SOPLEX_REAL 272 #define SOPLEX_REAL(x) x 273 #define SOPLEX_REAL_FORMAT "lf" 274 #endif 275 /// default allowed bound violation 276 #ifndef SOPLEX_DEFAULT_BND_VIOL 277 #define SOPLEX_DEFAULT_BND_VIOL 1e-6 278 #endif 279 /// default allowed additive zero: 1.0 + EPS_ZERO == 1.0 280 #ifndef SOPLEX_DEFAULT_EPS_ZERO 281 #define SOPLEX_DEFAULT_EPS_ZERO 1e-16 282 #endif 283 #ifndef SOPLEX_DEFAULT_EPS_FACTOR 284 #define SOPLEX_DEFAULT_EPS_FACTOR 1e-20 285 #endif 286 #ifndef SOPLEX_DEFAULT_EPS_UPDATE 287 #define SOPLEX_DEFAULT_EPS_UPDATE 1e-16 288 #endif 289 #ifndef SOPLEX_DEFAULT_EPS_PIVOR 290 #define SOPLEX_DEFAULT_EPS_PIVOR 1e-10 291 #endif 292 #define SOPLEX_DEFAULT_INFINITY 1e100 293 294 #endif // !WITH_FLOAT 295 #endif // !WITH_LONG_DOUBLE 296 297 #define SOPLEX_MAX(x,y) ((x)>(y) ? (x) : (y)) 298 #define SOPLEX_MIN(x,y) ((x)<(y) ? (x) : (y)) 299 300 #define SPX_MAXSTRLEN 1024 /**< maximum string length in SoPlex */ 301 302 SOPLEX_THREADLOCAL extern const Real infinity; 303 304 class Tolerances 305 { 306 private: 307 308 //------------------------------------ 309 /**@name Data */ 310 ///@{ 311 /// default allowed additive zero: 1.0 + EPS_ZERO == 1.0 312 Real s_epsilon; 313 /// epsilon for factorization 314 Real s_epsilon_factorization; 315 /// epsilon for factorization update 316 Real s_epsilon_update; 317 /// epsilon for pivot zero tolerance in factorization 318 Real s_epsilon_pivot; 319 /// feasibility tolerance 320 Real s_feastol; 321 /// optimality tolerance 322 Real s_opttol; 323 /// floating point feasibility tolerance 324 Real s_floating_point_feastol; 325 /// floating point optimality tolerance 326 Real s_floating_point_opttol; 327 /// multiplier for fixed numbers that should change if s_epsilon changes 328 Real s_epsilon_multiplier; 329 ///@} 330 331 public: 332 333 // default constructor 334 explicit Tolerances() 335 : s_epsilon(SOPLEX_DEFAULT_EPS_ZERO), s_epsilon_factorization(SOPLEX_DEFAULT_EPS_FACTOR), 336 s_epsilon_update(SOPLEX_DEFAULT_EPS_UPDATE), s_epsilon_pivot(SOPLEX_DEFAULT_EPS_PIVOR), 337 s_feastol(SOPLEX_DEFAULT_BND_VIOL), s_opttol(SOPLEX_DEFAULT_BND_VIOL), 338 s_floating_point_feastol(SOPLEX_DEFAULT_BND_VIOL), 339 s_floating_point_opttol(SOPLEX_DEFAULT_BND_VIOL), 340 s_epsilon_multiplier(1.0) 341 {} 342 343 //------------------------------------ 344 /**@name Access / modification */ 345 ///@{ 346 /// global zero epsilon 347 Real epsilon(); 348 /// set global zero epsilon 349 void setEpsilon(Real eps); 350 /// zero espilon used in factorization 351 Real epsilonFactorization(); 352 /// set zero espilon used in factorization 353 void setEpsilonFactorization(Real eps); 354 /// zero espilon used in factorization update 355 Real epsilonUpdate(); 356 /// set zero espilon used in factorization update 357 void setEpsilonUpdate(Real eps); 358 /// zero espilon used in pivot 359 Real epsilonPivot(); 360 /// set zero espilon used in pivot 361 void setEpsilonPivot(Real eps); 362 /// global feasibility tolerance 363 Real feastol(); 364 /// set global feasibility tolerance 365 void setFeastol(Real ftol); 366 /// global optimality tolerance 367 Real opttol(); 368 /// set global optimality tolerance 369 void setOpttol(Real otol); 370 /// floating point feasibility tolerance used within the solver 371 Real floatingPointFeastol(); 372 /// set floating point feasibility tolerance used within the solver 373 void setFloatingPointFeastol(Real ftol); 374 /// floating point optimality tolerance used within the solver 375 Real floatingPointOpttol(); 376 /// set floating point optimality tolerance used within the solver 377 void setFloatingPointOpttol(Real otol); 378 /// scale a value such that it remains unchanged at default epsilon, but is scaled withs smaller epsilon values 379 /// this is updated in setEpsilon() 380 inline Real scaleAccordingToEpsilon(Real a) 381 { 382 return s_epsilon_multiplier == 1.0 ? a : a * s_epsilon_multiplier; 383 } 384 ///@} 385 }; 386 387 // A generic version of spxAbs. It would be nice if we could replace spxAbs 388 // with std::abs. Currently there are different versions of spxAbs under 389 // compile time #if. It's better to make this an overloaded function. Even 390 // better, replace it by std::abs since types from boost/multiprecision would 391 // need no extra modification. 392 template <class R> 393 R spxAbs(R a) 394 { 395 return abs(a); 396 } 397 398 // cmath means proper long double function gets called, e.g. for fabs -> fabsl. 399 // Documentation unclear for nextafterl, so the ifdef remains for that case. 400 #ifdef WITH_LONG_DOUBLE 401 // returns the next representable value after x in the direction of y 402 inline Real spxNextafter(Real x, Real y) 403 { 404 return nextafterl(x, y); 405 } 406 #else 407 // returns the next representable value after x in the direction of y 408 inline Real spxNextafter(Real x, Real y) 409 { 410 #ifndef _MSC_VER 411 return nextafter(x, y); 412 #else 413 return _nextafter(x, y); 414 #endif 415 } 416 #endif 417 418 /// returns |a| 419 template <> 420 inline Real spxAbs(Real a) 421 { 422 return fabs(a); 423 } 424 425 /// returns square root 426 inline Real spxSqrt(Real a) 427 { 428 return std::sqrt(a); 429 } 430 431 /// returns max(|a|,|b|) 432 inline Real maxAbs(Real a, Real b) 433 { 434 const Real absa = spxAbs(a); 435 const Real absb = spxAbs(b); 436 437 return absa > absb ? absa : absb; 438 } 439 440 /// returns (a-b) / max(|a|,|b|,1.0) 441 inline Real relDiff(Real a, Real b) 442 { 443 return (a - b) / (maxAbs(a, b) > 1.0 ? maxAbs(a, b) : 1.0); 444 } 445 446 /// safe version of snprintf 447 inline int spxSnprintf( 448 char* t, /**< target string */ 449 size_t len, /**< length of the string to copy */ 450 const char* s, /**< source string */ 451 ... /**< further parameters */ 452 ) 453 { 454 va_list ap; 455 int n; 456 457 assert(t != NULL); 458 assert(len > 0); 459 460 va_start(ap, s); /*lint !e826*/ 461 462 #if defined(_WIN32) || defined(_WIN64) 463 n = _vsnprintf(t, len, s, ap); 464 #else 465 n = vsnprintf(t, len, s, ap); /*lint !e571*/ 466 #endif 467 va_end(ap); 468 469 if(n < 0 || (size_t) n >= len) 470 { 471 #ifndef NDEBUG 472 473 if(n < 0) 474 { 475 SPX_MSG_ERROR(std::cerr << "vsnprintf returned " << n << " while reading: " << s << std::endl;) 476 } 477 478 #endif 479 t[len - 1] = '\0'; 480 n = (int) len - 1; 481 } 482 483 return n; 484 } 485 486 #ifdef SOPLEX_WITH_BOOST 487 488 using namespace boost::multiprecision; 489 490 #ifdef SOPLEX_WITH_GMP 491 template<boost::multiprecision::expression_template_option eto> 492 inline number<gmp_rational, eto> ldexp(number<gmp_rational, eto>, int exp) 493 { 494 assert(false); 495 return number<gmp_rational>(); 496 } 497 498 template<boost::multiprecision::expression_template_option eto> 499 inline number<gmp_rational, eto> frexp(number<gmp_rational, eto>, int* exp) 500 { 501 assert(false); 502 return number<gmp_rational>(); 503 } 504 #else 505 inline cpp_rational ldexp(cpp_rational r, int exp) 506 { 507 assert(false); 508 return cpp_rational(); 509 } 510 511 inline cpp_rational frexp(cpp_rational, int* exp) 512 { 513 assert(false); 514 return cpp_rational(); 515 } 516 #endif 517 518 // wrapped frexp function 519 template <typename T, boost::multiprecision::expression_template_option eto> 520 boost::multiprecision::number<T, eto> spxFrexp(boost::multiprecision::number<T, eto> y, int* exp) 521 { 522 return frexp(y, exp); 523 } 524 525 // Overloaded spxLdexp 526 template <typename T, boost::multiprecision::expression_template_option eto> 527 boost::multiprecision::number<T> spxLdexp(boost::multiprecision::number<T, eto> x, int exp) 528 { 529 return ldexp(x, exp); 530 } 531 532 // Overloaded function to return the square-root 533 template <typename T, expression_template_option ep> 534 number<T, ep> spxSqrt(number<T, ep> a) 535 { 536 return sqrt(a); 537 } 538 539 // the nextafter function 540 template <typename T, expression_template_option eto> 541 number<T, eto> spxNextafter(number<T, eto> x, 542 number<T, eto> y) 543 { 544 // Turns out that nextafter is not supported in the mpfr library? The mpfr 545 // library does a different function named nextabove. Probably a 546 // replacement? I've made an issue about this. 547 // return nextafter(x,y); 548 549 // @todo Temporarily, I'm returning 0 550 assert(false); 551 return 0; 552 } 553 554 // Returns the square root 555 template <typename T> 556 number<T> spxSqrt(number<T> a) 557 { 558 return sqrt(a); 559 } 560 561 /// returns max(|a|,|b|) 562 template <typename T, expression_template_option et> 563 inline number<T, et> maxAbs( 564 number<T, et> a, number<T, et> b) 565 { 566 const auto absa = spxAbs(a); 567 const auto absb = spxAbs(b); 568 569 return absa > absb ? absa : absb; 570 } 571 572 template <typename T, expression_template_option et> 573 inline number<T, et> relDiff(number<T, et> a, 574 number<T, et> b) 575 { 576 return (a - b) / (maxAbs(a, b) > 1.0 ? maxAbs(a, b) : 1.0); 577 } 578 #endif 579 using namespace soplex; 580 581 } // namespace soplex 582 583 // For the templated functions 584 #include "spxdefines.hpp" 585 586 #endif // _SPXDEFINES_H_ 587