Scippy

SoPlex

Sequential object-oriented simPlex

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