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