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-2023 Zuse Institute Berlin (ZIB) */
7 /* */
8 /* Licensed under the Apache License, Version 2.0 (the "License"); */
9 /* you may not use this file except in compliance with the License. */
10 /* You may obtain a copy of the License at */
11 /* */
12 /* http://www.apache.org/licenses/LICENSE-2.0 */
13 /* */
14 /* Unless required by applicable law or agreed to in writing, software */
15 /* distributed under the License is distributed on an "AS IS" BASIS, */
16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17 /* See the License for the specific language governing permissions and */
18 /* limitations under the License. */
19 /* */
20 /* You should have received a copy of the Apache-2.0 license */
21 /* along with SoPlex; see the file LICENSE. If not email to soplex@zib.de. */
22 /* */
23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24 
25 /**@file soplexmain.cpp
26  * @brief Command line interface of SoPlex LP solver
27  */
28 
29 #include <assert.h>
30 #include <math.h>
31 #include <string.h>
32 
33 #include <iostream>
34 #include <iomanip>
35 #include <fstream>
36 
37 #include "soplex.h"
38 #include "soplex/validation.h"
39 
40 using namespace soplex;
41 
42 // function prototype
43 int main(int argc, char* argv[]);
44 
45 // prints usage and command line options
46 static
47 void printUsage(const char* const argv[], int idx)
48 {
49  const char* usage =
50  "general options:\n"
51  " --readbas=<basfile> read starting basis from file\n"
52  " --writebas=<basfile> write terminal basis to file\n"
53  " --writefile=<lpfile> write LP to file in LP or MPS format depending on extension\n"
54  " --writedual=<lpfile> write the dual LP to a file in LP or MPS formal depending on extension\n"
55  " --<type>:<name>=<val> change parameter value using syntax of settings file entries\n"
56  " --loadset=<setfile> load parameters from settings file (overruled by command line parameters)\n"
57  " --saveset=<setfile> save parameters to settings file\n"
58  " --diffset=<setfile> save modified parameters to settings file\n"
59  " --extsol=<value> external solution for soplex to use for validation\n"
60  "\n"
61  "limits and tolerances:\n"
62  " -t<s> set time limit to <s> seconds\n"
63  " -i<n> set iteration limit to <n>\n"
64  " -f<eps> set primal feasibility tolerance to <eps>\n"
65  " -o<eps> set dual feasibility (optimality) tolerance to <eps>\n"
66  " -l<eps> set validation tolerance to <eps>\n"
67  "\n"
68  "algorithmic settings (* indicates default):\n"
69  " --readmode=<value> choose reading mode for <lpfile> (0* - floating-point, 1 - rational)\n"
70  " --solvemode=<value> choose solving mode (0 - floating-point solve, 1* - auto, 2 - force iterative refinement)\n"
71  " --arithmetic=<value> choose base arithmetic type (0 - double, 1 - quadprecision, 2 - higher multiprecision)\n"
72 #ifdef SOPLEX_WITH_MPFR
73  " --precision=<value> choose precision for multiprecision solve (only active when arithmetic=2 minimal value = 50)\n"
74 #endif
75 #ifdef SOPLEX_WITH_CPPMPF
76  " --precision=<value> choose precision for multiprecision solve (only active when arithmetic=2, possible values 50,100,200, compile with mpfr for arbitrary precision)\n"
77 #endif
78  " -s<value> choose simplifier/presolver (0 - off, 1* - internal, 2*- PaPILO)\n"
79  " -g<value> choose scaling (0 - off, 1 - uni-equilibrium, 2* - bi-equilibrium, 3 - geometric, 4 - iterated geometric, 5 - least squares, 6 - geometric-equilibrium)\n"
80  " -p<value> choose pricing (0* - auto, 1 - dantzig, 2 - parmult, 3 - devex, 4 - quicksteep, 5 - steep)\n"
81  " -r<value> choose ratio tester (0 - textbook, 1 - harris, 2 - fast, 3* - boundflipping)\n"
82  "\n"
83  "display options:\n"
84  " -v<level> set verbosity to <level> (0 - error, 3 - normal, 5 - high)\n"
85  " -x=<solfile> print primal solution to file (or just -x to print to terminal)\n"
86  " -y=<solfile> print dual multipliers to file (or just -y to print to terminal)\n"
87  " -X=<solfile> print primal solution in rational numbers to file (or just -X to print to terminal)\n"
88  " -Y=<solfile> print dual multipliers in rational numbers to file (or just -Y to print to terminal)\n"
89  " -q display detailed statistics\n"
90  " -c perform final check of optimal solution in original problem\n"
91  "\n";
92 
93  if(idx <= 0)
94  std::cerr << "missing input file\n\n";
95  else
96  std::cerr << "invalid option \"" << argv[idx] << "\"\n\n";
97 
98  std::cerr << "usage: " << argv[0] << " " << "[options] <lpfile>\n"
99 #ifdef SOPLEX_WITH_ZLIB
100  << " <lpfile> linear program as .mps[.gz] or .lp[.gz] file\n\n"
101 #else
102  << " <lpfile> linear program as .mps or .lp file\n\n"
103 #endif
104  << usage;
105 }
106 
107 // cleans up C strings
108 static
109 void freeStrings(char*& s1, char*& s2, char*& s3, char*& s4, char*& s5)
110 {
111  if(s1 != 0)
112  {
113  delete [] s1;
114  s1 = 0;
115  }
116 
117  if(s2 != 0)
118  {
119  delete [] s2;
120  s2 = 0;
121  }
122 
123  if(s3 != 0)
124  {
125  delete [] s3;
126  s3 = 0;
127  }
128 
129  if(s4 != 0)
130  {
131  delete [] s4;
132  s4 = 0;
133  }
134 
135  if(s5 != 0)
136  {
137  delete [] s5;
138  s5 = 0;
139  }
140 }
141 
142 /// performs external feasibility check with real type
143 ///@todo implement external check; currently we use the internal methods for convenience
144 
145 template <class R>
146 static
148 {
149  if(soplex.hasPrimal())
150  {
151  R boundviol;
152  R rowviol;
153  R sumviol;
154 
155  if(soplex.getBoundViolation(boundviol, sumviol) && soplex.getRowViolation(rowviol, sumviol))
156  {
157  SPX_MSG_INFO1(soplex.spxout,
158  R maxviol = boundviol > rowviol ? boundviol : rowviol;
159  bool feasible = (maxviol <= soplex.realParam(SoPlexBase<R>::FEASTOL));
160  soplex.spxout << "Primal solution " << (feasible ? "feasible" : "infeasible")
161  << " in original problem (max. violation = " << std::scientific << maxviol
162  << std::setprecision(8) << std::fixed << ").\n");
163  }
164  else
165  {
166  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "Could not check primal solution.\n");
167  }
168  }
169  else
170  {
171  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "No primal solution available.\n");
172  }
173 
174  if(soplex.hasDual())
175  {
176  R redcostviol;
177  R dualviol;
178  R sumviol;
179 
180  if(soplex.getRedCostViolation(redcostviol, sumviol) && soplex.getDualViolation(dualviol, sumviol))
181  {
182  SPX_MSG_INFO1(soplex.spxout,
183  R maxviol = redcostviol > dualviol ? redcostviol : dualviol;
184  bool feasible = (maxviol <= soplex.realParam(SoPlexBase<R>::OPTTOL));
185  soplex.spxout << "Dual solution " << (feasible ? "feasible" : "infeasible")
186  << " in original problem (max. violation = " << std::scientific << maxviol
187  << std::setprecision(8) << std::fixed << ").\n"
188  );
189  }
190  else
191  {
192  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "Could not check dual solution.\n");
193  }
194  }
195  else
196  {
197  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "No dual solution available.\n");
198  }
199 }
200 
201 /// performs external feasibility check with rational type
202 ///@todo implement external check; currently we use the internal methods for convenience
203 template <class R>
205 {
206  if(soplex.hasPrimal())
207  {
208  Rational boundviol;
209  Rational rowviol;
210  Rational sumviol;
211 
212  if(soplex.getBoundViolationRational(boundviol, sumviol)
213  && soplex.getRowViolationRational(rowviol, sumviol))
214  {
215  SPX_MSG_INFO1(soplex.spxout,
216  Rational maxviol = boundviol > rowviol ? boundviol : rowviol;
217  bool feasible = (maxviol <= soplex.realParam(SoPlexBase<R>::FEASTOL));
218  soplex.spxout << "Primal solution " << (feasible ? "feasible" : "infeasible") <<
219  " in original problem (max. violation = " << maxviol << ").\n"
220  );
221  }
222  else
223  {
224  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "Could not check primal solution.\n");
225  }
226  }
227  else
228  {
229  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "No primal solution available.\n");
230  }
231 
232  if(soplex.hasDual())
233  {
234  Rational redcostviol;
235  Rational dualviol;
236  Rational sumviol;
237 
238  if(soplex.getRedCostViolationRational(redcostviol, sumviol)
239  && soplex.getDualViolationRational(dualviol, sumviol))
240  {
241  SPX_MSG_INFO1(soplex.spxout,
242  Rational maxviol = redcostviol > dualviol ? redcostviol : dualviol;
243  bool feasible = (maxviol <= soplex.realParam(SoPlexBase<R>::OPTTOL));
244  soplex.spxout << "Dual solution " << (feasible ? "feasible" : "infeasible") <<
245  " in original problem (max. violation = " << maxviol << ").\n"
246  );
247  }
248  else
249  {
250  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "Could not check dual solution.\n");
251  }
252  }
253  else
254  {
255  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "No dual solution available.\n");
256  }
257 }
258 
259 /// performs external feasibility check according to check mode
260 template <class R>
262 {
266  {
267  checkSolutionRational(soplex);
268  }
269  else
270  {
271  checkSolutionReal(soplex);
272  }
273 
274  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\n");
275 }
276 
277 template <class R>
278 static
279 void writePrimalSolution(SoPlexBase<R>& soplex, const char* filename, NameSet& colnames,
280  NameSet& rownames,
281  bool real = true, bool rational = false, bool append = false)
282 {
283  int printprec;
284  int printwidth;
285  printprec = (int) - log10(Real(soplex.tolerances()->epsilon()));
286  printwidth = printprec + 10;
287  std::ofstream outfile;
288 
289  if(append)
290  outfile.open(filename, std::ios::app);
291  else
292  outfile.open(filename);
293 
294  if(real)
295  {
296  VectorBase<R> primal(soplex.numCols());
297 
298  if(soplex.getPrimalRay(primal))
299  {
300  outfile << "\nPrimal ray (name, value):\n";
301 
302  for(int i = 0; i < soplex.numCols(); ++i)
303  {
304  if(isNotZero(primal[i], soplex.tolerances()->epsilon()))
305  {
306  outfile << colnames[i] << "\t"
307  << std::setw(printwidth) << std::setprecision(printprec)
308  << primal[i] << std::endl;
309  }
310  }
311 
312  outfile << "All other entries are zero (within "
313  << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon()
314  << std::setprecision(8) << std::fixed
315  << ")." << std::endl;
316  }
317  else if(soplex.isPrimalFeasible() && soplex.getPrimal(primal))
318  {
319  int nNonzeros = 0;
320  outfile << "\nPrimal solution (name, value):\n";
321 
322  for(int i = 0; i < soplex.numCols(); ++i)
323  {
324  if(isNotZero(primal[i], soplex.tolerances()->epsilon()))
325  {
326  outfile << colnames[i] << "\t"
327  << std::setw(printwidth) << std::setprecision(printprec)
328  << primal[i] << std::endl;
329  ++nNonzeros;
330  }
331  }
332 
333  outfile << "All other variables are zero (within "
334  << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon()
335  << std::setprecision(8) << std::fixed
336  << "). Solution has " << nNonzeros << " nonzero entries." << std::endl;
337  }
338  else
339  outfile << "No primal information available.\n";
340  }
341 
342  if(rational)
343  {
344  VectorRational primal(soplex.numCols());
345 
346  if(soplex.getPrimalRayRational(primal))
347  {
348  outfile << "\nPrimal ray (name, value):\n";
349 
350  for(int i = 0; i < soplex.numCols(); ++i)
351  {
352  if(primal[i] != (Rational) 0)
353  {
354  outfile << colnames[i] << "\t"
355  << std::setw(printwidth) << std::setprecision(printprec)
356  << primal[i] << std::endl;
357  }
358  }
359 
360  outfile << "All other entries are zero." << std::endl;
361  }
362 
363  if(soplex.isPrimalFeasible() && soplex.getPrimalRational(primal))
364  {
365  int nNonzeros = 0;
366  outfile << "\nPrimal solution (name, value):\n";
367 
368  for(int i = 0; i < soplex.numColsRational(); ++i)
369  {
370  if(primal[i] != (Rational) 0)
371  {
372  outfile << colnames[i] << "\t" << primal[i] << std::endl;
373  ++nNonzeros;
374  }
375  }
376 
377  outfile << "All other variables are zero. Solution has "
378  << nNonzeros << " nonzero entries." << std::endl;
379  }
380  else
381  outfile << "No primal (rational) solution available.\n";
382  }
383 }
384 
385 template <class R>
386 static
387 void writeDualSolution(SoPlexBase<R>& soplex, const char* filename, NameSet& colnames,
388  NameSet& rownames,
389  bool real = true, bool rational = false, bool append = false)
390 {
391  int printprec;
392  int printwidth;
393  printprec = (int) - log10(Real(soplex.tolerances()->epsilon()));
394  printwidth = printprec + 10;
395 
396  std::ofstream outfile;
397 
398  if(append)
399  outfile.open(filename, std::ios::app);
400  else
401  outfile.open(filename);
402 
403  if(real)
404  {
405  VectorBase<R> dual(soplex.numRows());
406 
407  if(soplex.getDualFarkas(dual))
408  {
409  outfile << "\nDual ray (name, value):\n";
410 
411  for(int i = 0; i < soplex.numRows(); ++i)
412  {
413  if(isNotZero(dual[i], soplex.tolerances()->epsilon()))
414  {
415  outfile << rownames[i] << "\t"
416  << std::setw(printwidth) << std::setprecision(printprec)
417  << dual[i] << std::endl;
418  }
419  }
420 
421  outfile << "All other entries are zero (within "
422  << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon()
423  << std::setprecision(8) << std::fixed << ")." << std::endl;
424  }
425  else if(soplex.isDualFeasible() && soplex.getDual(dual))
426  {
427  outfile << "\nDual solution (name, value):\n";
428 
429  for(int i = 0; i < soplex.numRows(); ++i)
430  {
431  if(isNotZero(dual[i], soplex.tolerances()->epsilon()))
432  {
433  outfile << rownames[i] << "\t"
434  << std::setw(printwidth) << std::setprecision(printprec)
435  << dual[i] << std::endl;
436  }
437  }
438 
439  outfile << "All other dual values are zero (within "
440  << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon()
441  << std::setprecision(8) << std::fixed << ")." << std::endl;
442 
443  VectorBase<R> redcost(soplex.numCols());
444 
445  if(soplex.getRedCost(redcost))
446  {
447  outfile << "\nReduced costs (name, value):\n";
448 
449  for(int i = 0; i < soplex.numCols(); ++i)
450  {
451  if(isNotZero(redcost[i], soplex.tolerances()->epsilon()))
452  {
453  outfile << colnames[i] << "\t"
454  << std::setw(printwidth) << std::setprecision(printprec)
455  << redcost[i] << std::endl;
456  }
457  }
458 
459  outfile << "All other reduced costs are zero (within "
460  << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon()
461  << std::setprecision(8) << std::fixed << ")." << std::endl;
462  }
463  }
464  else
465  outfile << "No dual information available.\n";
466  }
467 
468  if(rational)
469  {
470  VectorRational dual(soplex.numRows());
471 
472  if(soplex.getDualFarkasRational(dual))
473  {
474  outfile << "\nDual ray (name, value):\n";
475 
476  for(int i = 0; i < soplex.numRows(); ++i)
477  {
478  if(dual[i] != (Rational) 0)
479  {
480  outfile << rownames[i] << "\t"
481  << std::setw(printwidth)
482  << std::setprecision(printprec)
483  << dual[i] << std::endl;
484  }
485  }
486 
487  outfile << "All other entries are zero." << std::endl;
488  }
489 
490  if(soplex.isDualFeasible() && soplex.getDualRational(dual))
491  {
492  outfile << "\nDual solution (name, value):\n";
493 
494  for(int i = 0; i < soplex.numRowsRational(); ++i)
495  {
496  if(dual[i] != (Rational) 0)
497  outfile << rownames[i] << "\t" << dual[i] << std::endl;
498  }
499 
500  outfile << "All other dual values are zero." << std::endl;
501 
502  VectorRational redcost(soplex.numCols());
503 
504  if(soplex.getRedCostRational(redcost))
505  {
506  outfile << "\nReduced costs (name, value):\n";
507 
508  for(int i = 0; i < soplex.numCols(); ++i)
509  {
510  if(redcost[i] != (Rational) 0)
511  outfile << colnames[i] << "\t" << redcost[i] << std::endl;
512  }
513 
514  outfile << "All other reduced costs are zero." << std::endl;
515  }
516  }
517  else
518  outfile << "No dual (rational) solution available.\n";
519  }
520 }
521 
522 template <class R>
523 static
525  bool real = true, bool rational = false)
526 {
527  int printprec;
528  int printwidth;
529  printprec = (int) - log10(Real(soplex.tolerances()->epsilon()));
530  printwidth = printprec + 10;
531 
532  if(real)
533  {
534  VectorBase<R> primal(soplex.numCols());
535 
536  if(soplex.getPrimalRay(primal))
537  {
538  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nPrimal ray (name, value):\n";)
539 
540  for(int i = 0; i < soplex.numCols(); ++i)
541  {
542  if(isNotZero(primal[i], soplex.tolerances()->epsilon()))
543  {
544  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << colnames[i] << "\t"
545  << std::setw(printwidth) << std::setprecision(printprec)
546  << primal[i] << std::endl;)
547  }
548  }
549 
550  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other entries are zero (within "
551  << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon()
552  << std::setprecision(8) << std::fixed
553  << ")." << std::endl;)
554  }
555  else if(soplex.isPrimalFeasible() && soplex.getPrimal(primal))
556  {
557  int nNonzeros = 0;
558  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nPrimal solution (name, value):\n";)
559 
560  for(int i = 0; i < soplex.numCols(); ++i)
561  {
562  if(isNotZero(primal[i], soplex.tolerances()->epsilon()))
563  {
564  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << colnames[i] << "\t"
565  << std::setw(printwidth) << std::setprecision(printprec)
566  << primal[i] << std::endl;)
567  ++nNonzeros;
568  }
569  }
570 
571  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other variables are zero (within "
572  << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon()
573  << std::setprecision(8) << std::fixed
574  << "). Solution has " << nNonzeros << " nonzero entries." << std::endl;)
575  }
576  else
577  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "No primal information available.\n")
578  }
579 
580  if(rational)
581  {
582  VectorRational primal(soplex.numCols());
583 
584  if(soplex.getPrimalRayRational(primal))
585  {
586  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nPrimal ray (name, value):\n";)
587 
588  for(int i = 0; i < soplex.numCols(); ++i)
589  {
590  if(primal[i] != (Rational) 0)
591  {
592  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << colnames[i] << "\t"
593  << std::setw(printwidth) << std::setprecision(printprec)
594  << primal[i] << std::endl;)
595  }
596  }
597 
598  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other entries are zero." << std::endl;)
599  }
600 
601  if(soplex.isPrimalFeasible() && soplex.getPrimalRational(primal))
602  {
603  int nNonzeros = 0;
604  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nPrimal solution (name, value):\n";)
605 
606  for(int i = 0; i < soplex.numColsRational(); ++i)
607  {
608  if(primal[i] != (Rational) 0)
609  {
610  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << colnames[i] << "\t" << primal[i] << std::endl;)
611  ++nNonzeros;
612  }
613  }
614 
615  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other variables are zero. Solution has "
616  << nNonzeros << " nonzero entries." << std::endl;)
617  }
618  else
619  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "No primal (rational) solution available.\n")
620 
621  }
622 }
623 
624 template <class R>
625 static
627  bool real = true, bool rational = false)
628 {
629  int printprec;
630  int printwidth;
631  printprec = (int) - log10(Real(soplex.tolerances()->epsilon()));
632  printwidth = printprec + 10;
633 
634  if(real)
635  {
636  VectorBase<R> dual(soplex.numRows());
637 
638  if(soplex.getDualFarkas(dual))
639  {
640  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nDual ray (name, value):\n";)
641 
642  for(int i = 0; i < soplex.numRows(); ++i)
643  {
644  if(isNotZero(dual[i], soplex.tolerances()->epsilon()))
645  {
646  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << rownames[i] << "\t"
647  << std::setw(printwidth) << std::setprecision(printprec)
648  << dual[i] << std::endl;)
649  }
650  }
651 
652  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other entries are zero (within "
653  << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon()
654  << std::setprecision(8) << std::fixed << ")." << std::endl;)
655  }
656  else if(soplex.isDualFeasible() && soplex.getDual(dual))
657  {
658  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nDual solution (name, value):\n";)
659 
660  for(int i = 0; i < soplex.numRows(); ++i)
661  {
662  if(isNotZero(dual[i], soplex.tolerances()->epsilon()))
663  {
664  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << rownames[i] << "\t"
665  << std::setw(printwidth) << std::setprecision(printprec)
666  << dual[i] << std::endl;)
667  }
668  }
669 
670  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other dual values are zero (within "
671  << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon()
672  << std::setprecision(8) << std::fixed << ")." << std::endl;)
673 
674  VectorBase<R> redcost(soplex.numCols());
675 
676  if(soplex.getRedCost(redcost))
677  {
678  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nReduced costs (name, value):\n";)
679 
680  for(int i = 0; i < soplex.numCols(); ++i)
681  {
682  if(isNotZero(redcost[i], soplex.tolerances()->epsilon()))
683  {
684  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << colnames[i] << "\t"
685  << std::setw(printwidth) << std::setprecision(printprec)
686  << redcost[i] << std::endl;)
687  }
688  }
689 
690  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other reduced costs are zero (within "
691  << std::setprecision(1) << std::scientific << soplex.tolerances()->epsilon()
692  << std::setprecision(8) << std::fixed << ")." << std::endl;)
693  }
694  }
695  else
696  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "No dual information available.\n")
697  }
698 
699  if(rational)
700  {
701  VectorRational dual(soplex.numRows());
702 
703  if(soplex.getDualFarkasRational(dual))
704  {
705  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nDual ray (name, value):\n";)
706 
707  for(int i = 0; i < soplex.numRows(); ++i)
708  {
709  if(dual[i] != (Rational) 0)
710  {
711  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << rownames[i] << "\t"
712  << std::setw(printwidth)
713  << std::setprecision(printprec)
714  << dual[i] << std::endl;)
715  }
716  }
717 
718  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other entries are zero." << std::endl;)
719  }
720 
721  if(soplex.isDualFeasible() && soplex.getDualRational(dual))
722  {
723  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nDual solution (name, value):\n";)
724 
725  for(int i = 0; i < soplex.numRowsRational(); ++i)
726  {
727  if(dual[i] != (Rational) 0)
728  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << rownames[i] << "\t" << dual[i] << std::endl;)
729  }
730 
731  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other dual values are zero." << std::endl;)
732 
733  VectorRational redcost(soplex.numCols());
734 
735  if(soplex.getRedCostRational(redcost))
736  {
737  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "\nReduced costs (name, value):\n";)
738 
739  for(int i = 0; i < soplex.numCols(); ++i)
740  {
741  if(redcost[i] != (Rational) 0)
742  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << colnames[i] << "\t" << redcost[i] << std::endl;)
743  }
744 
745  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "All other reduced costs are zero." << std::endl;)
746  }
747  }
748  else
749  SPX_MSG_INFO1(soplex.spxout, soplex.spxout << "No dual (rational) solution available.\n")
750  }
751 }
752 
753 // Runs SoPlex with the parsed boost variables map
754 template <class R>
755 int runSoPlex(int argc, char* argv[])
756 {
757  SoPlexBase<R>* soplex = nullptr;
758 
759  Timer* readingTime = nullptr;
760  Validation<R>* validation = nullptr;
761  int optidx;
762 
763  const char* lpfilename = nullptr;
764  char* readbasname = nullptr;
765  char* writebasname = nullptr;
766  char* writefilename = nullptr;
767  char* writedualfilename = nullptr;
768  char* loadsetname = nullptr;
769  char* savesetname = nullptr;
770  char* diffsetname = nullptr;
771  bool printPrimal = false;
772  bool printPrimalRational = false;
773  bool printDual = false;
774  bool printDualRational = false;
775  bool displayStatistics = false;
776  bool checkSol = false;
777 
778  char* primalSolName = nullptr;
779  char* dualSolName = nullptr;
780 
781  // names for solutions with rational numbers
782  char* primalSolNameRational = nullptr;
783  char* dualSolNameRational = nullptr;
784 
785  int returnValue = 0;
786 
787  try
788  {
789  NameSet rownames;
790  NameSet colnames;
791 
792  // create default timer (CPU time)
794  soplex = nullptr;
795  spx_alloc(soplex);
796  new(soplex) SoPlexBase<R>();
797 
798  soplex->printVersion();
799  SPX_MSG_INFO1(soplex->spxout, soplex->spxout << SOPLEX_COPYRIGHT << std::endl << std::endl);
800 
801  validation = nullptr;
802  spx_alloc(validation);
803  new(validation) Validation<R>();
804 
805  // no options were given
806  if(argc <= 1)
807  {
808  printUsage(argv, 0);
809  returnValue = 1;
810  goto TERMINATE;
811  }
812 
813  // read arguments from command line
814  for(optidx = 1; optidx < argc; optidx++)
815  {
816  char* option = argv[optidx];
817 
818  // we reached <lpfile>
819  if(option[0] != '-')
820  {
821  lpfilename = argv[optidx];
822  continue;
823  }
824 
825  // option string must start with '-', 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(0, 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 
1418 TERMINATE_FREESTRINGS:
1419  freeStrings(readbasname, writebasname, loadsetname, savesetname, diffsetname);
1420  freeStrings(primalSolName, dualSolName, primalSolName, primalSolName, primalSolName);
1421 
1422 TERMINATE:
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();
1430  spx_free(soplex);
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
1449 int 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 }
bool writeFile(const char *filename, const NameSet *rowNames=0, const NameSet *colNames=0, const DIdxSet *intvars=0, const bool unscale=true) const
Templated write function Real writes real LP to file; LP or MPS format is chosen from the extension i...
virtual ~SoPlexBase()
destructor
number< gmp_rational, et_off > Rational
Definition: rational.h:29
#define SPX_MSG_WARNING(spxout, x)
Prints out message x if the verbosity level is at least SPxOut::WARNING.
Definition: spxdefines.h:165
bool getBoundViolationRational(Rational &maxviol, Rational &sumviol)
Dense vector.Class VectorBase provides dense linear algebra vectors. Internally, VectorBase wraps std...
Definition: dsvectorbase.h:37
bool getDualRational(VectorRational &vector)
int numNonzeros() const
returns number of nonzeros
type of ratio test
Definition: soplex.h:1084
int numRowsRational() const
virtual ~Timer()
Definition: timer.h:133
bool getPrimalRational(VectorRational &vector)
dual feasibility tolerance
Definition: soplex.h:1385
bool writeDualFileReal(const char *filename, const NameSet *rowNames=0, const NameSet *colNames=0, const DIdxSet *intvars=0) const
writes the dual of the real LP to file; LP or MPS format is chosen from the extension in filename; if...
#define SPX_MSG_ERROR(x)
Prints out message x if the verbosity level is at least SPxOut::ERROR.
Definition: spxdefines.h:163
bool isDualFeasible() const
is stored dual solution feasible?
bool updateValidationTolerance(const std::string &tolerance)
updates the tolerance used for validation
static void checkSolutionReal(SoPlexBase< R > &soplex)
performs external feasibility check with real type
Definition: soplexmain.cpp:147
bool getDual(VectorBase< R > &vector)
gets the dual solution vector if available; returns true on success
bool getRowViolationRational(Rational &maxviol, Rational &sumviol)
SPxSolverBase< R >::Status optimize(volatile bool *interrupt=NULL)
optimize the given LP
type of scaler
Definition: soplex.h:1075
bool getPrimalRay(VectorBase< R > &vector)
gets the primal ray if available; returns true on success
bool getRedCostViolation(R &maxviol, R &sumviol)
gets violation of reduced costs; returns true on success
void validateSolveReal(SoPlexBase< R > &soplex)
validates the soplex solution using the external solution
virtual const std::string what() const
returns exception message
Definition: exceptions.h:66
bool parseSettingsString(char *str)
parses one setting string and returns true on success; note that string is modified ...
virtual void start()=0
start timer, resume accounting user, system and real time.
virtual Real stop()=0
stop timer, return accounted user time.
void spx_alloc(T &p, int n=1)
Allocate memory.
Definition: spxalloc.h:58
user sync of real and rational LP
Definition: soplex.h:1300
double Real
Definition: spxdefines.h:269
int main(int argc, char *argv[])
runs SoPlexBase command line
bool getDualViolationRational(Rational &maxviol, Rational &sumviol)
bool getRedCostRational(VectorRational &vector)
int runSoPlex(int argc, char *argv[])
Definition: soplexmain.cpp:755
static void printUsage(const char *const argv[], int idx)
Definition: soplexmain.cpp:47
int intParam(const IntParam param) const
returns integer parameter value
bool getDualFarkas(VectorBase< R > &vector)
gets the Farkas proof if available; returns true on success
Real realParam(const RealParam param) const
returns real parameter value
iteration limit (-1 if unlimited)
Definition: soplex.h:1057
bool getBoundViolation(R &maxviol, R &sumviol)
gets violation of bounds; returns true on success
primal feasibility tolerance
Definition: soplex.h:1382
bool hasDual() const
deprecated: use hasSol() instead
Definition: soplex.h:627
int spxSnprintf(char *t, size_t len, const char *s,...)
safe version of snprintf
Definition: spxdefines.h:447
bool saveSettingsFile(const char *filename, const bool onlyChanged=false, int solvemode=1) const
writes settings file; returns true on success
bool getPrimal(VectorBase< R > &vector)
gets the primal solution vector if available; returns true on success
bool readBasisFile(const char *filename, const NameSet *rowNames=0, const NameSet *colNames=0)
reads basis information from filename and returns true on success; if rowNames and colNames are NULL...
bool hasPrimal() const
deprecated: use hasSol() instead
Definition: soplex.h:621
automatic sync of real and rational LP
Definition: soplex.h:1297
bool getDualFarkasRational(VectorRational &vector)
int numCols() const
Templated function that returns number of columns.
static void checkSolutionRational(SoPlexBase< R > &soplex)
performs external feasibility check with rational type
Definition: soplexmain.cpp:204
virtual Real time() const =0
bool getRedCostViolationRational(Rational &maxviol, Rational &sumviol)
static Timer * createTimer(Timer::TYPE ttype)
create timers and allocate memory for them
Definition: timerfactory.h:53
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
bool setRealParam(const RealParam param, const Real value, const bool init=true)
sets real parameter value; returns true on success
Preconfigured SoPlex LP solver.
Set of strings.Class NameSet implements a symbol or name table. It allows to store or remove names (i...
Definition: nameset.h:70
bool getDualViolation(R &maxviol, R &sumviol)
gets violation of dual multipliers; returns true on success
type of simplifier
Definition: soplex.h:1072
void checkSolution(SoPlexBase< R > &soplex)
performs external feasibility check according to check mode
Definition: soplexmain.cpp:261
bool validate
should the soplex solution be validated?
Definition: validation.h:43
Exception base class.This class implements a base class for our SoPlex exceptions We provide a what()...
Definition: exceptions.h:41
Everything should be within this namespace.
static void printPrimalSolution(SoPlexBase< R > &soplex, NameSet &colnames, NameSet &rownames, bool real=true, bool rational=false)
Definition: soplexmain.cpp:524
mode for iterative refinement strategy
Definition: soplex.h:1093
apply standard floating-point algorithm
Definition: soplex.h:1317
bool getRowViolation(R &maxviol, R &sumviol)
gets violation of constraints; returns true on success
int numRows() const
returns number of rows
time limit in seconds (INFTY if unlimited)
Definition: soplex.h:1403
mode for reading LP files
Definition: soplex.h:1090
#define SPX_MSG_INFO1(spxout, x)
Prints out message x if the verbosity level is at least SPxOut::INFO1.
Definition: spxdefines.h:167
std::streamsize precision() const
Definition: spxout.h:153
static void printDualSolution(SoPlexBase< R > &soplex, NameSet &colnames, NameSet &rownames, bool real=true, bool rational=false)
Definition: soplexmain.cpp:626
bool readFile(const char *filename, NameSet *rowNames=0, NameSet *colNames=0, DIdxSet *intVars=0)
reads LP file in LP or MPS format according to READMODE parameter; gets row names, column names, and integer variables if desired; returns true on success
~Validation()
default destructor
Definition: validation.h:59
void printVersion() const
prints version and compilation options
bool updateExternalSolution(const std::string &solution)
updates the external solution used for validation
bool getPrimalRayRational(VectorRational &vector)
verbosity level
Definition: soplex.h:1069
int numColsRational() const
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
bool isPrimalFeasible() const
is stored primal solution feasible?
Validation object for soplex solutions.
static void freeStrings(char *&s1, char *&s2, char *&s3, char *&s4, char *&s5)
Definition: soplexmain.cpp:109
type of pricer
Definition: soplex.h:1081
#define SOPLEX_COPYRIGHT
Definition: spxdefines.h:97
standard floating-point parsing
Definition: soplex.h:1307
bool setIntParam(const IntParam param, const int value, const bool init=true)
sets integer parameter value; returns true on success
const std::shared_ptr< Tolerances > tolerances() const
returns current tolerances
mode for synchronizing real and rational LP
Definition: soplex.h:1087
Wrapper for the system time query methods.
Definition: timer.h:85
void spx_free(T &p)
Release memory.
Definition: spxalloc.h:121
bool loadSettingsFile(const char *filename)
reads settings file; returns true on success
bool getRedCost(VectorBase< R > &vector)
gets the vector of reduced cost values if available; returns true on success
void printUserSettings()
print non-default parameter values