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