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
147  	void checkSolutionReal(SoPlexBase<R>& soplex)
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>
204  	static void checkSolutionRational(SoPlexBase<R>& soplex)
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>
261  	void checkSolution(SoPlexBase<R>& soplex)
262  	{
263  	   if(soplex.intParam(SoPlexBase<R>::CHECKMODE) == SoPlexBase<R>::CHECKMODE_RATIONAL
264  	         || (soplex.intParam(SoPlexBase<R>::CHECKMODE) == SoPlexBase<R>::CHECKMODE_AUTO
265  	             && soplex.intParam(SoPlexBase<R>::READMODE) == SoPlexBase<R>::READMODE_RATIONAL))
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
524  	void printPrimalSolution(SoPlexBase<R>& soplex, NameSet& colnames, NameSet& rownames,
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
626  	void printDualSolution(SoPlexBase<R>& soplex, NameSet& colnames, NameSet& rownames,
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)
793  	      readingTime = TimerFactory::createTimer(Timer::USER_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 '-', must contain at least two characters, and exactly two characters if and
826  	         // only if it is -x, -y, -q, or -c
827  	         if(option[0] != '-' || option[1] == '\0'
828  	               || ((option[2] == '\0') != (option[1] == 'q' || option[1] == 'c')))
829  	         {
830  	            printUsage(argv, optidx);
831  	            returnValue = 1;
832  	            goto TERMINATE_FREESTRINGS;
833  	         }
834  	
835  	         switch(option[1])
836  	         {
837  	         case '-' :
838  	         {
839  	            option = &option[2];
840  	
841  	            // --readbas=<basfile> : read starting basis from file
842  	            if(strncmp(option, "readbas=", 8) == 0)
843  	            {
844  	               if(readbasname == nullptr)
845  	               {
846  	                  char* filename = &option[8];
847  	                  readbasname = new char[strlen(filename) + 1];
848  	                  spxSnprintf(readbasname, strlen(filename) + 1, "%s", filename);
849  	               }
850  	            }
851  	            // --writebas=<basfile> : write terminal basis to file
852  	            else if(strncmp(option, "writebas=", 9) == 0)
853  	            {
854  	               if(writebasname == nullptr)
855  	               {
856  	                  char* filename = &option[9];
857  	                  writebasname =  new char[strlen(filename) + 1];
858  	                  spxSnprintf(writebasname, strlen(filename) + 1, "%s", filename);
859  	               }
860  	            }
861  	            // --writefile=<lpfile> : write LP to file
862  	            else if(strncmp(option, "writefile=", 10) == 0)
863  	            {
864  	               if(writefilename == nullptr)
865  	               {
866  	                  char* filename = &option[10];
867  	                  writefilename = new char[strlen(filename) + 1];
868  	                  spxSnprintf(writefilename, strlen(filename) + 1, "%s", filename);
869  	               }
870  	            }
871  	            // --writedual=<lpfile> : write dual LP to a file
872  	            else if(strncmp(option, "writedual=", 10) == 0)
873  	            {
874  	               if(writedualfilename == nullptr)
875  	               {
876  	                  char* dualfilename = &option[10];
877  	                  writedualfilename = new char[strlen(dualfilename) + 1];
878  	                  spxSnprintf(writedualfilename, strlen(dualfilename) + 1, "%s", dualfilename);
879  	               }
880  	            }
881  	            // --loadset=<setfile> : load parameters from settings file
882  	            else if(strncmp(option, "loadset=", 8) == 0)
883  	            {
884  	               if(loadsetname == nullptr)
885  	               {
886  	                  char* filename = &option[8];
887  	                  loadsetname = new char[strlen(filename) + 1];
888  	                  spxSnprintf(loadsetname, strlen(filename) + 1, "%s", filename);
889  	
890  	                  if(!soplex->loadSettingsFile(loadsetname))
891  	                  {
892  	                     printUsage(argv, optidx);
893  	                     returnValue = 1;
894  	                     goto TERMINATE_FREESTRINGS;
895  	                  }
896  	                  else
897  	                  {
898  	                     // we need to start parsing again because some command line parameters might have been overwritten
899  	                     optidx = 0;
900  	                  }
901  	               }
902  	            }
903  	            // --saveset=<setfile> : save parameters to settings file
904  	            else if(strncmp(option, "saveset=", 8) == 0)
905  	            {
906  	               if(savesetname == nullptr)
907  	               {
908  	                  char* filename = &option[8];
909  	                  savesetname = new char[strlen(filename) + 1];
910  	                  spxSnprintf(savesetname, strlen(filename) + 1, "%s", filename);
911  	               }
912  	            }
913  	            // --diffset=<setfile> : save modified parameters to settings file
914  	            else if(strncmp(option, "diffset=", 8) == 0)
915  	            {
916  	               if(diffsetname == nullptr)
917  	               {
918  	                  char* filename = &option[8];
919  	                  diffsetname = new char[strlen(filename) + 1];
920  	                  spxSnprintf(diffsetname, strlen(filename) + 1, "%s", filename);
921  	               }
922  	            }
923  	            // --readmode=<value> : choose reading mode for <lpfile> (0* - floating-point, 1 - rational)
924  	            else if(strncmp(option, "readmode=", 9) == 0)
925  	            {
926  	               if(!soplex->setIntParam(soplex->READMODE, option[9] - '0'))
927  	               {
928  	                  printUsage(argv, optidx);
929  	                  returnValue = 1;
930  	                  goto TERMINATE_FREESTRINGS;
931  	               }
932  	            }
933  	            // --solvemode=<value> : choose solving mode (0* - floating-point solve, 1 - auto, 2 - force iterative refinement)
934  	            else if(strncmp(option, "solvemode=", 10) == 0)
935  	            {
936  	               if(!soplex->setIntParam(soplex->SOLVEMODE, option[10] - '0'))
937  	               {
938  	                  printUsage(argv, optidx);
939  	                  returnValue = 1;
940  	                  goto TERMINATE_FREESTRINGS;
941  	               }
942  	               // if the LP is parsed rationally and might be solved rationally, we choose automatic syncmode such that
943  	               // the rational LP is kept after reading
944  	               else if(soplex->intParam(soplex->READMODE) == soplex->READMODE_RATIONAL
945  	                       && soplex->intParam(soplex->SOLVEMODE) != soplex->SOLVEMODE_REAL)
946  	               {
947  	                  soplex->setIntParam(soplex->SYNCMODE, soplex->SYNCMODE_AUTO);
948  	               }
949  	            }
950  	            // --extsol=<value> : external solution for soplex to use for validation
951  	            else if(strncmp(option, "extsol=", 7) == 0)
952  	            {
953  	               char* input = &option[7];
954  	
955  	               if(!validation->updateExternalSolution(input))
956  	               {
957  	                  printUsage(argv, optidx);
958  	                  returnValue = 1;
959  	                  goto TERMINATE_FREESTRINGS;
960  	               }
961  	            }
962  	            // --arithmetic=<value> : base arithmetic type, directly handled in main()
963  	            else if(strncmp(option, "arithmetic=", 11) == 0)
964  	            {
965  	               continue;
966  	            }
967  	            // --precision=<value> : arithmetic precision, directly handled in main()
968  	            else if(strncmp(option, "precision=", 10) == 0)
969  	            {
970  	               continue;
971  	            }
972  	            // --<type>:<name>=<val> :  change parameter value using syntax of settings file entries
973  	            else if(!soplex->parseSettingsString(option))
974  	            {
975  	               printUsage(argv, optidx);
976  	               returnValue = 1;
977  	               goto TERMINATE_FREESTRINGS;
978  	            }
979  	
980  	            break;
981  	         }
982  	
983  	         case 't' :
984  	
985  	            // -t<s> : set time limit to <s> seconds
986  	            if(!soplex->setRealParam(soplex->TIMELIMIT, atoi(&option[2])))
987  	            {
988  	               printUsage(argv, optidx);
989  	               returnValue = 1;
990  	               goto TERMINATE_FREESTRINGS;
991  	            }
992  	
993  	            break;
994  	
995  	         case 'i' :
996  	
997  	            // -i<n> : set iteration limit to <n>
998  	            if(!soplex->setIntParam(soplex->ITERLIMIT, atoi(&option[2])))
999  	            {
1000 	               printUsage(argv, optidx);
1001 	               returnValue = 1;
1002 	               goto TERMINATE_FREESTRINGS;
1003 	            }
1004 	
1005 	            break;
1006 	
1007 	         case 'f' :
1008 	
1009 	            // -f<eps> : set primal feasibility tolerance to <eps>
1010 	            if(!soplex->setRealParam(soplex->FEASTOL, atof(&option[2])))
1011 	            {
1012 	               printUsage(argv, optidx);
1013 	               returnValue = 1;
1014 	               goto TERMINATE_FREESTRINGS;
1015 	            }
1016 	
1017 	            break;
1018 	
1019 	         case 'o' :
1020 	
1021 	            // -o<eps> : set dual feasibility (optimality) tolerance to <eps>
1022 	            if(!soplex->setRealParam(soplex->OPTTOL, atof(&option[2])))
1023 	            {
1024 	               printUsage(argv, optidx);
1025 	               returnValue = 1;
1026 	               goto TERMINATE_FREESTRINGS;
1027 	            }
1028 	
1029 	            break;
1030 	
1031 	         case 'l' :
1032 	
1033 	            // l<eps> : set validation tolerance to <eps>
1034 	            if(!validation->updateValidationTolerance(&option[2]))
1035 	            {
1036 	               printUsage(argv, optidx);
1037 	               returnValue = 1;
1038 	               goto TERMINATE_FREESTRINGS;
1039 	            }
1040 	
1041 	            break;
1042 	
1043 	         case 's' :
1044 	
1045 	            // -s<value> : choose simplifier/presolver (0 - off, 1 - internal, 2* - PaPILO)
1046 	            if(!soplex->setIntParam(soplex->SIMPLIFIER, option[2] - '0'))
1047 	            {
1048 	               printUsage(argv, optidx);
1049 	               returnValue = 1;
1050 	               goto TERMINATE_FREESTRINGS;
1051 	            }
1052 	
1053 	            break;
1054 	
1055 	         case 'g' :
1056 	
1057 	            // -g<value> : choose scaling (0 - off, 1 - uni-equilibrium, 2* - bi-equilibrium, 3 - geometric, 4 - iterated geometric,  5 - least squares, 6 - geometric-equilibrium)
1058 	            if(!soplex->setIntParam(soplex->SCALER, option[2] - '0'))
1059 	            {
1060 	               printUsage(argv, optidx);
1061 	               returnValue = 1;
1062 	               goto TERMINATE_FREESTRINGS;
1063 	            }
1064 	
1065 	            break;
1066 	
1067 	         case 'p' :
1068 	
1069 	            // -p<value> : choose pricing (0* - auto, 1 - dantzig, 2 - parmult, 3 - devex, 4 - quicksteep, 5 - steep)
1070 	            if(!soplex->setIntParam(soplex->PRICER, option[2] - '0'))
1071 	            {
1072 	               printUsage(argv, optidx);
1073 	               returnValue = 1;
1074 	               goto TERMINATE_FREESTRINGS;
1075 	            }
1076 	
1077 	            break;
1078 	
1079 	         case 'r' :
1080 	
1081 	            // -r<value> : choose ratio tester (0 - textbook, 1 - harris, 2* - fast, 3 - boundflipping)
1082 	            if(!soplex->setIntParam(soplex->RATIOTESTER, option[2] - '0'))
1083 	            {
1084 	               printUsage(argv, optidx);
1085 	               returnValue = 1;
1086 	               goto TERMINATE_FREESTRINGS;
1087 	            }
1088 	
1089 	            break;
1090 	
1091 	         case 'v' :
1092 	
1093 	            // -v<level> : set verbosity to <level> (0 - error, 3 - normal, 5 - high)
1094 	            if(!soplex->setIntParam(soplex->VERBOSITY, option[2] - '0'))
1095 	            {
1096 	               printUsage(argv, optidx);
1097 	               returnValue = 1;
1098 	               goto TERMINATE_FREESTRINGS;
1099 	            }
1100 	
1101 	            break;
1102 	
1103 	         case 'x' :
1104 	            // -x : print primal solution
1105 	            printPrimal = true;
1106 	
1107 	            if(strncmp(option, "-x=", 3) == 0)
1108 	            {
1109 	               if(primalSolName == nullptr)
1110 	               {
1111 	                  char* filename = &option[3];
1112 	                  primalSolName = new char[strlen(filename) + 1];
1113 	                  spxSnprintf(primalSolName, strlen(filename) + 1, "%s", filename);
1114 	               }
1115 	            }
1116 	
1117 	            break;
1118 	
1119 	         case 'X' :
1120 	            // -X : print primal solution with rationals
1121 	            printPrimalRational = true;
1122 	
1123 	            if(strncmp(option, "-X=", 3) == 0)
1124 	            {
1125 	               if(primalSolNameRational == nullptr)
1126 	               {
1127 	                  char* filename = &option[3];
1128 	                  primalSolNameRational = new char[strlen(filename) + 1];
1129 	                  spxSnprintf(primalSolNameRational, strlen(filename) + 1, "%s", filename);
1130 	               }
1131 	            }
1132 	
1133 	            break;
1134 	
1135 	         case 'y' :
1136 	            // -y : print dual multipliers
1137 	            printDual = true;
1138 	
1139 	            if(strncmp(option, "-y=", 3) == 0)
1140 	            {
1141 	               if(dualSolName == nullptr)
1142 	               {
1143 	                  char* filename = &option[3];
1144 	                  dualSolName = new char[strlen(filename) + 1];
1145 	                  spxSnprintf(dualSolName, strlen(filename) + 1, "%s", filename);
1146 	               }
1147 	            }
1148 	
1149 	            break;
1150 	
1151 	         case 'Y' :
1152 	            // -Y : print dual multipliers with rationals
1153 	            printDualRational = true;
1154 	
1155 	            if(strncmp(option, "-Y=", 3) == 0)
1156 	            {
1157 	               if(dualSolNameRational == nullptr)
1158 	               {
1159 	                  char* filename = &option[3];
1160 	                  dualSolNameRational = new char[strlen(filename) + 1];
1161 	                  spxSnprintf(dualSolNameRational, strlen(filename) + 1, "%s", filename);
1162 	               }
1163 	            }
1164 	
1165 	            break;
1166 	
1167 	         case 'q' :
1168 	            // -q : display detailed statistics
1169 	            displayStatistics = true;
1170 	            break;
1171 	
1172 	         case 'c' :
1173 	            // -c : perform final check of optimal solution in original problem
1174 	            checkSol = true;
1175 	            break;
1176 	
1177 	         case 'h' :
1178 	
1179 	            // -h : display all parameters
1180 	            if(!soplex->saveSettingsFile(0, false))
1181 	            {
1182 	               SPX_MSG_ERROR(std::cerr << "Error printing parameters\n");
1183 	            }
1184 	
1185 	            break;
1186 	
1187 	         //lint -fallthrough
1188 	         default :
1189 	         {
1190 	            printUsage(argv, optidx);
1191 	            returnValue = 1;
1192 	            goto TERMINATE_FREESTRINGS;
1193 	         }
1194 	         }
1195 	      }
1196 	
1197 	      SPX_MSG_INFO1(soplex->spxout, soplex->printUserSettings();)
1198 	
1199 	      // no LP file was given and no settings files are written
1200 	      if(lpfilename == nullptr && savesetname == nullptr && diffsetname == nullptr)
1201 	      {
1202 	         printUsage(argv, 0);
1203 	         returnValue = 1;
1204 	         goto TERMINATE_FREESTRINGS;
1205 	      }
1206 	
1207 	      // ensure that syncmode is not manual
1208 	      if(soplex->intParam(soplex->SYNCMODE) == soplex->SYNCMODE_MANUAL)
1209 	      {
1210 	         SPX_MSG_ERROR(std::cerr <<
1211 	                       "Error: manual synchronization is invalid on command line.  Change parameter int:syncmode.\n");
1212 	         returnValue = 1;
1213 	         goto TERMINATE_FREESTRINGS;
1214 	      }
1215 	
1216 	      // save settings files
1217 	      if(savesetname != nullptr)
1218 	      {
1219 	         SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "Saving parameters to settings file <" <<
1220 	                       savesetname <<
1221 	                       "> . . .\n");
1222 	
1223 	         if(!soplex->saveSettingsFile(savesetname, false))
1224 	         {
1225 	            SPX_MSG_ERROR(std::cerr << "Error writing parameters to file <" << savesetname << ">\n");
1226 	         }
1227 	      }
1228 	
1229 	      if(diffsetname != nullptr)
1230 	      {
1231 	         SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "Saving modified parameters to settings file <" <<
1232 	                       diffsetname << "> . . .\n");
1233 	
1234 	         if(!soplex->saveSettingsFile(diffsetname, true))
1235 	         {
1236 	            SPX_MSG_ERROR(std::cerr << "Error writing modified parameters to file <" << diffsetname << ">\n");
1237 	         }
1238 	      }
1239 	
1240 	      // no LP file given: exit after saving settings
1241 	      if(lpfilename == nullptr)
1242 	      {
1243 	         if(loadsetname != nullptr || savesetname != nullptr || diffsetname != nullptr)
1244 	         {
1245 	            SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "\n");
1246 	         }
1247 	
1248 	         goto TERMINATE_FREESTRINGS;
1249 	      }
1250 	
1251 	      // measure time for reading LP file and basis file
1252 	      readingTime->start();
1253 	
1254 	      // if the LP is parsed rationally and might be solved rationally, we choose automatic syncmode such that
1255 	      // the rational LP is kept after reading
1256 	      if(soplex->intParam(soplex->READMODE) == soplex->READMODE_RATIONAL
1257 	            && soplex->intParam(soplex->SOLVEMODE) != soplex->SOLVEMODE_REAL)
1258 	      {
1259 	         soplex->setIntParam(soplex->SYNCMODE, soplex->SYNCMODE_AUTO);
1260 	      }
1261 	
1262 	      // read LP from input file
1263 	      SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "Reading "
1264 	                    << (soplex->intParam(soplex->READMODE) == soplex->READMODE_REAL ? "(real)" : "(rational)")
1265 	                    << " LP file <" << lpfilename << "> . . .\n");
1266 	
1267 	      if(!soplex->readFile(lpfilename, &rownames, &colnames))
1268 	      {
1269 	         SPX_MSG_ERROR(std::cerr << "Error while reading file <" << lpfilename << ">.\n");
1270 	         returnValue = 1;
1271 	         goto TERMINATE_FREESTRINGS;
1272 	      }
1273 	
1274 	      // write LP if specified
1275 	      if(writefilename != nullptr)
1276 	      {
1277 	         if(!soplex->writeFile(writefilename, &rownames, &colnames))
1278 	         {
1279 	            SPX_MSG_ERROR(std::cerr << "Error while writing file <" << writefilename << ">.\n\n");
1280 	            returnValue = 1;
1281 	            goto TERMINATE_FREESTRINGS;
1282 	         }
1283 	         else
1284 	         {
1285 	            SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "Written LP to file <" << writefilename <<
1286 	                          ">.\n\n");
1287 	         }
1288 	      }
1289 	
1290 	      // write dual LP if specified
1291 	      if(writedualfilename != nullptr)
1292 	      {
1293 	         if(!soplex->writeDualFileReal(writedualfilename, &rownames, &colnames))
1294 	         {
1295 	            SPX_MSG_ERROR(std::cerr << "Error while writing dual file <" << writedualfilename << ">.\n\n");
1296 	            returnValue = 1;
1297 	            goto TERMINATE_FREESTRINGS;
1298 	         }
1299 	         else
1300 	         {
1301 	            SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "Written dual LP to file <" << writedualfilename <<
1302 	                          ">.\n\n");
1303 	         }
1304 	      }
1305 	
1306 	      // read basis file if specified
1307 	      if(readbasname != nullptr)
1308 	      {
1309 	         SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "Reading basis file <" << readbasname <<
1310 	                       "> . . . ");
1311 	
1312 	         if(!soplex->readBasisFile(readbasname, &rownames, &colnames))
1313 	         {
1314 	            SPX_MSG_ERROR(std::cerr << "Error while reading file <" << readbasname << ">.\n");
1315 	            returnValue = 1;
1316 	            goto TERMINATE_FREESTRINGS;
1317 	         }
1318 	      }
1319 	
1320 	      readingTime->stop();
1321 	
1322 	      SPX_MSG_INFO1(soplex->spxout,
1323 	                    std::streamsize prec = soplex->spxout.precision();
1324 	                    soplex->spxout << "Reading took "
1325 	                    << std::fixed << std::setprecision(2) << readingTime->time()
1326 	                    << std::scientific << std::setprecision(int(prec))
1327 	                    << " seconds.\n\n");
1328 	
1329 	      SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "LP has " << soplex->numRows() << " rows "
1330 	                    << soplex->numCols() << " columns and " << soplex->numNonzeros() << " nonzeros.\n\n");
1331 	
1332 	      // solve the LP
1333 	      soplex->optimize();
1334 	
1335 	      // print solution to stdout, check solution, and display statistics
1336 	      if(primalSolName == nullptr && primalSolNameRational == nullptr)
1337 	         printPrimalSolution(*soplex, colnames, rownames, printPrimal, printPrimalRational);
1338 	
1339 	      // print fp solution to file primalSolName
1340 	      if(primalSolName != nullptr)
1341 	         writePrimalSolution(*soplex, primalSolName, colnames, rownames, true, false, false);
1342 	
1343 	      bool append;
1344 	
1345 	      // print rational solution to file primalSolNameRational
1346 	      if(primalSolNameRational != nullptr)
1347 	      {
1348 	         append = primalSolName != nullptr && strcmp(primalSolName, primalSolNameRational) == 0;
1349 	         writePrimalSolution(*soplex, primalSolNameRational, colnames, rownames, false, true, append);
1350 	      }
1351 	
1352 	      // print dual solution to stdout, check solution, and display statistics
1353 	      if(dualSolName == nullptr && dualSolNameRational == nullptr)
1354 	         printDualSolution(*soplex, colnames, rownames, printDual, printDualRational);
1355 	
1356 	      // print fp solution to file dualSolName
1357 	      if(dualSolName != nullptr)
1358 	      {
1359 	         append = primalSolName != nullptr && strcmp(dualSolName, primalSolName) == 0;
1360 	         append = append || (primalSolNameRational != nullptr
1361 	                             && strcmp(dualSolName, primalSolNameRational) == 0);
1362 	         writeDualSolution(*soplex, dualSolName, colnames, rownames, true, false, append);
1363 	      }
1364 	
1365 	      // print rational solution to file dualSolNameRational
1366 	      if(dualSolNameRational != nullptr)
1367 	      {
1368 	         append = (primalSolName != nullptr && strcmp(dualSolNameRational, primalSolName) == 0);
1369 	         append = append || (primalSolNameRational != nullptr
1370 	                             && strcmp(dualSolNameRational, primalSolNameRational) == 0);
1371 	         append = append || (dualSolName != nullptr && strcmp(dualSolNameRational, dualSolName) == 0);
1372 	         writeDualSolution(*soplex, dualSolNameRational, colnames, rownames, false, true, append);
1373 	      }
1374 	
1375 	      if(checkSol)
1376 	         checkSolution<R>(*soplex); // The type needs to get fixed here
1377 	
1378 	      if(displayStatistics)
1379 	      {
1380 	         SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "Statistics\n==========\n\n");
1381 	         soplex->printStatistics(soplex->spxout.getStream(SPxOut::INFO1));
1382 	      }
1383 	
1384 	      if(validation->validate)
1385 	         validation->validateSolveReal(*soplex);
1386 	
1387 	      // write basis file if specified
1388 	      if(writebasname != nullptr)
1389 	      {
1390 	         if(!soplex->hasBasis())
1391 	         {
1392 	            SPX_MSG_WARNING(soplex->spxout, soplex->spxout <<
1393 	                            "No basis information available.  Could not write file <" << writebasname << ">\n\n");
1394 	         }
1395 	         else if(!soplex->writeBasisFile(writebasname, &rownames, &colnames))
1396 	         {
1397 	            SPX_MSG_ERROR(std::cerr << "Error while writing file <" << writebasname << ">.\n\n");
1398 	            returnValue = 1;
1399 	            goto TERMINATE_FREESTRINGS;
1400 	         }
1401 	         else
1402 	         {
1403 	            SPX_MSG_INFO1(soplex->spxout, soplex->spxout << "Written basis information to file <" <<
1404 	                          writebasname <<
1405 	                          ">.\n\n");
1406 	         }
1407 	      }
1408 	   }
1409 	   catch(const SPxException& x)
1410 	   {
1411 	      SPX_MSG_ERROR(std::cerr << "Exception caught: " << x.what() << "\n");
1412 	      returnValue = 1;
1413 	      goto TERMINATE_FREESTRINGS;
1414 	   }
1415 	
1416 	TERMINATE_FREESTRINGS:
1417 	   freeStrings(readbasname, writebasname, loadsetname, savesetname, diffsetname);
1418 	   freeStrings(primalSolName, dualSolName, primalSolName, primalSolName, primalSolName);
1419 	
1420 	TERMINATE:
1421 	
1422 	   // because EGlpNumClear() calls mpq_clear() for all mpq_t variables, we need to destroy all objects of class Rational
1423 	   // beforehand; hence all Rational objects and all data that uses Rational objects must be allocated dynamically via
1424 	   // spx_alloc() and freed here; disabling the list memory is crucial
1425 	   if(nullptr != soplex)
1426 	   {
1427 	      soplex->~SoPlexBase();
1428 	      spx_free(soplex);
1429 	   }
1430 	
1431 	   if(nullptr != validation)
1432 	   {
1433 	      validation->~Validation();
1434 	      spx_free(validation);
1435 	   }
1436 	
1437 	   if(nullptr != readingTime)
1438 	   {
1439 	      readingTime->~Timer();
1440 	      spx_free(readingTime);
1441 	   }
1442 	
1443 	   return returnValue;
1444 	}
1445 	
1446 	/// runs SoPlexBase command line
1447 	int main(int argc, char* argv[])
1448 	{
1449 	   int arithmetic = 0;
1450 	   int precision = 0;
1451 	   int optidx;
1452 	
1453 	   // find out which precision/solvemode soplex should be run in. the rest happens in runSoPlex
1454 	   // no options were given
1455 	   if(argc <= 1)
1456 	   {
1457 	      printUsage(argv, 0);
1458 	      return 1;
1459 	   }
1460 	
1461 	   // read arguments from command line
1462 	   for(optidx = 1; optidx < argc; optidx++)
1463 	   {
1464 	      char* option = argv[optidx];
1465 	
1466 	      // we reached <lpfile>
1467 	      if(option[0] != '-')
1468 	         continue;
1469 	
1470 	      // option string must start with '-', must contain at least two characters, and exactly two characters if and
1471 	      // only if it is -q, or -c
1472 	      if(option[0] != '-' || option[1] == '\0'
1473 	            || ((option[2] == '\0') != (option[1] == 'q' || option[1] == 'c')))
1474 	      {
1475 	         printUsage(argv, optidx);
1476 	         return 1;
1477 	      }
1478 	
1479 	      switch(option[1])
1480 	      {
1481 	      case '-' :
1482 	         option = &option[2];
1483 	
1484 	         // --arithmetic=<value> : choose base arithmetic type (0 - double, 1 - quadprecision, 2 - higher multiprecision)
1485 	         // only need to do something here if multi or quad, the rest is handled in runSoPlex
1486 	         if(strncmp(option, "arithmetic=", 11) == 0)
1487 	         {
1488 	            if(option[11] == '1')
1489 	            {
1490 	#ifndef SOPLEX_WITH_FLOAT128
1491 	               SPX_MSG_ERROR(std::cerr <<
1492 	                             "Cannot set arithmetic type to quadprecision - Soplex compiled without quadprecision support\n";)
1493 	               printUsage(argv, 0);
1494 	               return 1;
1495 	#else
1496 	               arithmetic = 1;
1497 	#endif
1498 	            }
1499 	            else if(option[11] == '2')
1500 	            {
1501 	#ifndef SOPLEX_WITH_BOOST
1502 	               SPX_MSG_ERROR(std::cerr <<
1503 	                             "Cannot set arithmetic type to multiprecision - Soplex compiled without boost\n";)
1504 	               printUsage(argv, 0);
1505 	               return 1;
1506 	#else
1507 	               arithmetic = 2;
1508 	
1509 	               // default precision in multiprecision solve is 50
1510 	               if(precision == 0)
1511 	                  precision = 50;
1512 	
1513 	#endif
1514 	            }
1515 	         }
1516 	         // set precision
1517 	         else if(strncmp(option, "precision=", 10) == 0)
1518 	         {
1519 	            precision = atoi(option + 10);
1520 	#ifndef SOPLEX_WITH_BOOST
1521 	            SPX_MSG_ERROR(std::cerr << "Setting precision to non-default value without Boost has no effect\n";)
1522 	#endif
1523 	         }
1524 	
1525 	         break;
1526 	
1527 	      default:
1528 	         break;
1529 	      }
1530 	   }
1531 	
1532 	   if(precision != 0 && arithmetic != 2)
1533 	   {
1534 	      SPX_MSG_ERROR(std::cerr <<
1535 	                    "Setting precision to non-default value without enabling multiprecision solve has no effect\n";)
1536 	   }
1537 	
1538 	   switch(arithmetic)
1539 	   {
1540 	   case 0:                 // double
1541 	      runSoPlex<Real>(argc, argv);
1542 	      break;
1543 	
1544 	#ifdef SOPLEX_WITH_BOOST
1545 	#ifdef SOPLEX_WITH_FLOAT128
1546 	
1547 	   case 1:                // quadprecision
1548 	#if BOOST_VERSION < 107000
1549 	      std::cerr << "Error: Boost version too old." << std:: endl <<
1550 	                "In order to use the quadprecision feature of SoPlex," <<
1551 	                " Boost Version 1.70.0 or higher is required." << std::endl << \
1552 	                "Included Boost version is " << BOOST_VERSION / 100000 << "."  // maj. version
1553 	                << BOOST_VERSION / 100 % 1000 << "."  // min. version
1554 	                << BOOST_VERSION % 100                // patch version;
1555 	                << std::endl;
1556 	#else
1557 	      using namespace boost::multiprecision;
1558 	      using Quad = boost::multiprecision::float128;
1559 	      runSoPlex<Quad>(argc, argv);
1560 	#endif
1561 	      break;
1562 	#endif
1563 	
1564 	   case 2:                 // soplex mpf
1565 	      using namespace boost::multiprecision;
1566 	
1567 	#if BOOST_VERSION < 107000
1568 	      std::cerr << "Error: Boost version too old." << std:: endl <<
1569 	                "In order to use the multiprecision feature of SoPlex," <<
1570 	                " Boost Version 1.70.0 or higher is required." << std::endl << \
1571 	                "Included Boost version is " << BOOST_VERSION / 100000 << "."  // maj. version
1572 	                << BOOST_VERSION / 100 % 1000 << "."  // min. version
1573 	                << BOOST_VERSION % 100                // patch version;
1574 	                << std::endl;
1575 	#else
1576 	#ifdef SOPLEX_WITH_MPFR
1577 	
1578 	      // et_off means the expression templates options is turned off. TODO:
1579 	      // The documentation also mentions about static vs dynamic memory
1580 	      // allocation for the mpfr types. Is it relevant here? I probably also
1581 	      // need to have the mpfr_float_eto in the global soplex namespace
1582 	      using multiprecision = number<mpfr_float_backend<0>, et_off>;
1583 	      multiprecision::default_precision(precision);
1584 	      runSoPlex<multiprecision>(argc, argv);
1585 	#endif  // SOPLEX_WITH_MPFR
1586 	
1587 	#ifdef SOPLEX_WITH_CPPMPF
1588 	      // It seems that precision cannot be set on run time for cpp_float
1589 	      // backend for boost::number. So a precision of 50 decimal points is
1590 	      // set.
1591 	      using multiprecision1 = number<cpp_dec_float<50>, et_off>;
1592 	      using multiprecision2 = number<cpp_dec_float<100>, et_off>;
1593 	      using multiprecision3 = number<cpp_dec_float<200>, et_off>;
1594 	
1595 	      if(precision <= 50)
1596 	         runSoPlex<multiprecision1>(argc, argv);
1597 	      else if(precision <= 100)
1598 	         runSoPlex<multiprecision2>(argc, argv);
1599 	      else
1600 	         runSoPlex<multiprecision3>(argc, argv);
1601 	
1602 	#endif  // SOPLEX_WITH_CPPMPF
1603 	#endif
1604 	      break;
1605 	#endif
1606 	
1607 	   // coverity[dead_error_begin]
1608 	   default:
1609 	      std::cerr << "Wrong value for the arithmetic mode\n";
1610 	      return 0;
1611 	   }
1612 	}
1613