SoPlex Documentation
Loading...
Searching...
No Matches
soplexmain.cpp
Go to the documentation of this file.
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
40using namespace soplex;
41
42// function prototype
43int main(int argc, char* argv[]);
44
45// prints usage and command line options
46static
47void 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 print primal solution\n"
86 " -y print dual multipliers\n"
87 " -X print primal solution in rational numbers\n"
88 " -Y print dual multipliers in rational numbers\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
108static
109void 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
145template <class R>
146static
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 MSG_INFO1(soplex.spxout,
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 MSG_INFO1(soplex.spxout, soplex.spxout << "Could not check primal solution.\n");
167 }
168 }
169 else
170 {
171 MSG_INFO1(soplex.spxout, soplex.spxout << "No primal solution available.\n");
172 }
173
174 if(soplex.hasDual())
175 {
177 R dualviol;
178 R sumviol;
179
180 if(soplex.getRedCostViolation(redcostviol, sumviol) && soplex.getDualViolation(dualviol, sumviol))
181 {
182 MSG_INFO1(soplex.spxout,
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 MSG_INFO1(soplex.spxout, soplex.spxout << "Could not check dual solution.\n");
193 }
194 }
195 else
196 {
197 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
203template <class R>
205{
206 if(soplex.hasPrimal())
207 {
211
212 if(soplex.getBoundViolationRational(boundviol, sumviol)
213 && soplex.getRowViolationRational(rowviol, sumviol))
214 {
215 MSG_INFO1(soplex.spxout,
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 MSG_INFO1(soplex.spxout, soplex.spxout << "Could not check primal solution.\n");
225 }
226 }
227 else
228 {
229 MSG_INFO1(soplex.spxout, soplex.spxout << "No primal solution available.\n");
230 }
231
232 if(soplex.hasDual())
233 {
237
238 if(soplex.getRedCostViolationRational(redcostviol, sumviol)
239 && soplex.getDualViolationRational(dualviol, sumviol))
240 {
241 MSG_INFO1(soplex.spxout,
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 MSG_INFO1(soplex.spxout, soplex.spxout << "Could not check dual solution.\n");
251 }
252 }
253 else
254 {
255 MSG_INFO1(soplex.spxout, soplex.spxout << "No dual solution available.\n");
256 }
257}
258
259/// performs external feasibility check according to check mode
260template <class R>
276
277template <class R>
278static
280 bool real = true, bool rational = false)
281{
282 int printprec;
283 int printwidth;
285 printwidth = printprec + 10;
286
287 if(real)
288 {
289 VectorBase<R> primal(soplex.numCols());
290
291 if(soplex.getPrimalRay(primal))
292 {
293 MSG_INFO1(soplex.spxout, soplex.spxout << "\nPrimal ray (name, value):\n";)
294
295 for(int i = 0; i < soplex.numCols(); ++i)
296 {
297 if(isNotZero(primal[i]))
298 {
299 MSG_INFO1(soplex.spxout, soplex.spxout << colnames[i] << "\t"
300 << std::setw(printwidth) << std::setprecision(printprec)
301 << primal[i] << std::endl;)
302 }
303 }
304
305 MSG_INFO1(soplex.spxout, soplex.spxout << "All other entries are zero (within "
306 << std::setprecision(1) << std::scientific << Param::epsilon()
307 << std::setprecision(8) << std::fixed
308 << ")." << std::endl;)
309 }
310 else if(soplex.isPrimalFeasible() && soplex.getPrimal(primal))
311 {
312 int nNonzeros = 0;
313 MSG_INFO1(soplex.spxout, soplex.spxout << "\nPrimal solution (name, value):\n";)
314
315 for(int i = 0; i < soplex.numCols(); ++i)
316 {
317 if(isNotZero(primal[i]))
318 {
319 MSG_INFO1(soplex.spxout, soplex.spxout << colnames[i] << "\t"
320 << std::setw(printwidth) << std::setprecision(printprec)
321 << primal[i] << std::endl;)
322 ++nNonzeros;
323 }
324 }
325
326 MSG_INFO1(soplex.spxout, soplex.spxout << "All other variables are zero (within "
327 << std::setprecision(1) << std::scientific << Param::epsilon()
328 << std::setprecision(8) << std::fixed
329 << "). Solution has " << nNonzeros << " nonzero entries." << std::endl;)
330 }
331 else
332 MSG_INFO1(soplex.spxout, soplex.spxout << "No primal information available.\n")
333 }
334
335 if(rational)
336 {
337 VectorRational primal(soplex.numCols());
338
339 if(soplex.getPrimalRayRational(primal))
340 {
341 MSG_INFO1(soplex.spxout, soplex.spxout << "\nPrimal ray (name, value):\n";)
342
343 for(int i = 0; i < soplex.numCols(); ++i)
344 {
345 if(primal[i] != (Rational) 0)
346 {
347 MSG_INFO1(soplex.spxout, soplex.spxout << colnames[i] << "\t"
348 << std::setw(printwidth) << std::setprecision(printprec)
349 << primal[i] << std::endl;)
350 }
351 }
352
353 MSG_INFO1(soplex.spxout, soplex.spxout << "All other entries are zero." << std::endl;)
354 }
355
356 if(soplex.isPrimalFeasible() && soplex.getPrimalRational(primal))
357 {
358 int nNonzeros = 0;
359 MSG_INFO1(soplex.spxout, soplex.spxout << "\nPrimal solution (name, value):\n";)
360
361 for(int i = 0; i < soplex.numColsRational(); ++i)
362 {
363 if(primal[i] != (Rational) 0)
364 {
365 MSG_INFO1(soplex.spxout, soplex.spxout << colnames[i] << "\t" << primal[i] << std::endl;)
366 ++nNonzeros;
367 }
368 }
369
370 MSG_INFO1(soplex.spxout, soplex.spxout << "All other variables are zero. Solution has "
371 << nNonzeros << " nonzero entries." << std::endl;)
372 }
373 else
374 MSG_INFO1(soplex.spxout, soplex.spxout << "No primal (rational) solution available.\n")
375
376 }
377}
378
379template <class R>
380static
382 bool real = true, bool rational = false)
383{
384 int printprec;
385 int printwidth;
387 printwidth = printprec + 10;
388
389 if(real)
390 {
391 VectorBase<R> dual(soplex.numRows());
392
393 if(soplex.getDualFarkas(dual))
394 {
395 MSG_INFO1(soplex.spxout, soplex.spxout << "\nDual ray (name, value):\n";)
396
397 for(int i = 0; i < soplex.numRows(); ++i)
398 {
399 if(isNotZero(dual[i]))
400 {
401 MSG_INFO1(soplex.spxout, soplex.spxout << rownames[i] << "\t"
402 << std::setw(printwidth) << std::setprecision(printprec)
403 << dual[i] << std::endl;)
404 }
405 }
406
407 MSG_INFO1(soplex.spxout, soplex.spxout << "All other entries are zero (within "
408 << std::setprecision(1) << std::scientific << Param::epsilon()
409 << std::setprecision(8) << std::fixed << ")." << std::endl;)
410 }
411 else if(soplex.isDualFeasible() && soplex.getDual(dual))
412 {
413 MSG_INFO1(soplex.spxout, soplex.spxout << "\nDual solution (name, value):\n";)
414
415 for(int i = 0; i < soplex.numRows(); ++i)
416 {
417 if(isNotZero(dual[i]))
418 {
419 MSG_INFO1(soplex.spxout, soplex.spxout << rownames[i] << "\t"
420 << std::setw(printwidth) << std::setprecision(printprec)
421 << dual[i] << std::endl;)
422 }
423 }
424
425 MSG_INFO1(soplex.spxout, soplex.spxout << "All other dual values are zero (within "
426 << std::setprecision(1) << std::scientific << Param::epsilon()
427 << std::setprecision(8) << std::fixed << ")." << std::endl;)
428
429 VectorBase<R> redcost(soplex.numCols());
430
431 if(soplex.getRedCost(redcost))
432 {
433 MSG_INFO1(soplex.spxout, soplex.spxout << "\nReduced costs (name, value):\n";)
434
435 for(int i = 0; i < soplex.numCols(); ++i)
436 {
437 if(isNotZero(redcost[i]))
438 {
439 MSG_INFO1(soplex.spxout, soplex.spxout << colnames[i] << "\t"
440 << std::setw(printwidth) << std::setprecision(printprec)
441 << redcost[i] << std::endl;)
442 }
443 }
444
445 MSG_INFO1(soplex.spxout, soplex.spxout << "All other reduced costs are zero (within "
446 << std::setprecision(1) << std::scientific << Param::epsilon()
447 << std::setprecision(8) << std::fixed << ")." << std::endl;)
448 }
449 }
450 else
451 MSG_INFO1(soplex.spxout, soplex.spxout << "No dual information available.\n")
452 }
453
454 if(rational)
455 {
456 VectorRational dual(soplex.numRows());
457
458 if(soplex.getDualFarkasRational(dual))
459 {
460 MSG_INFO1(soplex.spxout, soplex.spxout << "\nDual ray (name, value):\n";)
461
462 for(int i = 0; i < soplex.numRows(); ++i)
463 {
464 if(dual[i] != (Rational) 0)
465 {
466 MSG_INFO1(soplex.spxout, soplex.spxout << rownames[i] << "\t"
467 << std::setw(printwidth)
468 << std::setprecision(printprec)
469 << dual[i] << std::endl;)
470 }
471 }
472
473 MSG_INFO1(soplex.spxout, soplex.spxout << "All other entries are zero." << std::endl;)
474 }
475
476 if(soplex.isDualFeasible() && soplex.getDualRational(dual))
477 {
478 MSG_INFO1(soplex.spxout, soplex.spxout << "\nDual solution (name, value):\n";)
479
480 for(int i = 0; i < soplex.numRowsRational(); ++i)
481 {
482 if(dual[i] != (Rational) 0)
483 MSG_INFO1(soplex.spxout, soplex.spxout << rownames[i] << "\t" << dual[i] << std::endl;)
484 }
485
486 MSG_INFO1(soplex.spxout, soplex.spxout << "All other dual values are zero." << std::endl;)
487
488 VectorRational redcost(soplex.numCols());
489
490 if(soplex.getRedCostRational(redcost))
491 {
492 MSG_INFO1(soplex.spxout, soplex.spxout << "\nReduced costs (name, value):\n";)
493
494 for(int i = 0; i < soplex.numCols(); ++i)
495 {
496 if(redcost[i] != (Rational) 0)
497 MSG_INFO1(soplex.spxout, soplex.spxout << colnames[i] << "\t" << redcost[i] << std::endl;)
498 }
499
500 MSG_INFO1(soplex.spxout, soplex.spxout << "All other reduced costs are zero." << std::endl;)
501 }
502 }
503 else
504 MSG_INFO1(soplex.spxout, soplex.spxout << "No dual (rational) solution available.\n")
505 }
506}
507
508// Runs SoPlex with the parsed boost variables map
509template <class R>
510int runSoPlex(int argc, char* argv[])
511{
512 SoPlexBase<R>* soplex = nullptr;
513
514 Timer* readingTime = nullptr;
515 Validation<R>* validation = nullptr;
516 int optidx;
517
518 const char* lpfilename = nullptr;
519 char* readbasname = nullptr;
520 char* writebasname = nullptr;
521 char* writefilename = nullptr;
522 char* writedualfilename = nullptr;
523 char* loadsetname = nullptr;
524 char* savesetname = nullptr;
525 char* diffsetname = nullptr;
526 bool printPrimal = false;
527 bool printPrimalRational = false;
528 bool printDual = false;
529 bool printDualRational = false;
530 bool displayStatistics = false;
531 bool checkSol = false;
532
533 int returnValue = 0;
534
535 try
536 {
539
540 // create default timer (CPU time)
542 soplex = nullptr;
544 new(soplex) SoPlexBase<R>();
545
546 soplex->printVersion();
547 MSG_INFO1(soplex->spxout, soplex->spxout << SOPLEX_COPYRIGHT << std::endl << std::endl);
548
549 validation = nullptr;
552
553 // no options were given
554 if(argc <= 1)
555 {
556 printUsage(argv, 0);
557 returnValue = 1;
558 goto TERMINATE;
559 }
560
561 // read arguments from command line
562 for(optidx = 1; optidx < argc; optidx++)
563 {
564 char* option = argv[optidx];
565
566 // we reached <lpfile>
567 if(option[0] != '-')
568 {
570 continue;
571 }
572
573 // option string must start with '-', must contain at least two characters, and exactly two characters if and
574 // only if it is -x, -y, -q, or -c
575 if(option[0] != '-' || option[1] == '\0'
576 || ((option[2] == '\0') != (option[1] == 'x' || option[1] == 'X' || option[1] == 'y'
577 || option[1] == 'Y' || option[1] == 'q' || option[1] == 'c')))
578 {
580 returnValue = 1;
582 }
583
584 switch(option[1])
585 {
586 case '-' :
587 {
588 option = &option[2];
589
590 // --readbas=<basfile> : read starting basis from file
591 if(strncmp(option, "readbas=", 8) == 0)
592 {
593 if(readbasname == nullptr)
594 {
595 char* filename = &option[8];
596 readbasname = new char[strlen(filename) + 1];
598 }
599 }
600 // --writebas=<basfile> : write terminal basis to file
601 else if(strncmp(option, "writebas=", 9) == 0)
602 {
603 if(writebasname == nullptr)
604 {
605 char* filename = &option[9];
606 writebasname = new char[strlen(filename) + 1];
608 }
609 }
610 // --writefile=<lpfile> : write LP to file
611 else if(strncmp(option, "writefile=", 10) == 0)
612 {
613 if(writefilename == nullptr)
614 {
615 char* filename = &option[10];
616 writefilename = new char[strlen(filename) + 1];
618 }
619 }
620 // --writedual=<lpfile> : write dual LP to a file
621 else if(strncmp(option, "writedual=", 10) == 0)
622 {
623 if(writedualfilename == nullptr)
624 {
625 char* dualfilename = &option[10];
626 writedualfilename = new char[strlen(dualfilename) + 1];
628 }
629 }
630 // --loadset=<setfile> : load parameters from settings file
631 else if(strncmp(option, "loadset=", 8) == 0)
632 {
633 if(loadsetname == nullptr)
634 {
635 char* filename = &option[8];
636 loadsetname = new char[strlen(filename) + 1];
638
639 if(!soplex->loadSettingsFile(loadsetname))
640 {
642 returnValue = 1;
644 }
645 else
646 {
647 // we need to start parsing again because some command line parameters might have been overwritten
648 optidx = 0;
649 }
650 }
651 }
652 // --saveset=<setfile> : save parameters to settings file
653 else if(strncmp(option, "saveset=", 8) == 0)
654 {
655 if(savesetname == nullptr)
656 {
657 char* filename = &option[8];
658 savesetname = new char[strlen(filename) + 1];
660 }
661 }
662 // --diffset=<setfile> : save modified parameters to settings file
663 else if(strncmp(option, "diffset=", 8) == 0)
664 {
665 if(diffsetname == nullptr)
666 {
667 char* filename = &option[8];
668 diffsetname = new char[strlen(filename) + 1];
670 }
671 }
672 // --readmode=<value> : choose reading mode for <lpfile> (0* - floating-point, 1 - rational)
673 else if(strncmp(option, "readmode=", 9) == 0)
674 {
675 if(!soplex->setIntParam(soplex->READMODE, option[9] - '0'))
676 {
678 returnValue = 1;
680 }
681 }
682 // --solvemode=<value> : choose solving mode (0* - floating-point solve, 1 - auto, 2 - force iterative refinement)
683 else if(strncmp(option, "solvemode=", 10) == 0)
684 {
685 if(!soplex->setIntParam(soplex->SOLVEMODE, option[10] - '0'))
686 {
688 returnValue = 1;
690 }
691 // if the LP is parsed rationally and might be solved rationally, we choose automatic syncmode such that
692 // the rational LP is kept after reading
693 else if(soplex->intParam(soplex->READMODE) == soplex->READMODE_RATIONAL
694 && soplex->intParam(soplex->SOLVEMODE) != soplex->SOLVEMODE_REAL)
695 {
696 soplex->setIntParam(soplex->SYNCMODE, soplex->SYNCMODE_AUTO);
697 }
698 }
699 // --extsol=<value> : external solution for soplex to use for validation
700 else if(strncmp(option, "extsol=", 7) == 0)
701 {
702 char* input = &option[7];
703
704 if(!validation->updateExternalSolution(input))
705 {
707 returnValue = 1;
709 }
710 }
711 // --arithmetic=<value> : base arithmetic type, directly handled in main()
712 else if(strncmp(option, "arithmetic=", 11) == 0)
713 {
714 continue;
715 }
716 // --precision=<value> : arithmetic precision, directly handled in main()
717 else if(strncmp(option, "precision=", 10) == 0)
718 {
719 continue;
720 }
721 // --<type>:<name>=<val> : change parameter value using syntax of settings file entries
722 else if(!soplex->parseSettingsString(option))
723 {
725 returnValue = 1;
727 }
728
729 break;
730 }
731
732 case 't' :
733
734 // -t<s> : set time limit to <s> seconds
735 if(!soplex->setRealParam(soplex->TIMELIMIT, atoi(&option[2])))
736 {
738 returnValue = 1;
740 }
741
742 break;
743
744 case 'i' :
745
746 // -i<n> : set iteration limit to <n>
747 if(!soplex->setIntParam(soplex->ITERLIMIT, atoi(&option[2])))
748 {
750 returnValue = 1;
752 }
753
754 break;
755
756 case 'f' :
757
758 // -f<eps> : set primal feasibility tolerance to <eps>
759 if(!soplex->setRealParam(soplex->FEASTOL, atof(&option[2])))
760 {
762 returnValue = 1;
764 }
765
766 break;
767
768 case 'o' :
769
770 // -o<eps> : set dual feasibility (optimality) tolerance to <eps>
771 if(!soplex->setRealParam(soplex->OPTTOL, atof(&option[2])))
772 {
774 returnValue = 1;
776 }
777
778 break;
779
780 case 'l' :
781
782 // l<eps> : set validation tolerance to <eps>
783 if(!validation->updateValidationTolerance(&option[2]))
784 {
786 returnValue = 1;
788 }
789
790 break;
791
792 case 's' :
793
794 // -s<value> : choose simplifier/presolver (0 - off, 1 - internal, 2* - PaPILO)
795 if(!soplex->setIntParam(soplex->SIMPLIFIER, option[2] - '0'))
796 {
798 returnValue = 1;
800 }
801
802 break;
803
804 case 'g' :
805
806 // -g<value> : choose scaling (0 - off, 1 - uni-equilibrium, 2* - bi-equilibrium, 3 - geometric, 4 - iterated geometric, 5 - least squares, 6 - geometric-equilibrium)
807 if(!soplex->setIntParam(soplex->SCALER, option[2] - '0'))
808 {
810 returnValue = 1;
812 }
813
814 break;
815
816 case 'p' :
817
818 // -p<value> : choose pricing (0* - auto, 1 - dantzig, 2 - parmult, 3 - devex, 4 - quicksteep, 5 - steep)
819 if(!soplex->setIntParam(soplex->PRICER, option[2] - '0'))
820 {
822 returnValue = 1;
824 }
825
826 break;
827
828 case 'r' :
829
830 // -r<value> : choose ratio tester (0 - textbook, 1 - harris, 2* - fast, 3 - boundflipping)
831 if(!soplex->setIntParam(soplex->RATIOTESTER, option[2] - '0'))
832 {
834 returnValue = 1;
836 }
837
838 break;
839
840 case 'v' :
841
842 // -v<level> : set verbosity to <level> (0 - error, 3 - normal, 5 - high)
843 if(!soplex->setIntParam(soplex->VERBOSITY, option[2] - '0'))
844 {
846 returnValue = 1;
848 }
849
850 break;
851
852 case 'x' :
853 // -x : print primal solution
854 printPrimal = true;
855 break;
856
857 case 'X' :
858 // -X : print primal solution with rationals
859 printPrimalRational = true;
860 break;
861
862 case 'y' :
863 // -y : print dual multipliers
864 printDual = true;
865 break;
866
867 case 'Y' :
868 // -Y : print dual multipliers with rationals
869 printDualRational = true;
870 break;
871
872 case 'q' :
873 // -q : display detailed statistics
874 displayStatistics = true;
875 break;
876
877 case 'c' :
878 // -c : perform final check of optimal solution in original problem
879 checkSol = true;
880 break;
881
882 case 'h' :
883
884 // -h : display all parameters
885 if(!soplex->saveSettingsFile(0, false))
886 {
887 MSG_ERROR(std::cerr << "Error printing parameters\n");
888 }
889
890 break;
891
892 //lint -fallthrough
893 default :
894 {
896 returnValue = 1;
898 }
899 }
900 }
901
902 MSG_INFO1(soplex->spxout, soplex->printUserSettings();)
903
904 // no LP file was given and no settings files are written
905 if(lpfilename == nullptr && savesetname == nullptr && diffsetname == nullptr)
906 {
907 printUsage(argv, 0);
908 returnValue = 1;
910 }
911
912 // ensure that syncmode is not manual
913 if(soplex->intParam(soplex->SYNCMODE) == soplex->SYNCMODE_MANUAL)
914 {
915 MSG_ERROR(std::cerr <<
916 "Error: manual synchronization is invalid on command line. Change parameter int:syncmode.\n");
917 returnValue = 1;
919 }
920
921 // save settings files
922 if(savesetname != nullptr)
923 {
924 MSG_INFO1(soplex->spxout, soplex->spxout << "Saving parameters to settings file <" << savesetname <<
925 "> . . .\n");
926
927 if(!soplex->saveSettingsFile(savesetname, false))
928 {
929 MSG_ERROR(std::cerr << "Error writing parameters to file <" << savesetname << ">\n");
930 }
931 }
932
933 if(diffsetname != nullptr)
934 {
935 MSG_INFO1(soplex->spxout, soplex->spxout << "Saving modified parameters to settings file <" <<
936 diffsetname << "> . . .\n");
937
938 if(!soplex->saveSettingsFile(diffsetname, true))
939 {
940 MSG_ERROR(std::cerr << "Error writing modified parameters to file <" << diffsetname << ">\n");
941 }
942 }
943
944 // no LP file given: exit after saving settings
945 if(lpfilename == nullptr)
946 {
947 if(loadsetname != nullptr || savesetname != nullptr || diffsetname != nullptr)
948 {
949 MSG_INFO1(soplex->spxout, soplex->spxout << "\n");
950 }
951
953 }
954
955 // measure time for reading LP file and basis file
956 readingTime->start();
957
958 // if the LP is parsed rationally and might be solved rationally, we choose automatic syncmode such that
959 // the rational LP is kept after reading
960 if(soplex->intParam(soplex->READMODE) == soplex->READMODE_RATIONAL
961 && soplex->intParam(soplex->SOLVEMODE) != soplex->SOLVEMODE_REAL)
962 {
963 soplex->setIntParam(soplex->SYNCMODE, soplex->SYNCMODE_AUTO);
964 }
965
966 // read LP from input file
967 MSG_INFO1(soplex->spxout, soplex->spxout << "Reading "
968 << (soplex->intParam(soplex->READMODE) == soplex->READMODE_REAL ? "(real)" : "(rational)")
969 << " LP file <" << lpfilename << "> . . .\n");
970
971 if(!soplex->readFile(lpfilename, &rownames, &colnames))
972 {
973 MSG_ERROR(std::cerr << "Error while reading file <" << lpfilename << ">.\n");
974 returnValue = 1;
976 }
977
978 // write LP if specified
979 if(writefilename != nullptr)
980 {
981 if(!soplex->writeFile(writefilename, &rownames, &colnames))
982 {
983 MSG_ERROR(std::cerr << "Error while writing file <" << writefilename << ">.\n\n");
984 returnValue = 1;
986 }
987 else
988 {
989 MSG_INFO1(soplex->spxout, soplex->spxout << "Written LP to file <" << writefilename << ">.\n\n");
990 }
991 }
992
993 // write dual LP if specified
994 if(writedualfilename != nullptr)
995 {
996 if(!soplex->writeDualFileReal(writedualfilename, &rownames, &colnames))
997 {
998 MSG_ERROR(std::cerr << "Error while writing dual file <" << writedualfilename << ">.\n\n");
999 returnValue = 1;
1001 }
1002 else
1003 {
1004 MSG_INFO1(soplex->spxout, soplex->spxout << "Written dual LP to file <" << writedualfilename <<
1005 ">.\n\n");
1006 }
1007 }
1008
1009 // read basis file if specified
1010 if(readbasname != nullptr)
1011 {
1012 MSG_INFO1(soplex->spxout, soplex->spxout << "Reading basis file <" << readbasname << "> . . . ");
1013
1014 if(!soplex->readBasisFile(readbasname, &rownames, &colnames))
1015 {
1016 MSG_ERROR(std::cerr << "Error while reading file <" << readbasname << ">.\n");
1017 returnValue = 1;
1019 }
1020 }
1021
1022 readingTime->stop();
1023
1024 MSG_INFO1(soplex->spxout,
1025 std::streamsize prec = soplex->spxout.precision();
1026 soplex->spxout << "Reading took "
1027 << std::fixed << std::setprecision(2) << readingTime->time()
1028 << std::scientific << std::setprecision(int(prec))
1029 << " seconds.\n\n");
1030
1031 MSG_INFO1(soplex->spxout, soplex->spxout << "LP has " << soplex->numRows() << " rows "
1032 << soplex->numCols() << " columns and " << soplex->numNonzeros() << " nonzeros.\n\n");
1033
1034 // solve the LP
1035 soplex->optimize();
1036
1037 // print solution, check solution, and display statistics
1040
1041 if(checkSol)
1042 checkSolution<R>(*soplex); // The type needs to get fixed here
1043
1045 {
1046 MSG_INFO1(soplex->spxout, soplex->spxout << "Statistics\n==========\n\n");
1047 soplex->printStatistics(soplex->spxout.getStream(SPxOut::INFO1));
1048 }
1049
1050 if(validation->validate)
1051 validation->validateSolveReal(*soplex);
1052
1053 // write basis file if specified
1054 if(writebasname != nullptr)
1055 {
1056 if(!soplex->hasBasis())
1057 {
1058 MSG_WARNING(soplex->spxout, soplex->spxout <<
1059 "No basis information available. Could not write file <" << writebasname << ">\n\n");
1060 }
1061 else if(!soplex->writeBasisFile(writebasname, &rownames, &colnames))
1062 {
1063 MSG_ERROR(std::cerr << "Error while writing file <" << writebasname << ">.\n\n");
1064 returnValue = 1;
1066 }
1067 else
1068 {
1069 MSG_INFO1(soplex->spxout, soplex->spxout << "Written basis information to file <" << writebasname <<
1070 ">.\n\n");
1071 }
1072 }
1073 }
1074 catch(const SPxException& x)
1075 {
1076 MSG_ERROR(std::cerr << "Exception caught: " << x.what() << "\n");
1077 returnValue = 1;
1079 }
1080
1083
1084TERMINATE:
1085
1086 // because EGlpNumClear() calls mpq_clear() for all mpq_t variables, we need to destroy all objects of class Rational
1087 // beforehand; hence all Rational objects and all data that uses Rational objects must be allocated dynamically via
1088 // spx_alloc() and freed here; disabling the list memory is crucial
1089 if(nullptr != soplex)
1090 {
1091 soplex->~SoPlexBase();
1093 }
1094
1095 if(nullptr != validation)
1096 {
1097 validation->~Validation();
1099 }
1100
1101 if(nullptr != readingTime)
1102 {
1103 readingTime->~Timer();
1104 spx_free(readingTime);
1105 }
1106
1107 return returnValue;
1108}
1109
1110/// runs SoPlexBase command line
1111int main(int argc, char* argv[])
1112{
1113 int arithmetic = 0;
1114 int precision = 0;
1115 int optidx;
1116
1117 // find out which precision/solvemode soplex should be run in. the rest happens in runSoPlex
1118 // no options were given
1119 if(argc <= 1)
1120 {
1121 printUsage(argv, 0);
1122 return 1;
1123 }
1124
1125 // read arguments from command line
1126 for(optidx = 1; optidx < argc; optidx++)
1127 {
1128 char* option = argv[optidx];
1129
1130 // we reached <lpfile>
1131 if(option[0] != '-')
1132 continue;
1133
1134 // option string must start with '-', must contain at least two characters, and exactly two characters if and
1135 // only if it is -x, -y, -q, or -c
1136 if(option[0] != '-' || option[1] == '\0'
1137 || ((option[2] == '\0') != (option[1] == 'x' || option[1] == 'X' || option[1] == 'y'
1138 || option[1] == 'Y' || option[1] == 'q' || option[1] == 'c')))
1139 {
1141 return 1;
1142 }
1143
1144 switch(option[1])
1145 {
1146 case '-' :
1147 option = &option[2];
1148
1149 // --arithmetic=<value> : choose base arithmetic type (0 - double, 1 - quadprecision, 2 - higher multiprecision)
1150 // only need to do something here if multi or quad, the rest is handled in runSoPlex
1151 if(strncmp(option, "arithmetic=", 11) == 0)
1152 {
1153 if(option[11] == '1')
1154 {
1155#ifndef SOPLEX_WITH_FLOAT128
1156 MSG_ERROR(std::cerr <<
1157 "Cannot set arithmetic type to quadprecision - Soplex compiled without quadprecision support\n";)
1158 printUsage(argv, 0);
1159 return 1;
1160#else
1161 arithmetic = 1;
1162#endif
1163 }
1164 else if(option[11] == '2')
1165 {
1166#ifndef SOPLEX_WITH_BOOST
1167 MSG_ERROR(std::cerr <<
1168 "Cannot set arithmetic type to multiprecision - Soplex compiled without boost\n";)
1169 printUsage(argv, 0);
1170 return 1;
1171#else
1172 arithmetic = 2;
1173
1174 // default precision in multiprecision solve is 50
1175 if(precision == 0)
1176 precision = 50;
1177
1178#endif
1179 }
1180 }
1181 // set precision
1182 else if(strncmp(option, "precision=", 10) == 0)
1183 {
1184 precision = atoi(option + 10);
1185#ifndef SOPLEX_WITH_BOOST
1186 MSG_ERROR(std::cerr << "Setting precision to non-default value without Boost has no effect\n";)
1187#endif
1188 }
1189
1190 break;
1191
1192 default:
1193 break;
1194 }
1195 }
1196
1197 if(precision != 0 && arithmetic != 2)
1198 {
1199 MSG_ERROR(std::cerr <<
1200 "Setting precision to non-default value without enabling multiprecision solve has no effect\n";)
1201 }
1202
1203 switch(arithmetic)
1204 {
1205 case 0: // double
1207 break;
1208
1209#ifdef SOPLEX_WITH_BOOST
1210#ifdef SOPLEX_WITH_FLOAT128
1211
1212 case 1: // quadprecision
1213#if BOOST_VERSION < 107000
1214 std::cerr << "Error: Boost version too old." << std:: endl <<
1215 "In order to use the quadprecision feature of SoPlex," <<
1216 " Boost Version 1.70.0 or higher is required." << std::endl << \
1217 "Included Boost version is " << BOOST_VERSION / 100000 << "." // maj. version
1218 << BOOST_VERSION / 100 % 1000 << "." // min. version
1219 << BOOST_VERSION % 100 // patch version;
1220 << std::endl;
1221#else
1222 using namespace boost::multiprecision;
1223 using Quad = boost::multiprecision::float128;
1225#endif
1226 break;
1227#endif
1228
1229 case 2: // soplex mpf
1230 using namespace boost::multiprecision;
1231
1232#if BOOST_VERSION < 107000
1233 std::cerr << "Error: Boost version too old." << std:: endl <<
1234 "In order to use the multiprecision feature of SoPlex," <<
1235 " Boost Version 1.70.0 or higher is required." << std::endl << \
1236 "Included Boost version is " << BOOST_VERSION / 100000 << "." // maj. version
1237 << BOOST_VERSION / 100 % 1000 << "." // min. version
1238 << BOOST_VERSION % 100 // patch version;
1239 << std::endl;
1240#else
1241#ifdef SOPLEX_WITH_MPFR
1242
1243 // et_off means the expression templates options is turned off. TODO:
1244 // The documentation also mentions about static vs dynamic memory
1245 // allocation for the mpfr types. Is it relevant here? I probably also
1246 // need to have the mpfr_float_eto in the global soplex namespace
1248 multiprecision::default_precision(precision);
1250#endif // SOPLEX_WITH_MPFR
1251
1252#ifdef SOPLEX_WITH_CPPMPF
1253 // It seems that precision cannot be set on run time for cpp_float
1254 // backend for boost::number. So a precision of 50 decimal points is
1255 // set.
1259
1260 if(precision <= 50)
1262 else if(precision <= 100)
1264 else
1266
1267#endif // SOPLEX_WITH_CPPMPF
1268#endif
1269 break;
1270#endif
1271
1272 // coverity[dead_error_begin]
1273 default:
1274 std::cerr << "Wrong value for the arithmetic mode\n";
1275 return 0;
1276 }
1277}
Safe arrays of data objects.
Definition dataarray.h:75
Set of strings.
Definition nameset.h:71
static Real epsilon()
Exception base class.
Definition exceptions.h:42
static Timer * createTimer(Timer::TYPE ttype)
create timers and allocate memory for them
Wrapper for the system time query methods.
Definition timer.h:86
virtual ~Timer()
Definition timer.h:133
virtual Real time() const =0
virtual void start()=0
start timer, resume accounting user, system and real time.
virtual Real stop()=0
stop timer, return accounted user time.
int main()
Definition example.cpp:144
Everything should be within this namespace.
double Real
Definition spxdefines.h:266
void spx_free(T &p)
Release memory.
Definition spxalloc.h:121
int spxSnprintf(char *t, size_t len, const char *s,...)
safe version of snprintf
Definition spxdefines.h:402
void spx_alloc(T &p, int n=1)
Allocate memory.
Definition spxalloc.h:58
Preconfigured SoPlex LP solver.
static void printUsage(const char *const argv[], int idx)
static void printDualSolution(SoPlexBase< R > &soplex, NameSet &colnames, NameSet &rownames, bool real=true, bool rational=false)
int runSoPlex(int argc, char *argv[])
static void checkSolutionRational(SoPlexBase< R > &soplex)
performs external feasibility check with rational type
void checkSolution(SoPlexBase< R > &soplex)
performs external feasibility check according to check mode
static void freeStrings(char *&s1, char *&s2, char *&s3, char *&s4, char *&s5)
static void checkSolutionReal(SoPlexBase< R > &soplex)
performs external feasibility check with real type
static void printPrimalSolution(SoPlexBase< R > &soplex, NameSet &colnames, NameSet &rownames, bool real=true, bool rational=false)
#define MSG_WARNING(spxout, x)
Prints out message x if the verbosity level is at least SPxOut::WARNING.
Definition spxdefines.h:164
#define MSG_INFO1(spxout, x)
Prints out message x if the verbosity level is at least SPxOut::INFO1.
Definition spxdefines.h:166
#define SOPLEX_COPYRIGHT
Definition spxdefines.h:96
#define MSG_ERROR(x)
Prints out message x if the verbosity level is at least SPxOut::ERROR.
Definition spxdefines.h:162
Validation object for soplex solutions.