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 soplexmain.cpp 26 * @brief Command line interface of SoPlex LP solver 27 */ 28 29 #include <assert.h> 30 #include <math.h> 31 #include <string.h> 32 33 #include <iostream> 34 #include <iomanip> 35 #include <fstream> 36 37 #include "soplex.h" 38 #include "soplex/validation.h" 39 40 using namespace soplex; 41 42 // function prototype 43 int main(int argc, char* argv[]); 44 45 // prints usage and command line options 46 static 47 void printUsage(const char* const argv[], int idx) 48 { 49 const char* usage = 50 "general options:\n" 51 " --readbas=<basfile> read starting basis from file\n" 52 " --writebas=<basfile> write terminal basis to file\n" 53 " --writefile=<lpfile> write LP to file in LP or MPS format depending on extension\n" 54 " --writedual=<lpfile> write the dual LP to a file in LP or MPS formal depending on extension\n" 55 " --<type>:<name>=<val> change parameter value using syntax of settings file entries\n" 56 " --loadset=<setfile> load parameters from settings file (overruled by command line parameters)\n" 57 " --saveset=<setfile> save parameters to settings file\n" 58 " --diffset=<setfile> save modified parameters to settings file\n" 59 " --extsol=<value> external solution for soplex to use for validation\n" 60 "\n" 61 "limits and tolerances:\n" 62 " -t<s> set time limit to <s> seconds\n" 63 " -i<n> set iteration limit to <n>\n" 64 " -f<eps> set primal feasibility tolerance to <eps>\n" 65 " -o<eps> set dual feasibility (optimality) tolerance to <eps>\n" 66 " -l<eps> set validation tolerance to <eps>\n" 67 "\n" 68 "algorithmic settings (* indicates default):\n" 69 " --readmode=<value> choose reading mode for <lpfile> (0* - floating-point, 1 - rational)\n" 70 " --solvemode=<value> choose solving mode (0 - floating-point solve, 1* - auto, 2 - force iterative refinement)\n" 71 " --arithmetic=<value> choose base arithmetic type (0 - double, 1 - quadprecision, 2 - higher multiprecision)\n" 72 #ifdef SOPLEX_WITH_MPFR 73 " --precision=<value> choose precision for multiprecision solve (only active when arithmetic=2 minimal value = 50)\n" 74 #endif 75 #ifdef SOPLEX_WITH_CPPMPF 76 " --precision=<value> choose precision for multiprecision solve (only active when arithmetic=2, possible values 50,100,200, compile with mpfr for arbitrary precision)\n" 77 #endif 78 " -s<value> choose simplifier/presolver (0 - off, 1* - internal, 2*- PaPILO)\n" 79 " -g<value> choose scaling (0 - off, 1 - uni-equilibrium, 2* - bi-equilibrium, 3 - geometric, 4 - iterated geometric, 5 - least squares, 6 - geometric-equilibrium)\n" 80 " -p<value> choose pricing (0* - auto, 1 - dantzig, 2 - parmult, 3 - devex, 4 - quicksteep, 5 - steep)\n" 81 " -r<value> choose ratio tester (0 - textbook, 1 - harris, 2 - fast, 3* - boundflipping)\n" 82 "\n" 83 "display options:\n" 84 " -v<level> set verbosity to <level> (0 - error, 3 - normal, 5 - high)\n" 85 " -x=<solfile> print primal solution to file (or just -x to print to terminal)\n" 86 " -y=<solfile> print dual multipliers to file (or just -y to print to terminal)\n" 87 " -X=<solfile> print primal solution in rational numbers to file (or just -X to print to terminal)\n" 88 " -Y=<solfile> print dual multipliers in rational numbers to file (or just -Y to print to terminal)\n" 89 " -q display detailed statistics\n" 90 " -c perform final check of optimal solution in original problem\n" 91 "\n"; 92 93 if(idx <= 0) 94 std::cerr << "missing input file\n\n"; 95 else 96 std::cerr << "invalid option \"" << argv[idx] << "\"\n\n"; 97 98 std::cerr << "usage: " << argv[0] << " " << "[options] <lpfile>\n" 99 #ifdef SOPLEX_WITH_ZLIB 100 << " <lpfile> linear program as .mps[.gz] or .lp[.gz] file\n\n" 101 #else 102 << " <lpfile> linear program as .mps or .lp file\n\n" 103 #endif 104 << usage; 105 } 106 107 // cleans up C strings 108 static 109 void freeStrings(char*& s1, char*& s2, char*& s3, char*& s4, char*& s5) 110 { 111 if(s1 != 0) 112 { 113 delete [] s1; 114 s1 = 0; 115 } 116 117 if(s2 != 0) 118 { 119 delete [] s2; 120 s2 = 0; 121 } 122 123 if(s3 != 0) 124 { 125 delete [] s3; 126 s3 = 0; 127 } 128 129 if(s4 != 0) 130 { 131 delete [] s4; 132 s4 = 0; 133 } 134 135 if(s5 != 0) 136 { 137 delete [] s5; 138 s5 = 0; 139 } 140 } 141 142 /// performs external feasibility check with real type 143 ///@todo implement external check; currently we use the internal methods for convenience 144 145 template <class R> 146 static 147 void checkSolutionReal(SoPlexBase<R>& soplex) 148 { 149 if(soplex.hasPrimal()) 150 { 151 R boundviol; 152 R rowviol; 153 R sumviol; 154 155 if(soplex.getBoundViolation(boundviol, sumviol) && soplex.getRowViolation(rowviol, sumviol)) 156 { 157 SPX_MSG_INFO1(soplex.spxout, 158 R maxviol = boundviol > rowviol ? boundviol : rowviol; 159 bool feasible = (maxviol <= soplex.realParam(SoPlexBase<R>::FEASTOL)); 160 soplex.spxout << "Primal solution " << (feasible ? "feasible" : "infeasible") 161 << " in original problem (max. violation = " << std::scientific << maxviol 162 << std::setprecision(8) << std::fixed << ").\n"); 163 } 164 else 165 { 166 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "Could not check primal solution.\n"); 167 } 168 } 169 else 170 { 171 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "No primal solution available.\n"); 172 } 173 174 if(soplex.hasDual()) 175 { 176 R redcostviol; 177 R dualviol; 178 R sumviol; 179 180 if(soplex.getRedCostViolation(redcostviol, sumviol) && soplex.getDualViolation(dualviol, sumviol)) 181 { 182 SPX_MSG_INFO1(soplex.spxout, 183 R maxviol = redcostviol > dualviol ? redcostviol : dualviol; 184 bool feasible = (maxviol <= soplex.realParam(SoPlexBase<R>::OPTTOL)); 185 soplex.spxout << "Dual solution " << (feasible ? "feasible" : "infeasible") 186 << " in original problem (max. violation = " << std::scientific << maxviol 187 << std::setprecision(8) << std::fixed << ").\n" 188 ); 189 } 190 else 191 { 192 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "Could not check dual solution.\n"); 193 } 194 } 195 else 196 { 197 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "No dual solution available.\n"); 198 } 199 } 200 201 /// performs external feasibility check with rational type 202 ///@todo implement external check; currently we use the internal methods for convenience 203 template <class R> 204 static void checkSolutionRational(SoPlexBase<R>& soplex) 205 { 206 if(soplex.hasPrimal()) 207 { 208 Rational boundviol; 209 Rational rowviol; 210 Rational sumviol; 211 212 if(soplex.getBoundViolationRational(boundviol, sumviol) 213 && soplex.getRowViolationRational(rowviol, sumviol)) 214 { 215 SPX_MSG_INFO1(soplex.spxout, 216 Rational maxviol = boundviol > rowviol ? boundviol : rowviol; 217 bool feasible = (maxviol <= soplex.realParam(SoPlexBase<R>::FEASTOL)); 218 soplex.spxout << "Primal solution " << (feasible ? "feasible" : "infeasible") << 219 " in original problem (max. violation = " << maxviol << ").\n" 220 ); 221 } 222 else 223 { 224 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "Could not check primal solution.\n"); 225 } 226 } 227 else 228 { 229 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "No primal solution available.\n"); 230 } 231 232 if(soplex.hasDual()) 233 { 234 Rational redcostviol; 235 Rational dualviol; 236 Rational sumviol; 237 238 if(soplex.getRedCostViolationRational(redcostviol, sumviol) 239 && soplex.getDualViolationRational(dualviol, sumviol)) 240 { 241 SPX_MSG_INFO1(soplex.spxout, 242 Rational maxviol = redcostviol > dualviol ? redcostviol : dualviol; 243 bool feasible = (maxviol <= soplex.realParam(SoPlexBase<R>::OPTTOL)); 244 soplex.spxout << "Dual solution " << (feasible ? "feasible" : "infeasible") << 245 " in original problem (max. violation = " << maxviol << ").\n" 246 ); 247 } 248 else 249 { 250 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "Could not check dual solution.\n"); 251 } 252 } 253 else 254 { 255 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "No dual solution available.\n"); 256 } 257 } 258 259 /// performs external feasibility check according to check mode 260 template <class R> 261 void checkSolution(SoPlexBase<R>& soplex) 262 { 263 if(soplex.intParam(SoPlexBase<R>::CHECKMODE) == SoPlexBase<R>::CHECKMODE_RATIONAL 264 || (soplex.intParam(SoPlexBase<R>::CHECKMODE) == SoPlexBase<R>::CHECKMODE_AUTO 265 && soplex.intParam(SoPlexBase<R>::READMODE) == SoPlexBase<R>::READMODE_RATIONAL)) 266 { 267 checkSolutionRational(soplex); 268 } 269 else 270 { 271 checkSolutionReal(soplex); 272 } 273 274 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\n"); 275 } 276 277 template <class R> 278 static 279 void writePrimalSolution(SoPlexBase<R>& soplex, const char* filename, NameSet& colnames, 280 NameSet& rownames, 281 bool real = true, bool rational = false, bool append = false) 282 { 283 int printprec; 284 int printwidth; 285 printprec = (int) - log10(Real(soplex.tolerances()->epsilon())); 286 printwidth = printprec + 10; 287 std::ofstream outfile; 288 289 if(append) 290 outfile.open(filename, std::ios::app); 291 else 292 outfile.open(filename); 293 294 if(real) 295 { 296 VectorBase<R> primal(soplex.numCols()); 297 298 if(soplex.getPrimalRay(primal)) 299 { 300 outfile << "\nPrimal ray (name, value):\n"; 301 302 for(int i = 0; i < soplex.numCols(); ++i) 303 { 304 if(isNotZero(primal[i], soplex.tolerances()->epsilon())) 305 { 306 outfile << colnames[i] << "\t" 307 << std::setw(printwidth) << std::setprecision(printprec) 308 << primal[i] << std::endl; 309 } 310 } 311 312 outfile << "All other entries are zero (within " 313 << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon() 314 << std::setprecision(8) << std::fixed 315 << ")." << std::endl; 316 } 317 else if(soplex.isPrimalFeasible() && soplex.getPrimal(primal)) 318 { 319 int nNonzeros = 0; 320 outfile << "\nPrimal solution (name, value):\n"; 321 322 for(int i = 0; i < soplex.numCols(); ++i) 323 { 324 if(isNotZero(primal[i], soplex.tolerances()->epsilon())) 325 { 326 outfile << colnames[i] << "\t" 327 << std::setw(printwidth) << std::setprecision(printprec) 328 << primal[i] << std::endl; 329 ++nNonzeros; 330 } 331 } 332 333 outfile << "All other variables are zero (within " 334 << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon() 335 << std::setprecision(8) << std::fixed 336 << "). Solution has " << nNonzeros << " nonzero entries." << std::endl; 337 } 338 else 339 outfile << "No primal information available.\n"; 340 } 341 342 if(rational) 343 { 344 VectorRational primal(soplex.numCols()); 345 346 if(soplex.getPrimalRayRational(primal)) 347 { 348 outfile << "\nPrimal ray (name, value):\n"; 349 350 for(int i = 0; i < soplex.numCols(); ++i) 351 { 352 if(primal[i] != (Rational) 0) 353 { 354 outfile << colnames[i] << "\t" 355 << std::setw(printwidth) << std::setprecision(printprec) 356 << primal[i] << std::endl; 357 } 358 } 359 360 outfile << "All other entries are zero." << std::endl; 361 } 362 363 if(soplex.isPrimalFeasible() && soplex.getPrimalRational(primal)) 364 { 365 int nNonzeros = 0; 366 outfile << "\nPrimal solution (name, value):\n"; 367 368 for(int i = 0; i < soplex.numColsRational(); ++i) 369 { 370 if(primal[i] != (Rational) 0) 371 { 372 outfile << colnames[i] << "\t" << primal[i] << std::endl; 373 ++nNonzeros; 374 } 375 } 376 377 outfile << "All other variables are zero. Solution has " 378 << nNonzeros << " nonzero entries." << std::endl; 379 } 380 else 381 outfile << "No primal (rational) solution available.\n"; 382 } 383 } 384 385 template <class R> 386 static 387 void writeDualSolution(SoPlexBase<R>& soplex, const char* filename, NameSet& colnames, 388 NameSet& rownames, 389 bool real = true, bool rational = false, bool append = false) 390 { 391 int printprec; 392 int printwidth; 393 printprec = (int) - log10(Real(soplex.tolerances()->epsilon())); 394 printwidth = printprec + 10; 395 396 std::ofstream outfile; 397 398 if(append) 399 outfile.open(filename, std::ios::app); 400 else 401 outfile.open(filename); 402 403 if(real) 404 { 405 VectorBase<R> dual(soplex.numRows()); 406 407 if(soplex.getDualFarkas(dual)) 408 { 409 outfile << "\nDual ray (name, value):\n"; 410 411 for(int i = 0; i < soplex.numRows(); ++i) 412 { 413 if(isNotZero(dual[i], soplex.tolerances()->epsilon())) 414 { 415 outfile << rownames[i] << "\t" 416 << std::setw(printwidth) << std::setprecision(printprec) 417 << dual[i] << std::endl; 418 } 419 } 420 421 outfile << "All other entries are zero (within " 422 << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon() 423 << std::setprecision(8) << std::fixed << ")." << std::endl; 424 } 425 else if(soplex.isDualFeasible() && soplex.getDual(dual)) 426 { 427 outfile << "\nDual solution (name, value):\n"; 428 429 for(int i = 0; i < soplex.numRows(); ++i) 430 { 431 if(isNotZero(dual[i], soplex.tolerances()->epsilon())) 432 { 433 outfile << rownames[i] << "\t" 434 << std::setw(printwidth) << std::setprecision(printprec) 435 << dual[i] << std::endl; 436 } 437 } 438 439 outfile << "All other dual values are zero (within " 440 << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon() 441 << std::setprecision(8) << std::fixed << ")." << std::endl; 442 443 VectorBase<R> redcost(soplex.numCols()); 444 445 if(soplex.getRedCost(redcost)) 446 { 447 outfile << "\nReduced costs (name, value):\n"; 448 449 for(int i = 0; i < soplex.numCols(); ++i) 450 { 451 if(isNotZero(redcost[i], soplex.tolerances()->epsilon())) 452 { 453 outfile << colnames[i] << "\t" 454 << std::setw(printwidth) << std::setprecision(printprec) 455 << redcost[i] << std::endl; 456 } 457 } 458 459 outfile << "All other reduced costs are zero (within " 460 << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon() 461 << std::setprecision(8) << std::fixed << ")." << std::endl; 462 } 463 } 464 else 465 outfile << "No dual information available.\n"; 466 } 467 468 if(rational) 469 { 470 VectorRational dual(soplex.numRows()); 471 472 if(soplex.getDualFarkasRational(dual)) 473 { 474 outfile << "\nDual ray (name, value):\n"; 475 476 for(int i = 0; i < soplex.numRows(); ++i) 477 { 478 if(dual[i] != (Rational) 0) 479 { 480 outfile << rownames[i] << "\t" 481 << std::setw(printwidth) 482 << std::setprecision(printprec) 483 << dual[i] << std::endl; 484 } 485 } 486 487 outfile << "All other entries are zero." << std::endl; 488 } 489 490 if(soplex.isDualFeasible() && soplex.getDualRational(dual)) 491 { 492 outfile << "\nDual solution (name, value):\n"; 493 494 for(int i = 0; i < soplex.numRowsRational(); ++i) 495 { 496 if(dual[i] != (Rational) 0) 497 outfile << rownames[i] << "\t" << dual[i] << std::endl; 498 } 499 500 outfile << "All other dual values are zero." << std::endl; 501 502 VectorRational redcost(soplex.numCols()); 503 504 if(soplex.getRedCostRational(redcost)) 505 { 506 outfile << "\nReduced costs (name, value):\n"; 507 508 for(int i = 0; i < soplex.numCols(); ++i) 509 { 510 if(redcost[i] != (Rational) 0) 511 outfile << colnames[i] << "\t" << redcost[i] << std::endl; 512 } 513 514 outfile << "All other reduced costs are zero." << std::endl; 515 } 516 } 517 else 518 outfile << "No dual (rational) solution available.\n"; 519 } 520 } 521 522 template <class R> 523 static 524 void printPrimalSolution(SoPlexBase<R>& soplex, NameSet& colnames, NameSet& rownames, 525 bool real = true, bool rational = false) 526 { 527 int printprec; 528 int printwidth; 529 printprec = (int) - log10(Real(soplex.tolerances()->epsilon())); 530 printwidth = printprec + 10; 531 532 if(real) 533 { 534 VectorBase<R> primal(soplex.numCols()); 535 536 if(soplex.getPrimalRay(primal)) 537 { 538 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nPrimal ray (name, value):\n";) 539 540 for(int i = 0; i < soplex.numCols(); ++i) 541 { 542 if(isNotZero(primal[i], soplex.tolerances()->epsilon())) 543 { 544 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << colnames[i] << "\t" 545 << std::setw(printwidth) << std::setprecision(printprec) 546 << primal[i] << std::endl;) 547 } 548 } 549 550 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other entries are zero (within " 551 << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon() 552 << std::setprecision(8) << std::fixed 553 << ")." << std::endl;) 554 } 555 else if(soplex.isPrimalFeasible() && soplex.getPrimal(primal)) 556 { 557 int nNonzeros = 0; 558 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nPrimal solution (name, value):\n";) 559 560 for(int i = 0; i < soplex.numCols(); ++i) 561 { 562 if(isNotZero(primal[i], soplex.tolerances()->epsilon())) 563 { 564 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << colnames[i] << "\t" 565 << std::setw(printwidth) << std::setprecision(printprec) 566 << primal[i] << std::endl;) 567 ++nNonzeros; 568 } 569 } 570 571 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other variables are zero (within " 572 << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon() 573 << std::setprecision(8) << std::fixed 574 << "). Solution has " << nNonzeros << " nonzero entries." << std::endl;) 575 } 576 else 577 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "No primal information available.\n") 578 } 579 580 if(rational) 581 { 582 VectorRational primal(soplex.numCols()); 583 584 if(soplex.getPrimalRayRational(primal)) 585 { 586 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nPrimal ray (name, value):\n";) 587 588 for(int i = 0; i < soplex.numCols(); ++i) 589 { 590 if(primal[i] != (Rational) 0) 591 { 592 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << colnames[i] << "\t" 593 << std::setw(printwidth) << std::setprecision(printprec) 594 << primal[i] << std::endl;) 595 } 596 } 597 598 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other entries are zero." << std::endl;) 599 } 600 601 if(soplex.isPrimalFeasible() && soplex.getPrimalRational(primal)) 602 { 603 int nNonzeros = 0; 604 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nPrimal solution (name, value):\n";) 605 606 for(int i = 0; i < soplex.numColsRational(); ++i) 607 { 608 if(primal[i] != (Rational) 0) 609 { 610 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << colnames[i] << "\t" << primal[i] << std::endl;) 611 ++nNonzeros; 612 } 613 } 614 615 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other variables are zero. Solution has " 616 << nNonzeros << " nonzero entries." << std::endl;) 617 } 618 else 619 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "No primal (rational) solution available.\n") 620 621 } 622 } 623 624 template <class R> 625 static 626 void printDualSolution(SoPlexBase<R>& soplex, NameSet& colnames, NameSet& rownames, 627 bool real = true, bool rational = false) 628 { 629 int printprec; 630 int printwidth; 631 printprec = (int) - log10(Real(soplex.tolerances()->epsilon())); 632 printwidth = printprec + 10; 633 634 if(real) 635 { 636 VectorBase<R> dual(soplex.numRows()); 637 638 if(soplex.getDualFarkas(dual)) 639 { 640 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nDual ray (name, value):\n";) 641 642 for(int i = 0; i < soplex.numRows(); ++i) 643 { 644 if(isNotZero(dual[i], soplex.tolerances()->epsilon())) 645 { 646 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << rownames[i] << "\t" 647 << std::setw(printwidth) << std::setprecision(printprec) 648 << dual[i] << std::endl;) 649 } 650 } 651 652 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other entries are zero (within " 653 << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon() 654 << std::setprecision(8) << std::fixed << ")." << std::endl;) 655 } 656 else if(soplex.isDualFeasible() && soplex.getDual(dual)) 657 { 658 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nDual solution (name, value):\n";) 659 660 for(int i = 0; i < soplex.numRows(); ++i) 661 { 662 if(isNotZero(dual[i], soplex.tolerances()->epsilon())) 663 { 664 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << rownames[i] << "\t" 665 << std::setw(printwidth) << std::setprecision(printprec) 666 << dual[i] << std::endl;) 667 } 668 } 669 670 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other dual values are zero (within " 671 << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon() 672 << std::setprecision(8) << std::fixed << ")." << std::endl;) 673 674 VectorBase<R> redcost(soplex.numCols()); 675 676 if(soplex.getRedCost(redcost)) 677 { 678 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nReduced costs (name, value):\n";) 679 680 for(int i = 0; i < soplex.numCols(); ++i) 681 { 682 if(isNotZero(redcost[i], soplex.tolerances()->epsilon())) 683 { 684 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << colnames[i] << "\t" 685 << std::setw(printwidth) << std::setprecision(printprec) 686 << redcost[i] << std::endl;) 687 } 688 } 689 690 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other reduced costs are zero (within " 691 << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon() 692 << std::setprecision(8) << std::fixed << ")." << std::endl;) 693 } 694 } 695 else 696 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "No dual information available.\n") 697 } 698 699 if(rational) 700 { 701 VectorRational dual(soplex.numRows()); 702 703 if(soplex.getDualFarkasRational(dual)) 704 { 705 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nDual ray (name, value):\n";) 706 707 for(int i = 0; i < soplex.numRows(); ++i) 708 { 709 if(dual[i] != (Rational) 0) 710 { 711 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << rownames[i] << "\t" 712 << std::setw(printwidth) 713 << std::setprecision(printprec) 714 << dual[i] << std::endl;) 715 } 716 } 717 718 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other entries are zero." << std::endl;) 719 } 720 721 if(soplex.isDualFeasible() && soplex.getDualRational(dual)) 722 { 723 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nDual solution (name, value):\n";) 724 725 for(int i = 0; i < soplex.numRowsRational(); ++i) 726 { 727 if(dual[i] != (Rational) 0) 728 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << rownames[i] << "\t" << dual[i] << std::endl;) 729 } 730 731 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other dual values are zero." << std::endl;) 732 733 VectorRational redcost(soplex.numCols()); 734 735 if(soplex.getRedCostRational(redcost)) 736 { 737 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nReduced costs (name, value):\n";) 738 739 for(int i = 0; i < soplex.numCols(); ++i) 740 { 741 if(redcost[i] != (Rational) 0) 742 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << colnames[i] << "\t" << redcost[i] << std::endl;) 743 } 744 745 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other reduced costs are zero." << std::endl;) 746 } 747 } 748 else 749 SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "No dual (rational) solution available.\n") 750 } 751 } 752 753 // Runs SoPlex with the parsed boost variables map 754 template <class R> 755 int runSoPlex(int argc, char* argv[]) 756 { 757 SoPlexBase<R>* soplex = nullptr; 758 759 Timer* readingTime = nullptr; 760 Validation<R>* validation = nullptr; 761 int optidx; 762 763 const char* lpfilename = nullptr; 764 char* readbasname = nullptr; 765 char* writebasname = nullptr; 766 char* writefilename = nullptr; 767 char* writedualfilename = nullptr; 768 char* loadsetname = nullptr; 769 char* savesetname = nullptr; 770 char* diffsetname = nullptr; 771 bool printPrimal = false; 772 bool printPrimalRational = false; 773 bool printDual = false; 774 bool printDualRational = false; 775 bool displayStatistics = false; 776 bool checkSol = false; 777 778 char* primalSolName = nullptr; 779 char* dualSolName = nullptr; 780 781 // names for solutions with rational numbers 782 char* primalSolNameRational = nullptr; 783 char* dualSolNameRational = nullptr; 784 785 int returnValue = 0; 786 787 try 788 { 789 NameSet rownames; 790 NameSet colnames; 791 792 // create default timer (CPU time) 793 readingTime = TimerFactory::createTimer(Timer::USER_TIME); 794 soplex = nullptr; 795 spx_alloc(soplex); 796 new(soplex) SoPlexBase<R>(); 797 798 soplex->printVersion(); 799 SPX_MSG_INFO1(soplex->spxout, soplex->spxout << SOPLEX_COPYRIGHT << std::endl << std::endl); 800 801 validation = nullptr; 802 spx_alloc(validation); 803 new(validation) Validation<R>(); 804 805 // no options were given 806 if(argc <= 1) 807 { 808 printUsage(argv, 0); 809 returnValue = 1; 810 goto TERMINATE; 811 } 812 813 // read arguments from command line 814 for(optidx = 1; optidx < argc; optidx++) 815 { 816 char* option = argv[optidx]; 817 818 // we reached <lpfile> 819 if(option[0] != '-') 820 { 821 lpfilename = argv[optidx]; 822 continue; 823 } 824 825 // option string must start with '-', must contain at least two characters, and exactly two characters if and 826 // only if it is -x, -y, -q, or -c 827 if(option[0] != '-' || option[1] == '\0' 828 || ((option[2] == '\0') != (option[1] == 'q' || option[1] == 'c'))) 829 { 830 printUsage(argv, optidx); 831 returnValue = 1; 832 goto TERMINATE_FREESTRINGS; 833 } 834 835 switch(option[1]) 836 { 837 case '-' : 838 { 839 option = &option[2]; 840 841 // --readbas=<basfile> : read starting basis from file 842 if(strncmp(option, "readbas=", 8) == 0) 843 { 844 if(readbasname == nullptr) 845 { 846 char* filename = &option[8]; 847 readbasname = new char[strlen(filename) + 1]; 848 spxSnprintf(readbasname, strlen(filename) + 1, "%s", filename); 849 } 850 } 851 // --writebas=<basfile> : write terminal basis to file 852 else if(strncmp(option, "writebas=", 9) == 0) 853 { 854 if(writebasname == nullptr) 855 { 856 char* filename = &option[9]; 857 writebasname = new char[strlen(filename) + 1]; 858 spxSnprintf(writebasname, strlen(filename) + 1, "%s", filename); 859 } 860 } 861 // --writefile=<lpfile> : write LP to file 862 else if(strncmp(option, "writefile=", 10) == 0) 863 { 864 if(writefilename == nullptr) 865 { 866 char* filename = &option[10]; 867 writefilename = new char[strlen(filename) + 1]; 868 spxSnprintf(writefilename, strlen(filename) + 1, "%s", filename); 869 } 870 } 871 // --writedual=<lpfile> : write dual LP to a file 872 else if(strncmp(option, "writedual=", 10) == 0) 873 { 874 if(writedualfilename == nullptr) 875 { 876 char* dualfilename = &option[10]; 877 writedualfilename = new char[strlen(dualfilename) + 1]; 878 spxSnprintf(writedualfilename, strlen(dualfilename) + 1, "%s", dualfilename); 879 } 880 } 881 // --loadset=<setfile> : load parameters from settings file 882 else if(strncmp(option, "loadset=", 8) == 0) 883 { 884 if(loadsetname == nullptr) 885 { 886 char* filename = &option[8]; 887 loadsetname = new char[strlen(filename) + 1]; 888 spxSnprintf(loadsetname, strlen(filename) + 1, "%s", filename); 889 890 if(!soplex->loadSettingsFile(loadsetname)) 891 { 892 printUsage(argv, optidx); 893 returnValue = 1; 894 goto TERMINATE_FREESTRINGS; 895 } 896 else 897 { 898 // we need to start parsing again because some command line parameters might have been overwritten 899 optidx = 0; 900 } 901 } 902 } 903 // --saveset=<setfile> : save parameters to settings file 904 else if(strncmp(option, "saveset=", 8) == 0) 905 { 906 if(savesetname == nullptr) 907 { 908 char* filename = &option[8]; 909 savesetname = new char[strlen(filename) + 1]; 910 spxSnprintf(savesetname, strlen(filename) + 1, "%s", filename); 911 } 912 } 913 // --diffset=<setfile> : save modified parameters to settings file 914 else if(strncmp(option, "diffset=", 8) == 0) 915 { 916 if(diffsetname == nullptr) 917 { 918 char* filename = &option[8]; 919 diffsetname = new char[strlen(filename) + 1]; 920 spxSnprintf(diffsetname, strlen(filename) + 1, "%s", filename); 921 } 922 } 923 // --readmode=<value> : choose reading mode for <lpfile> (0* - floating-point, 1 - rational) 924 else if(strncmp(option, "readmode=", 9) == 0) 925 { 926 if(!soplex->setIntParam(soplex->READMODE, option[9] - '0')) 927 { 928 printUsage(argv, optidx); 929 returnValue = 1; 930 goto TERMINATE_FREESTRINGS; 931 } 932 } 933 // --solvemode=<value> : choose solving mode (0* - floating-point solve, 1 - auto, 2 - force iterative refinement) 934 else if(strncmp(option, "solvemode=", 10) == 0) 935 { 936 if(!soplex->setIntParam(soplex->SOLVEMODE, option[10] - '0')) 937 { 938 printUsage(argv, optidx); 939 returnValue = 1; 940 goto TERMINATE_FREESTRINGS; 941 } 942 // if the LP is parsed rationally and might be solved rationally, we choose automatic syncmode such that 943 // the rational LP is kept after reading 944 else if(soplex->intParam(soplex->READMODE) == soplex->READMODE_RATIONAL 945 && soplex->intParam(soplex->SOLVEMODE) != soplex->SOLVEMODE_REAL) 946 { 947 soplex->setIntParam(soplex->SYNCMODE, soplex->SYNCMODE_AUTO); 948 } 949 } 950 // --extsol=<value> : external solution for soplex to use for validation 951 else if(strncmp(option, "extsol=", 7) == 0) 952 { 953 char* input = &option[7]; 954 955 if(!validation->updateExternalSolution(input)) 956 { 957 printUsage(argv, optidx); 958 returnValue = 1; 959 goto TERMINATE_FREESTRINGS; 960 } 961 } 962 // --arithmetic=<value> : base arithmetic type, directly handled in main() 963 else if(strncmp(option, "arithmetic=", 11) == 0) 964 { 965 continue; 966 } 967 // --precision=<value> : arithmetic precision, directly handled in main() 968 else if(strncmp(option, "precision=", 10) == 0) 969 { 970 continue; 971 } 972 // --<type>:<name>=<val> : change parameter value using syntax of settings file entries 973 else if(!soplex->parseSettingsString(option)) 974 { 975 printUsage(argv, optidx); 976 returnValue = 1; 977 goto TERMINATE_FREESTRINGS; 978 } 979 980 break; 981 } 982 983 case 't' : 984 985 // -t<s> : set time limit to <s> seconds 986 if(!soplex->setRealParam(soplex->TIMELIMIT, atoi(&option[2]))) 987 { 988 printUsage(argv, optidx); 989 returnValue = 1; 990 goto TERMINATE_FREESTRINGS; 991 } 992 993 break; 994 995 case 'i' : 996 997 // -i<n> : set iteration limit to <n> 998 if(!soplex->setIntParam(soplex->ITERLIMIT, atoi(&option[2]))) 999 { 1000 printUsage(argv, optidx); 1001 returnValue = 1; 1002 goto TERMINATE_FREESTRINGS; 1003 } 1004 1005 break; 1006 1007 case 'f' : 1008 1009 // -f<eps> : set primal feasibility tolerance to <eps> 1010 if(!soplex->setRealParam(soplex->FEASTOL, atof(&option[2]))) 1011 { 1012 printUsage(argv, optidx); 1013 returnValue = 1; 1014 goto TERMINATE_FREESTRINGS; 1015 } 1016 1017 break; 1018 1019 case 'o' : 1020 1021 // -o<eps> : set dual feasibility (optimality) tolerance to <eps> 1022 if(!soplex->setRealParam(soplex->OPTTOL, atof(&option[2]))) 1023 { 1024 printUsage(argv, optidx); 1025 returnValue = 1; 1026 goto TERMINATE_FREESTRINGS; 1027 } 1028 1029 break; 1030 1031 case 'l' : 1032 1033 // l<eps> : set validation tolerance to <eps> 1034 if(!validation->updateValidationTolerance(&option[2])) 1035 { 1036 printUsage(argv, optidx); 1037 returnValue = 1; 1038 goto TERMINATE_FREESTRINGS; 1039 } 1040 1041 break; 1042 1043 case 's' : 1044 1045 // -s<value> : choose simplifier/presolver (0 - off, 1 - internal, 2* - PaPILO) 1046 if(!soplex->setIntParam(soplex->SIMPLIFIER, option[2] - '0')) 1047 { 1048 printUsage(argv, optidx); 1049 returnValue = 1; 1050 goto TERMINATE_FREESTRINGS; 1051 } 1052 1053 break; 1054 1055 case 'g' : 1056 1057 // -g<value> : choose scaling (0 - off, 1 - uni-equilibrium, 2* - bi-equilibrium, 3 - geometric, 4 - iterated geometric, 5 - least squares, 6 - geometric-equilibrium) 1058 if(!soplex->setIntParam(soplex->SCALER, option[2] - '0')) 1059 { 1060 printUsage(argv, optidx); 1061 returnValue = 1; 1062 goto TERMINATE_FREESTRINGS; 1063 } 1064 1065 break; 1066 1067 case 'p' : 1068 1069 // -p<value> : choose pricing (0* - auto, 1 - dantzig, 2 - parmult, 3 - devex, 4 - quicksteep, 5 - steep) 1070 if(!soplex->setIntParam(soplex->PRICER, option[2] - '0')) 1071 { 1072 printUsage(argv, optidx); 1073 returnValue = 1; 1074 goto TERMINATE_FREESTRINGS; 1075 } 1076 1077 break; 1078 1079 case 'r' : 1080 1081 // -r<value> : choose ratio tester (0 - textbook, 1 - harris, 2* - fast, 3 - boundflipping) 1082 if(!soplex->setIntParam(soplex->RATIOTESTER, option[2] - '0')) 1083 { 1084 printUsage(argv, optidx); 1085 returnValue = 1; 1086 goto TERMINATE_FREESTRINGS; 1087 } 1088 1089 break; 1090 1091 case 'v' : 1092 1093 // -v<level> : set verbosity to <level> (0 - error, 3 - normal, 5 - high) 1094 if(!soplex->setIntParam(soplex->VERBOSITY, option[2] - '0')) 1095 { 1096 printUsage(argv, optidx); 1097 returnValue = 1; 1098 goto TERMINATE_FREESTRINGS; 1099 } 1100 1101 break; 1102 1103 case 'x' : 1104 // -x : print primal solution 1105 printPrimal = true; 1106 1107 if(strncmp(option, "-x=", 3) == 0) 1108 { 1109 if(primalSolName == nullptr) 1110 { 1111 char* filename = &option[3]; 1112 primalSolName = new char[strlen(filename) + 1]; 1113 spxSnprintf(primalSolName, strlen(filename) + 1, "%s", filename); 1114 } 1115 } 1116 1117 break; 1118 1119 case 'X' : 1120 // -X : print primal solution with rationals 1121 printPrimalRational = true; 1122 1123 if(strncmp(option, "-X=", 3) == 0) 1124 { 1125 if(primalSolNameRational == nullptr) 1126 { 1127 char* filename = &option[3]; 1128 primalSolNameRational = new char[strlen(filename) + 1]; 1129 spxSnprintf(primalSolNameRational, strlen(filename) + 1, "%s", filename); 1130 } 1131 } 1132 1133 break; 1134 1135 case 'y' : 1136 // -y : print dual multipliers 1137 printDual = true; 1138 1139 if(strncmp(option, "-y=", 3) == 0) 1140 { 1141 if(dualSolName == nullptr) 1142 { 1143 char* filename = &option[3]; 1144 dualSolName = new char[strlen(filename) + 1]; 1145 spxSnprintf(dualSolName, strlen(filename) + 1, "%s", filename); 1146 } 1147 } 1148 1149 break; 1150 1151 case 'Y' : 1152 // -Y : print dual multipliers with rationals 1153 printDualRational = true; 1154 1155 if(strncmp(option, "-Y=", 3) == 0) 1156 { 1157 if(dualSolNameRational == nullptr) 1158 { 1159 char* filename = &option[3]; 1160 dualSolNameRational = new char[strlen(filename) + 1]; 1161 spxSnprintf(dualSolNameRational, strlen(filename) + 1, "%s", filename); 1162 } 1163 } 1164 1165 break; 1166 1167 case 'q' : 1168 // -q : display detailed statistics 1169 displayStatistics = true; 1170 break; 1171 1172 case 'c' : 1173 // -c : perform final check of optimal solution in original problem 1174 checkSol = true; 1175 break; 1176 1177 case 'h' : 1178 1179 // -h : display all parameters 1180 if(!soplex->saveSettingsFile(0, false)) 1181 { 1182 SPX_MSG_ERROR(std::cerr << "Error printing parameters\n"); 1183 } 1184 1185 break; 1186 1187 //lint -fallthrough 1188 default : 1189 { 1190 printUsage(argv, optidx); 1191 returnValue = 1; 1192 goto TERMINATE_FREESTRINGS; 1193 } 1194 } 1195 } 1196 1197 SPX_MSG_INFO1(soplex->spxout, soplex->printUserSettings();) 1198 1199 // no LP file was given and no settings files are written 1200 if(lpfilename == nullptr && savesetname == nullptr && diffsetname == nullptr) 1201 { 1202 printUsage(argv, 0); 1203 returnValue = 1; 1204 goto TERMINATE_FREESTRINGS; 1205 } 1206 1207 // ensure that syncmode is not manual 1208 if(soplex->intParam(soplex->SYNCMODE) == soplex->SYNCMODE_MANUAL) 1209 { 1210 SPX_MSG_ERROR(std::cerr << 1211 "Error: manual synchronization is invalid on command line. Change parameter int:syncmode.\n"); 1212 returnValue = 1; 1213 goto TERMINATE_FREESTRINGS; 1214 } 1215 1216 // save settings files 1217 if(savesetname != nullptr) 1218 { 1219 SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "Saving parameters to settings file <" << 1220 savesetname << 1221 "> . . .\n"); 1222 1223 if(!soplex->saveSettingsFile(savesetname, false)) 1224 { 1225 SPX_MSG_ERROR(std::cerr << "Error writing parameters to file <" << savesetname << ">\n"); 1226 } 1227 } 1228 1229 if(diffsetname != nullptr) 1230 { 1231 SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "Saving modified parameters to settings file <" << 1232 diffsetname << "> . . .\n"); 1233 1234 if(!soplex->saveSettingsFile(diffsetname, true)) 1235 { 1236 SPX_MSG_ERROR(std::cerr << "Error writing modified parameters to file <" << diffsetname << ">\n"); 1237 } 1238 } 1239 1240 // no LP file given: exit after saving settings 1241 if(lpfilename == nullptr) 1242 { 1243 if(loadsetname != nullptr || savesetname != nullptr || diffsetname != nullptr) 1244 { 1245 SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "\n"); 1246 } 1247 1248 goto TERMINATE_FREESTRINGS; 1249 } 1250 1251 // measure time for reading LP file and basis file 1252 readingTime->start(); 1253 1254 // if the LP is parsed rationally and might be solved rationally, we choose automatic syncmode such that 1255 // the rational LP is kept after reading 1256 if(soplex->intParam(soplex->READMODE) == soplex->READMODE_RATIONAL 1257 && soplex->intParam(soplex->SOLVEMODE) != soplex->SOLVEMODE_REAL) 1258 { 1259 soplex->setIntParam(soplex->SYNCMODE, soplex->SYNCMODE_AUTO); 1260 } 1261 1262 // read LP from input file 1263 SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "Reading " 1264 << (soplex->intParam(soplex->READMODE) == soplex->READMODE_REAL ? "(real)" : "(rational)") 1265 << " LP file <" << lpfilename << "> . . .\n"); 1266 1267 if(!soplex->readFile(lpfilename, &rownames, &colnames)) 1268 { 1269 SPX_MSG_ERROR(std::cerr << "Error while reading file <" << lpfilename << ">.\n"); 1270 returnValue = 1; 1271 goto TERMINATE_FREESTRINGS; 1272 } 1273 1274 // write LP if specified 1275 if(writefilename != nullptr) 1276 { 1277 if(!soplex->writeFile(writefilename, &rownames, &colnames)) 1278 { 1279 SPX_MSG_ERROR(std::cerr << "Error while writing file <" << writefilename << ">.\n\n"); 1280 returnValue = 1; 1281 goto TERMINATE_FREESTRINGS; 1282 } 1283 else 1284 { 1285 SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "Written LP to file <" << writefilename << 1286 ">.\n\n"); 1287 } 1288 } 1289 1290 // write dual LP if specified 1291 if(writedualfilename != nullptr) 1292 { 1293 if(!soplex->writeDualFileReal(writedualfilename, &rownames, &colnames)) 1294 { 1295 SPX_MSG_ERROR(std::cerr << "Error while writing dual file <" << writedualfilename << ">.\n\n"); 1296 returnValue = 1; 1297 goto TERMINATE_FREESTRINGS; 1298 } 1299 else 1300 { 1301 SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "Written dual LP to file <" << writedualfilename << 1302 ">.\n\n"); 1303 } 1304 } 1305 1306 // read basis file if specified 1307 if(readbasname != nullptr) 1308 { 1309 SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "Reading basis file <" << readbasname << 1310 "> . . . "); 1311 1312 if(!soplex->readBasisFile(readbasname, &rownames, &colnames)) 1313 { 1314 SPX_MSG_ERROR(std::cerr << "Error while reading file <" << readbasname << ">.\n"); 1315 returnValue = 1; 1316 goto TERMINATE_FREESTRINGS; 1317 } 1318 } 1319 1320 readingTime->stop(); 1321 1322 SPX_MSG_INFO1(soplex->spxout, 1323 std::streamsize prec = soplex->spxout.precision(); 1324 soplex->spxout << "Reading took " 1325 << std::fixed << std::setprecision(2) << readingTime->time() 1326 << std::scientific << std::setprecision(int(prec)) 1327 << " seconds.\n\n"); 1328 1329 SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "LP has " << soplex->numRows() << " rows " 1330 << soplex->numCols() << " columns and " << soplex->numNonzeros() << " nonzeros.\n\n"); 1331 1332 // solve the LP 1333 soplex->optimize(); 1334 1335 // print solution to stdout, check solution, and display statistics 1336 if(primalSolName == nullptr && primalSolNameRational == nullptr) 1337 printPrimalSolution(*soplex, colnames, rownames, printPrimal, printPrimalRational); 1338 1339 // print fp solution to file primalSolName 1340 if(primalSolName != nullptr) 1341 writePrimalSolution(*soplex, primalSolName, colnames, rownames, true, false, false); 1342 1343 bool append; 1344 1345 // print rational solution to file primalSolNameRational 1346 if(primalSolNameRational != nullptr) 1347 { 1348 append = primalSolName != nullptr && strcmp(primalSolName, primalSolNameRational) == 0; 1349 writePrimalSolution(*soplex, primalSolNameRational, colnames, rownames, false, true, append); 1350 } 1351 1352 // print dual solution to stdout, check solution, and display statistics 1353 if(dualSolName == nullptr && dualSolNameRational == nullptr) 1354 printDualSolution(*soplex, colnames, rownames, printDual, printDualRational); 1355 1356 // print fp solution to file dualSolName 1357 if(dualSolName != nullptr) 1358 { 1359 append = primalSolName != nullptr && strcmp(dualSolName, primalSolName) == 0; 1360 append = append || (primalSolNameRational != nullptr 1361 && strcmp(dualSolName, primalSolNameRational) == 0); 1362 writeDualSolution(*soplex, dualSolName, colnames, rownames, true, false, append); 1363 } 1364 1365 // print rational solution to file dualSolNameRational 1366 if(dualSolNameRational != nullptr) 1367 { 1368 append = (primalSolName != nullptr && strcmp(dualSolNameRational, primalSolName) == 0); 1369 append = append || (primalSolNameRational != nullptr 1370 && strcmp(dualSolNameRational, primalSolNameRational) == 0); 1371 append = append || (dualSolName != nullptr && strcmp(dualSolNameRational, dualSolName) == 0); 1372 writeDualSolution(*soplex, dualSolNameRational, colnames, rownames, false, true, append); 1373 } 1374 1375 if(checkSol) 1376 checkSolution<R>(*soplex); // The type needs to get fixed here 1377 1378 if(displayStatistics) 1379 { 1380 SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "Statistics\n==========\n\n"); 1381 soplex->printStatistics(soplex->spxout.getStream(SPxOut::INFO1)); 1382 } 1383 1384 if(validation->validate) 1385 validation->validateSolveReal(*soplex); 1386 1387 // write basis file if specified 1388 if(writebasname != nullptr) 1389 { 1390 if(!soplex->hasBasis()) 1391 { 1392 SPX_MSG_WARNING(soplex->spxout, soplex->spxout << 1393 "No basis information available. Could not write file <" << writebasname << ">\n\n"); 1394 } 1395 else if(!soplex->writeBasisFile(writebasname, &rownames, &colnames)) 1396 { 1397 SPX_MSG_ERROR(std::cerr << "Error while writing file <" << writebasname << ">.\n\n"); 1398 returnValue = 1; 1399 goto TERMINATE_FREESTRINGS; 1400 } 1401 else 1402 { 1403 SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "Written basis information to file <" << 1404 writebasname << 1405 ">.\n\n"); 1406 } 1407 } 1408 } 1409 catch(const SPxException& x) 1410 { 1411 SPX_MSG_ERROR(std::cerr << "Exception caught: " << x.what() << "\n"); 1412 returnValue = 1; 1413 goto TERMINATE_FREESTRINGS; 1414 } 1415 1416 TERMINATE_FREESTRINGS: 1417 freeStrings(readbasname, writebasname, loadsetname, savesetname, diffsetname); 1418 freeStrings(primalSolName, dualSolName, primalSolName, primalSolName, primalSolName); 1419 1420 TERMINATE: 1421 1422 // because EGlpNumClear() calls mpq_clear() for all mpq_t variables, we need to destroy all objects of class Rational 1423 // beforehand; hence all Rational objects and all data that uses Rational objects must be allocated dynamically via 1424 // spx_alloc() and freed here; disabling the list memory is crucial 1425 if(nullptr != soplex) 1426 { 1427 soplex->~SoPlexBase(); 1428 spx_free(soplex); 1429 } 1430 1431 if(nullptr != validation) 1432 { 1433 validation->~Validation(); 1434 spx_free(validation); 1435 } 1436 1437 if(nullptr != readingTime) 1438 { 1439 readingTime->~Timer(); 1440 spx_free(readingTime); 1441 } 1442 1443 return returnValue; 1444 } 1445 1446 /// runs SoPlexBase command line 1447 int main(int argc, char* argv[]) 1448 { 1449 int arithmetic = 0; 1450 int precision = 0; 1451 int optidx; 1452 1453 // find out which precision/solvemode soplex should be run in. the rest happens in runSoPlex 1454 // no options were given 1455 if(argc <= 1) 1456 { 1457 printUsage(argv, 0); 1458 return 1; 1459 } 1460 1461 // read arguments from command line 1462 for(optidx = 1; optidx < argc; optidx++) 1463 { 1464 char* option = argv[optidx]; 1465 1466 // we reached <lpfile> 1467 if(option[0] != '-') 1468 continue; 1469 1470 // option string must start with '-', must contain at least two characters, and exactly two characters if and 1471 // only if it is -q, or -c 1472 if(option[0] != '-' || option[1] == '\0' 1473 || ((option[2] == '\0') != (option[1] == 'q' || option[1] == 'c'))) 1474 { 1475 printUsage(argv, optidx); 1476 return 1; 1477 } 1478 1479 switch(option[1]) 1480 { 1481 case '-' : 1482 option = &option[2]; 1483 1484 // --arithmetic=<value> : choose base arithmetic type (0 - double, 1 - quadprecision, 2 - higher multiprecision) 1485 // only need to do something here if multi or quad, the rest is handled in runSoPlex 1486 if(strncmp(option, "arithmetic=", 11) == 0) 1487 { 1488 if(option[11] == '1') 1489 { 1490 #ifndef SOPLEX_WITH_FLOAT128 1491 SPX_MSG_ERROR(std::cerr << 1492 "Cannot set arithmetic type to quadprecision - Soplex compiled without quadprecision support\n";) 1493 printUsage(argv, 0); 1494 return 1; 1495 #else 1496 arithmetic = 1; 1497 #endif 1498 } 1499 else if(option[11] == '2') 1500 { 1501 #ifndef SOPLEX_WITH_BOOST 1502 SPX_MSG_ERROR(std::cerr << 1503 "Cannot set arithmetic type to multiprecision - Soplex compiled without boost\n";) 1504 printUsage(argv, 0); 1505 return 1; 1506 #else 1507 arithmetic = 2; 1508 1509 // default precision in multiprecision solve is 50 1510 if(precision == 0) 1511 precision = 50; 1512 1513 #endif 1514 } 1515 } 1516 // set precision 1517 else if(strncmp(option, "precision=", 10) == 0) 1518 { 1519 precision = atoi(option + 10); 1520 #ifndef SOPLEX_WITH_BOOST 1521 SPX_MSG_ERROR(std::cerr << "Setting precision to non-default value without Boost has no effect\n";) 1522 #endif 1523 } 1524 1525 break; 1526 1527 default: 1528 break; 1529 } 1530 } 1531 1532 if(precision != 0 && arithmetic != 2) 1533 { 1534 SPX_MSG_ERROR(std::cerr << 1535 "Setting precision to non-default value without enabling multiprecision solve has no effect\n";) 1536 } 1537 1538 switch(arithmetic) 1539 { 1540 case 0: // double 1541 runSoPlex<Real>(argc, argv); 1542 break; 1543 1544 #ifdef SOPLEX_WITH_BOOST 1545 #ifdef SOPLEX_WITH_FLOAT128 1546 1547 case 1: // quadprecision 1548 #if BOOST_VERSION < 107000 1549 std::cerr << "Error: Boost version too old." << std:: endl << 1550 "In order to use the quadprecision feature of SoPlex," << 1551 " Boost Version 1.70.0 or higher is required." << std::endl << \ 1552 "Included Boost version is " << BOOST_VERSION / 100000 << "." // maj. version 1553 << BOOST_VERSION / 100 % 1000 << "." // min. version 1554 << BOOST_VERSION % 100 // patch version; 1555 << std::endl; 1556 #else 1557 using namespace boost::multiprecision; 1558 using Quad = boost::multiprecision::float128; 1559 runSoPlex<Quad>(argc, argv); 1560 #endif 1561 break; 1562 #endif 1563 1564 case 2: // soplex mpf 1565 using namespace boost::multiprecision; 1566 1567 #if BOOST_VERSION < 107000 1568 std::cerr << "Error: Boost version too old." << std:: endl << 1569 "In order to use the multiprecision feature of SoPlex," << 1570 " Boost Version 1.70.0 or higher is required." << std::endl << \ 1571 "Included Boost version is " << BOOST_VERSION / 100000 << "." // maj. version 1572 << BOOST_VERSION / 100 % 1000 << "." // min. version 1573 << BOOST_VERSION % 100 // patch version; 1574 << std::endl; 1575 #else 1576 #ifdef SOPLEX_WITH_MPFR 1577 1578 // et_off means the expression templates options is turned off. TODO: 1579 // The documentation also mentions about static vs dynamic memory 1580 // allocation for the mpfr types. Is it relevant here? I probably also 1581 // need to have the mpfr_float_eto in the global soplex namespace 1582 using multiprecision = number<mpfr_float_backend<0>, et_off>; 1583 multiprecision::default_precision(precision); 1584 runSoPlex<multiprecision>(argc, argv); 1585 #endif // SOPLEX_WITH_MPFR 1586 1587 #ifdef SOPLEX_WITH_CPPMPF 1588 // It seems that precision cannot be set on run time for cpp_float 1589 // backend for boost::number. So a precision of 50 decimal points is 1590 // set. 1591 using multiprecision1 = number<cpp_dec_float<50>, et_off>; 1592 using multiprecision2 = number<cpp_dec_float<100>, et_off>; 1593 using multiprecision3 = number<cpp_dec_float<200>, et_off>; 1594 1595 if(precision <= 50) 1596 runSoPlex<multiprecision1>(argc, argv); 1597 else if(precision <= 100) 1598 runSoPlex<multiprecision2>(argc, argv); 1599 else 1600 runSoPlex<multiprecision3>(argc, argv); 1601 1602 #endif // SOPLEX_WITH_CPPMPF 1603 #endif 1604 break; 1605 #endif 1606 1607 // coverity[dead_error_begin] 1608 default: 1609 std::cerr << "Wrong value for the arithmetic mode\n"; 1610 return 0; 1611 } 1612 } 1613