1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the class library                   */
4    	/*       SoPlex --- the Sequential object-oriented simPlex.                  */
5    	/*                                                                           */
6    	/*    Copyright (C) 1996-2021 Konrad-Zuse-Zentrum                            */
7    	/*                            fuer Informationstechnik Berlin                */
8    	/*                                                                           */
9    	/*  SoPlex is distributed under the terms of the ZIB Academic Licence.       */
10   	/*                                                                           */
11   	/*  You should have received a copy of the ZIB Academic License              */
12   	/*  along with SoPlex; see the file COPYING. If not email to soplex@zib.de.  */
13   	/*                                                                           */
14   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15   	
16   	#include <iostream>
17   	#include <assert.h>
18   	
19   	#include "soplex.h"
20   	#include "soplex/statistics.h"
21   	#include "soplex/slufactor_rational.h"
22   	#include "soplex/ratrecon.h"
23   	
24   	namespace soplex
25   	{
26   	
27   	/// solves rational LP
28   	template <class R>
29   	void SoPlexBase<R>::_optimizeRational(volatile bool* interrupt)
30   	{
31   	   bool hasUnboundedRay = false;
32   	   bool infeasibilityNotCertified = false;
33   	   bool unboundednessNotCertified = false;
34   	
35   	   // start timing
36   	   _statistics->solvingTime->start();
37   	   _statistics->preprocessingTime->start();
38   	
39   	   // remember that last solve was rational
40   	   _lastSolveMode = SOLVEMODE_RATIONAL;
41   	
42   	   // ensure that the solver has the original problemo
43   	   if(!_isRealLPLoaded)
44   	   {
45   	      assert(_realLP != &_solver);
46   	
47   	      _solver.loadLP(*_realLP);
48   	      spx_free(_realLP);
49   	      _realLP = &_solver;
50   	      _isRealLPLoaded = true;
51   	   }
52   	   // during the rational solve, we always store basis information in the basis arrays
53   	   else if(_hasBasis)
54   	   {
55   	      _basisStatusRows.reSize(numRows());
56   	      _basisStatusCols.reSize(numCols());
57   	      _solver.getBasis(_basisStatusRows.get_ptr(), _basisStatusCols.get_ptr(), _basisStatusRows.size(),
58   	                       _basisStatusCols.size());
59   	   }
60   	
61   	   // store objective, bounds, and sides of Real LP in case they will be modified during iterative refinement
62   	   _storeLPReal();
63   	
64   	   // deactivate objective limit in floating-point solver
65   	   if(realParam(SoPlexBase<R>::OBJLIMIT_LOWER) > -realParam(SoPlexBase<R>::INFTY)
66   	         || realParam(SoPlexBase<R>::OBJLIMIT_UPPER) < realParam(SoPlexBase<R>::INFTY))
67   	   {
68   	      MSG_INFO2(spxout, spxout << "Deactivating objective limit.\n");
69   	   }
70   	
71   	   _solver.setTerminationValue(realParam(SoPlexBase<R>::INFTY));
72   	
73   	   _statistics->preprocessingTime->stop();
74   	
75   	   // apply lifting to reduce range of nonzero matrix coefficients
76   	   if(boolParam(SoPlexBase<R>::LIFTING))
77   	      _lift();
78   	
79   	   // force column representation
80   	   ///@todo implement row objectives with row representation
81   	   int oldRepresentation = intParam(SoPlexBase<R>::REPRESENTATION);
82   	   setIntParam(SoPlexBase<R>::REPRESENTATION, SoPlexBase<R>::REPRESENTATION_COLUMN);
83   	
84   	   // force ratio test (avoid bound flipping)
85   	   int oldRatiotester = intParam(SoPlexBase<R>::RATIOTESTER);
86   	   setIntParam(SoPlexBase<R>::RATIOTESTER, SoPlexBase<R>::RATIOTESTER_FAST);
87   	
88   	   ///@todo implement handling of row objectives in Cplex interface
89   	#ifdef SOPLEX_WITH_CPX
90   	   int oldEqtrans = boolParam(SoPlexBase<R>::EQTRANS);
91   	   setBoolParam(SoPlexBase<R>::EQTRANS, true);
92   	#endif
93   	
94   	   // introduce slack variables to transform inequality constraints into equations
95   	   if(boolParam(SoPlexBase<R>::EQTRANS))
96   	      _transformEquality();
97   	
98   	   _storedBasis = false;
99   	
100  	   bool stoppedTime;
101  	   bool stoppedIter;
102  	
103  	   do
104  	   {
105  	      bool primalFeasible = false;
106  	      bool dualFeasible = false;
107  	      bool infeasible = false;
108  	      bool unbounded = false;
109  	      bool error = false;
110  	      stoppedTime = false;
111  	      stoppedIter = false;
112  	
113  	      // solve problem with iterative refinement and recovery mechanism
(4) Event template_instantiation_context: instantiation of "void soplex::SoPlexBase<R>::_performOptIRStable(soplex::SolRational &, bool, bool, int, bool &, bool &, bool &, bool &, bool &, bool &, bool &) [with R=soplex::Real]" at line 114
Also see events: [switch_selector_expr_is_constant][caretline][template_instantiation_context][template_instantiation_context][template_instantiation_context]
114  	      _performOptIRStable(_solRational, !unboundednessNotCertified, !infeasibilityNotCertified, 0,
115  	                          primalFeasible, dualFeasible, infeasible, unbounded, stoppedTime, stoppedIter, error);
116  	
117  	      // case: an unrecoverable error occured
118  	      if(error)
119  	      {
120  	         _status = SPxSolverBase<R>::ERROR;
121  	         break;
122  	      }
123  	      // case: stopped due to some limit
124  	      else if(stoppedTime)
125  	      {
126  	         _status = SPxSolverBase<R>::ABORT_TIME;
127  	         break;
128  	      }
129  	      else if(stoppedIter)
130  	      {
131  	         _status = SPxSolverBase<R>::ABORT_ITER;
132  	         break;
133  	      }
134  	      // case: unboundedness detected for the first time
135  	      else if(unbounded && !unboundednessNotCertified)
136  	      {
137  	         SolRational solUnbounded;
138  	
139  	         _performUnboundedIRStable(solUnbounded, hasUnboundedRay, stoppedTime, stoppedIter, error);
140  	
141  	         assert(!hasUnboundedRay || solUnbounded.hasPrimalRay());
142  	         assert(!solUnbounded.hasPrimalRay() || hasUnboundedRay);
143  	
144  	         if(error)
145  	         {
146  	            MSG_INFO1(spxout, spxout << "Error while testing for unboundedness.\n");
147  	            _status = SPxSolverBase<R>::ERROR;
148  	            break;
149  	         }
150  	
151  	         if(hasUnboundedRay)
152  	         {
153  	            MSG_INFO1(spxout, spxout << "Dual infeasible.  Primal unbounded ray available.\n");
154  	         }
155  	         else
156  	         {
157  	            MSG_INFO1(spxout, spxout << "Dual feasible.  Rejecting primal unboundedness.\n");
158  	         }
159  	
160  	         unboundednessNotCertified = !hasUnboundedRay;
161  	
162  	         if(stoppedTime)
163  	         {
164  	            _status = SPxSolverBase<R>::ABORT_TIME;
165  	            break;
166  	         }
167  	         else if(stoppedIter)
168  	         {
169  	            _status = SPxSolverBase<R>::ABORT_ITER;
170  	            break;
171  	         }
172  	
173  	         _performFeasIRStable(_solRational, infeasible, stoppedTime, stoppedIter, error);
174  	
175  	         ///@todo this should be stored already earlier, possible switch use solRational above and solFeas here
176  	         if(hasUnboundedRay)
177  	         {
178  	            _solRational._primalRay = solUnbounded._primalRay;
179  	            _solRational._hasPrimalRay = true;
180  	         }
181  	
182  	         if(error)
183  	         {
184  	            MSG_INFO1(spxout, spxout << "Error while testing for feasibility.\n");
185  	            _status = SPxSolverBase<R>::ERROR;
186  	            break;
187  	         }
188  	         else if(stoppedTime)
189  	         {
190  	            _status = SPxSolverBase<R>::ABORT_TIME;
191  	            break;
192  	         }
193  	         else if(stoppedIter)
194  	         {
195  	            _status = SPxSolverBase<R>::ABORT_ITER;
196  	            break;
197  	         }
198  	         else if(infeasible)
199  	         {
200  	            MSG_INFO1(spxout, spxout << "Primal infeasible.  Dual Farkas ray available.\n");
201  	            _status = SPxSolverBase<R>::INFEASIBLE;
202  	            break;
203  	         }
204  	         else if(hasUnboundedRay)
205  	         {
206  	            MSG_INFO1(spxout, spxout << "Primal feasible and unbounded.\n");
207  	            _status = SPxSolverBase<R>::UNBOUNDED;
208  	            break;
209  	         }
210  	         else
211  	         {
212  	            MSG_INFO1(spxout, spxout << "Primal feasible and bounded.\n");
213  	            continue;
214  	         }
215  	      }
216  	      // case: infeasibility detected
217  	      else if(infeasible && !infeasibilityNotCertified)
218  	      {
219  	         _storeBasis();
220  	
221  	         _performFeasIRStable(_solRational, infeasible, stoppedTime, stoppedIter, error);
222  	
223  	         if(error)
224  	         {
225  	            MSG_INFO1(spxout, spxout << "Error while testing for infeasibility.\n");
226  	            _status = SPxSolverBase<R>::ERROR;
227  	            _restoreBasis();
228  	            break;
229  	         }
230  	
231  	         infeasibilityNotCertified = !infeasible;
232  	
233  	         if(stoppedTime)
234  	         {
235  	            _status = SPxSolverBase<R>::ABORT_TIME;
236  	            _restoreBasis();
237  	            break;
238  	         }
239  	         else if(stoppedIter)
240  	         {
241  	            _status = SPxSolverBase<R>::ABORT_ITER;
242  	            _restoreBasis();
243  	            break;
244  	         }
245  	
246  	         if(infeasible && boolParam(SoPlexBase<R>::TESTDUALINF))
247  	         {
248  	            SolRational solUnbounded;
249  	
250  	            _performUnboundedIRStable(solUnbounded, hasUnboundedRay, stoppedTime, stoppedIter, error);
251  	
252  	            assert(!hasUnboundedRay || solUnbounded.hasPrimalRay());
253  	            assert(!solUnbounded.hasPrimalRay() || hasUnboundedRay);
254  	
255  	            if(error)
256  	            {
257  	               MSG_INFO1(spxout, spxout << "Error while testing for dual infeasibility.\n");
258  	               _status = SPxSolverBase<R>::ERROR;
259  	               _restoreBasis();
260  	               break;
261  	            }
262  	
263  	            if(hasUnboundedRay)
264  	            {
265  	               MSG_INFO1(spxout, spxout << "Dual infeasible.  Primal unbounded ray available.\n");
266  	               _solRational._primalRay = solUnbounded._primalRay;
267  	               _solRational._hasPrimalRay = true;
268  	            }
269  	            else if(solUnbounded._isDualFeasible)
270  	            {
271  	               MSG_INFO1(spxout, spxout << "Dual feasible.  Storing dual multipliers.\n");
272  	               _solRational._dual = solUnbounded._dual;
273  	               _solRational._redCost = solUnbounded._redCost;
274  	               _solRational._isDualFeasible = true;
275  	            }
276  	            else
277  	            {
278  	               assert(false);
279  	               MSG_INFO1(spxout, spxout << "Not dual infeasible.\n");
280  	            }
281  	         }
282  	
283  	         _restoreBasis();
284  	
285  	         if(infeasible)
286  	         {
287  	            MSG_INFO1(spxout, spxout << "Primal infeasible.  Dual Farkas ray available.\n");
288  	            _status = SPxSolverBase<R>::INFEASIBLE;
289  	            break;
290  	         }
291  	         else if(hasUnboundedRay)
292  	         {
293  	            MSG_INFO1(spxout, spxout << "Primal feasible and unbounded.\n");
294  	            _status = SPxSolverBase<R>::UNBOUNDED;
295  	            break;
296  	         }
297  	         else
298  	         {
299  	            MSG_INFO1(spxout, spxout << "Primal feasible.  Optimizing again.\n");
300  	            continue;
301  	         }
302  	      }
303  	      else if(primalFeasible && dualFeasible)
304  	      {
305  	         MSG_INFO1(spxout, spxout << "Solved to optimality.\n");
306  	         _status = SPxSolverBase<R>::OPTIMAL;
307  	         break;
308  	      }
309  	      else
310  	      {
311  	         MSG_INFO1(spxout, spxout << "Terminating without success.\n");
312  	         break;
313  	      }
314  	   }
315  	   while(!_isSolveStopped(stoppedTime, stoppedIter));
316  	
317  	   ///@todo set status to ABORT_VALUE if optimal solution exceeds objective limit
318  	
319  	   if(_status == SPxSolverBase<R>::OPTIMAL || _status == SPxSolverBase<R>::INFEASIBLE
320  	         || _status == SPxSolverBase<R>::UNBOUNDED)
321  	      _hasSolRational = true;
322  	
323  	   // restore original problem
324  	   if(boolParam(SoPlexBase<R>::EQTRANS))
325  	      _untransformEquality(_solRational);
326  	
327  	#ifdef SOPLEX_WITH_CPX
328  	   setBoolParam(SoPlexBase<R>::EQTRANS, oldEqtrans);
329  	#endif
330  	
331  	   // reset representation and ratio test
332  	   setIntParam(SoPlexBase<R>::REPRESENTATION, oldRepresentation);
333  	   setIntParam(SoPlexBase<R>::RATIOTESTER, oldRatiotester);
334  	
335  	   // undo lifting
336  	   if(boolParam(SoPlexBase<R>::LIFTING))
337  	      _project(_solRational);
338  	
339  	   // restore objective, bounds, and sides of Real LP in case they have been modified during iterative refinement
340  	   _restoreLPReal();
341  	
342  	   // since the Real LP is loaded in the solver, we need to also pass the basis information to the solver if
343  	   // available
344  	   if(_hasBasis)
345  	   {
346  	      assert(_isRealLPLoaded);
347  	      _solver.setBasis(_basisStatusRows.get_const_ptr(), _basisStatusCols.get_const_ptr());
348  	      _hasBasis = (_solver.basis().status() > SPxBasisBase<R>::NO_PROBLEM);
349  	
350  	      // since setBasis always sets the basis status to regular, we need to set it manually here
351  	      switch(_status)
352  	      {
353  	      case SPxSolverBase<R>::OPTIMAL:
354  	         _solver.setBasisStatus(SPxBasisBase<R>::OPTIMAL);
355  	         break;
356  	
357  	      case SPxSolverBase<R>::INFEASIBLE:
358  	         _solver.setBasisStatus(SPxBasisBase<R>::INFEASIBLE);
359  	         break;
360  	
361  	      case SPxSolverBase<R>::UNBOUNDED:
362  	         _solver.setBasisStatus(SPxBasisBase<R>::UNBOUNDED);
363  	         break;
364  	
365  	      default:
366  	         break;
367  	      }
368  	
369  	   }
370  	
371  	   // stop timing
372  	   _statistics->solvingTime->stop();
373  	}
374  	
375  	
376  	
377  	/// solves current problem with iterative refinement and recovery mechanism
378  	template <class R>
379  	void SoPlexBase<R>::_performOptIRStable(
380  	   SolRational& sol,
381  	   bool acceptUnbounded,
382  	   bool acceptInfeasible,
383  	   int minRounds,
384  	   bool& primalFeasible,
385  	   bool& dualFeasible,
386  	   bool& infeasible,
387  	   bool& unbounded,
388  	   bool& stoppedTime,
389  	   bool& stoppedIter,
390  	   bool& error)
391  	{
392  	   // start rational solving timing
393  	   _statistics->rationalTime->start();
394  	
395  	   primalFeasible = false;
396  	   dualFeasible = false;
397  	   infeasible = false;
398  	   unbounded = false;
399  	   stoppedTime = false;
400  	   stoppedIter = false;
401  	   error = false;
402  	
403  	   // set working tolerances in floating-point solver
404  	   _solver.setFeastol(realParam(SoPlexBase<R>::FPFEASTOL));
405  	   _solver.setOpttol(realParam(SoPlexBase<R>::FPOPTTOL));
406  	
407  	   // declare vectors and variables
408  	   typename SPxSolverBase<R>::Status result = SPxSolverBase<R>::UNKNOWN;
409  	
410  	   _modLower.reDim(numColsRational(), false);
411  	   _modUpper.reDim(numColsRational(), false);
412  	   _modLhs.reDim(numRowsRational(), false);
413  	   _modRhs.reDim(numRowsRational(), false);
414  	   _modObj.reDim(numColsRational(), false);
415  	
416  	   VectorBase<R> primalReal(numColsRational());
417  	   VectorBase<R> dualReal(numRowsRational());
418  	
419  	   Rational boundsViolation;
420  	   Rational sideViolation;
421  	   Rational redCostViolation;
422  	   Rational dualViolation;
423  	   Rational primalScale;
424  	   Rational dualScale;
425  	   Rational maxScale;
426  	
427  	   // solve original LP
428  	   MSG_INFO1(spxout, spxout << "Initial floating-point solve . . .\n");
429  	
430  	   if(_hasBasis)
431  	   {
432  	      assert(_basisStatusRows.size() == numRowsRational());
433  	      assert(_basisStatusCols.size() == numColsRational());
434  	      _solver.setBasis(_basisStatusRows.get_const_ptr(), _basisStatusCols.get_const_ptr());
435  	      _hasBasis = (_solver.basis().status() > SPxBasisBase<R>::NO_PROBLEM);
436  	   }
437  	
438  	   for(int r = numRowsRational() - 1; r >= 0; r--)
439  	   {
440  	      assert(_solver.maxRowObj(r) == 0.0);
441  	   }
442  	
443  	   _statistics->rationalTime->stop();
(3) Event template_instantiation_context: instantiation of "soplex::SPxSolverBase<R>::Status soplex::SoPlexBase<R>::_solveRealStable(bool, bool, soplex::VectorBase<R> &, soplex::VectorBase<R> &, soplex::DataArray<soplex::SPxSolverBase<R>::VarStatus> &, soplex::DataArray<soplex::SPxSolverBase<R>::VarStatus> &, bool) [with R=soplex::Real]" at line 444
Also see events: [switch_selector_expr_is_constant][caretline][template_instantiation_context][template_instantiation_context][template_instantiation_context]
444  	   result = _solveRealStable(acceptUnbounded, acceptInfeasible, primalReal, dualReal, _basisStatusRows,
445  	                             _basisStatusCols);
446  	
447  	   // evaluate result
448  	   switch(result)
449  	   {
450  	   case SPxSolverBase<R>::OPTIMAL:
451  	      MSG_INFO1(spxout, spxout << "Floating-point optimal.\n");
452  	      break;
453  	
454  	   case SPxSolverBase<R>::INFEASIBLE:
455  	      MSG_INFO1(spxout, spxout << "Floating-point infeasible.\n");
456  	
457  	      // the floating-point solve returns a Farkas ray if and only if the simplifier was not used, which is exactly
458  	      // the case when a basis could be returned
459  	      if(_hasBasis)
460  	      {
461  	         sol._dualFarkas = dualReal;
462  	         sol._hasDualFarkas = true;
463  	      }
464  	      else
465  	         sol._hasDualFarkas = false;
466  	
467  	      infeasible = true;
468  	      return;
469  	
470  	   case SPxSolverBase<R>::UNBOUNDED:
471  	      MSG_INFO1(spxout, spxout << "Floating-point unbounded.\n");
472  	      unbounded = true;
473  	      return;
474  	
475  	   case SPxSolverBase<R>::ABORT_TIME:
476  	      stoppedTime = true;
477  	      return;
478  	
479  	   case SPxSolverBase<R>::ABORT_ITER:
480  	      stoppedIter = true;
481  	      return;
482  	
483  	   default:
484  	      error = true;
485  	      return;
486  	   }
487  	
488  	   _statistics->rationalTime->start();
489  	
490  	   // store floating-point solution of original LP as current rational solution and ensure that solution vectors have
491  	   // right dimension; ensure that solution is aligned with basis
492  	   sol._primal.reDim(numColsRational(), false);
493  	   sol._slacks.reDim(numRowsRational(), false);
494  	   sol._dual.reDim(numRowsRational(), false);
495  	   sol._redCost.reDim(numColsRational(), false);
496  	   sol._isPrimalFeasible = true;
497  	   sol._isDualFeasible = true;
498  	
499  	   for(int c = numColsRational() - 1; c >= 0; c--)
500  	   {
501  	      typename SPxSolverBase<R>::VarStatus& basisStatusCol = _basisStatusCols[c];
502  	
503  	      if(basisStatusCol == SPxSolverBase<R>::ON_LOWER)
504  	         sol._primal[c] = lowerRational(c);
505  	      else if(basisStatusCol == SPxSolverBase<R>::ON_UPPER)
506  	         sol._primal[c] = upperRational(c);
507  	      else if(basisStatusCol == SPxSolverBase<R>::FIXED)
508  	      {
509  	         // it may happen that lower and upper are only equal in the Real LP but different in the rational LP; we do
510  	         // not check this to avoid rational comparisons, but simply switch the basis status to the lower bound; this
511  	         // is necessary, because for fixed variables any reduced cost is feasible
512  	         sol._primal[c] = lowerRational(c);
513  	         basisStatusCol = SPxSolverBase<R>::ON_LOWER;
514  	      }
515  	      else if(basisStatusCol == SPxSolverBase<R>::ZERO)
516  	         sol._primal[c] = 0;
517  	      else
518  	         sol._primal[c].assign(primalReal[c]);
519  	   }
520  	
521  	   _rationalLP->computePrimalActivity(sol._primal, sol._slacks);
522  	
523  	   int dualSize = 0;
524  	
525  	   for(int r = numRowsRational() - 1; r >= 0; r--)
526  	   {
527  	      typename SPxSolverBase<R>::VarStatus& basisStatusRow = _basisStatusRows[r];
528  	
529  	      // it may happen that left-hand and right-hand side are different in the rational, but equal in the Real LP,
530  	      // leading to a fixed basis status; this is critical because rows with fixed basis status are ignored in the
531  	      // computation of the dual violation; to avoid rational comparisons we do not check this but simply switch to
532  	      // the left-hand side status
533  	      if(basisStatusRow == SPxSolverBase<R>::FIXED)
534  	         basisStatusRow = SPxSolverBase<R>::ON_LOWER;
535  	
536  	      {
537  	         sol._dual[r].assign(dualReal[r]);
538  	
539  	         if(dualReal[r] != 0.0)
540  	            dualSize++;
541  	      }
542  	   }
543  	
544  	   // we assume that the objective function vector has less nonzeros than the reduced cost vector, and so multiplying
545  	   // with -1 first and subtracting the dual activity should be faster than adding the dual activity and negating
546  	   // afterwards
547  	   _rationalLP->getObj(sol._redCost);
548  	   _rationalLP->subDualActivity(sol._dual, sol._redCost);
549  	
550  	   // initial scaling factors are one
551  	   primalScale = _rationalPosone;
552  	   dualScale = _rationalPosone;
553  	
554  	   // control progress
555  	   Rational maxViolation;
556  	   Rational bestViolation = _rationalPosInfty;
557  	   const Rational violationImprovementFactor = 16;
558  	   const Rational errorCorrectionFactor = 1.1;
559  	   Rational errorCorrection = 2;
560  	   int numFailedRefinements = 0;
561  	
562  	   // store basis status in case solving modified problem failed
563  	   DataArray< typename SPxSolverBase<R>::VarStatus > basisStatusRowsFirst;
564  	   DataArray< typename SPxSolverBase<R>::VarStatus > basisStatusColsFirst;
565  	
566  	   // refinement loop
567  	   const bool maximizing = (intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MAXIMIZE);
568  	   const int maxDimRational = numColsRational() > numRowsRational() ? numColsRational() :
569  	                              numRowsRational();
570  	   SolRational factorSol;
571  	   bool factorSolNewBasis = true;
572  	   int lastStallRefinements = 0;
573  	   int nextRatrecRefinement = 0;
574  	
575  	   do
576  	   {
577  	      // decrement minRounds counter
578  	      minRounds--;
579  	
580  	      MSG_DEBUG(std::cout << "Computing primal violations.\n");
581  	
582  	      // compute violation of bounds
583  	      boundsViolation = 0;
584  	
585  	      for(int c = numColsRational() - 1; c >= 0; c--)
586  	      {
587  	         // lower bound
588  	         assert((lowerRational(c) > _rationalNegInfty) == _lowerFinite(_colTypes[c]));
589  	
590  	         if(_lowerFinite(_colTypes[c]))
591  	         {
592  	            if(lowerRational(c) == 0)
593  	            {
594  	               _modLower[c] = sol._primal[c];
595  	               _modLower[c] *= -1;
596  	
597  	               if(_modLower[c] > boundsViolation)
598  	                  boundsViolation = _modLower[c];
599  	            }
600  	            else
601  	            {
602  	               _modLower[c] = lowerRational(c);
603  	               _modLower[c] -= sol._primal[c];
604  	
605  	               if(_modLower[c] > boundsViolation)
606  	                  boundsViolation = _modLower[c];
607  	            }
608  	         }
609  	
610  	         // upper bound
611  	         assert((upperRational(c) < _rationalPosInfty) == _upperFinite(_colTypes[c]));
612  	
613  	         if(_upperFinite(_colTypes[c]))
614  	         {
615  	            if(upperRational(c) == 0)
616  	            {
617  	               _modUpper[c] = sol._primal[c];
618  	               _modUpper[c] *= -1;
619  	
620  	               if(_modUpper[c] < -boundsViolation)
621  	                  boundsViolation = -_modUpper[c];
622  	            }
623  	            else
624  	            {
625  	               _modUpper[c] = upperRational(c);
626  	               _modUpper[c] -= sol._primal[c];
627  	
628  	               if(_modUpper[c] < -boundsViolation)
629  	                  boundsViolation = -_modUpper[c];
630  	            }
631  	         }
632  	      }
633  	
634  	      // compute violation of sides
635  	      sideViolation = 0;
636  	
637  	      for(int r = numRowsRational() - 1; r >= 0; r--)
638  	      {
639  	         const typename SPxSolverBase<R>::VarStatus& basisStatusRow = _basisStatusRows[r];
640  	
641  	         // left-hand side
642  	         assert((lhsRational(r) > _rationalNegInfty) == _lowerFinite(_rowTypes[r]));
643  	
644  	         if(_lowerFinite(_rowTypes[r]))
645  	         {
646  	            if(lhsRational(r) == 0)
647  	            {
648  	               _modLhs[r] = sol._slacks[r];
649  	               _modLhs[r] *= -1;
650  	            }
651  	            else
652  	            {
653  	               _modLhs[r] = lhsRational(r);
654  	               _modLhs[r] -= sol._slacks[r];
655  	            }
656  	
657  	            if(_modLhs[r] > sideViolation)
658  	               sideViolation = _modLhs[r];
659  	            // if the activity is feasible, but too far from the bound, this violates complementary slackness; we
660  	            // count it as side violation here
661  	            else if(basisStatusRow == SPxSolverBase<R>::ON_LOWER && _modLhs[r] < -sideViolation)
662  	               sideViolation = -_modLhs[r];
663  	         }
664  	
665  	         // right-hand side
666  	         assert((rhsRational(r) < _rationalPosInfty) == _upperFinite(_rowTypes[r]));
667  	
668  	         if(_upperFinite(_rowTypes[r]))
669  	         {
670  	            if(rhsRational(r) == 0)
671  	            {
672  	               _modRhs[r] = sol._slacks[r];
673  	               _modRhs[r] *= -1;
674  	            }
675  	            else
676  	            {
677  	               _modRhs[r] = rhsRational(r);
678  	               _modRhs[r] -= sol._slacks[r];
679  	            }
680  	
681  	            if(_modRhs[r] < -sideViolation)
682  	               sideViolation = -_modRhs[r];
683  	            // if the activity is feasible, but too far from the bound, this violates complementary slackness; we
684  	            // count it as side violation here
685  	            else if(basisStatusRow == SPxSolverBase<R>::ON_UPPER && _modRhs[r] > sideViolation)
686  	               sideViolation = _modRhs[r];
687  	         }
688  	      }
689  	
690  	      MSG_DEBUG(std::cout << "Computing dual violations.\n");
691  	
692  	      // compute reduced cost violation
693  	      redCostViolation = 0;
694  	
695  	      for(int c = numColsRational() - 1; c >= 0; c--)
696  	      {
697  	         if(_colTypes[c] == RANGETYPE_FIXED)
698  	            continue;
699  	
700  	         const typename SPxSolverBase<R>::VarStatus& basisStatusCol = _basisStatusCols[c];
701  	         assert(basisStatusCol != SPxSolverBase<R>::FIXED);
702  	
703  	         if(((maximizing && basisStatusCol != SPxSolverBase<R>::ON_LOWER) || (!maximizing
704  	               && basisStatusCol != SPxSolverBase<R>::ON_UPPER))
705  	               && sol._redCost[c] < -redCostViolation)
706  	         {
707  	            MSG_DEBUG(std::cout << "basisStatusCol = " << basisStatusCol
708  	                      << ", lower tight = " << bool(sol._primal[c] <= lowerRational(c))
709  	                      << ", upper tight = " << bool(sol._primal[c] >= upperRational(c))
710  	                      << ", sol._redCost[c] = " << sol._redCost[c].str()
711  	                      << "\n");
712  	            redCostViolation = -sol._redCost[c];
713  	         }
714  	
715  	         if(((maximizing && basisStatusCol != SPxSolverBase<R>::ON_UPPER) || (!maximizing
716  	               && basisStatusCol != SPxSolverBase<R>::ON_LOWER))
717  	               && sol._redCost[c] > redCostViolation)
718  	         {
719  	            MSG_DEBUG(std::cout << "basisStatusCol = " << basisStatusCol
720  	                      << ", lower tight = " << bool(sol._primal[c] <= lowerRational(c))
721  	                      << ", upper tight = " << bool(sol._primal[c] >= upperRational(c))
722  	                      << ", sol._redCost[c] = " << sol._redCost[c].str()
723  	                      << "\n");
724  	            redCostViolation = sol._redCost[c];
725  	         }
726  	      }
727  	
728  	      // compute dual violation
729  	      dualViolation = 0;
730  	
731  	      for(int r = numRowsRational() - 1; r >= 0; r--)
732  	      {
733  	         if(_rowTypes[r] == RANGETYPE_FIXED)
734  	            continue;
735  	
736  	         const typename SPxSolverBase<R>::VarStatus& basisStatusRow = _basisStatusRows[r];
737  	         assert(basisStatusRow != SPxSolverBase<R>::FIXED);
738  	
739  	         if(((maximizing && basisStatusRow != SPxSolverBase<R>::ON_LOWER) || (!maximizing
740  	               && basisStatusRow != SPxSolverBase<R>::ON_UPPER))
741  	               && sol._dual[r] < -dualViolation)
742  	         {
743  	            MSG_DEBUG(std::cout << "basisStatusRow = " << basisStatusRow
744  	                      << ", lower tight = " << bool(sol._slacks[r] <= lhsRational(r))
745  	                      << ", upper tight = " << bool(sol._slacks[r] >= rhsRational(r))
746  	                      << ", sol._dual[r] = " << sol._dual[r].str()
747  	                      << "\n");
748  	            dualViolation = -sol._dual[r];
749  	         }
750  	
751  	         if(((maximizing && basisStatusRow != SPxSolverBase<R>::ON_UPPER) || (!maximizing
752  	               && basisStatusRow != SPxSolverBase<R>::ON_LOWER))
753  	               && sol._dual[r] > dualViolation)
754  	         {
755  	            MSG_DEBUG(std::cout << "basisStatusRow = " << basisStatusRow
756  	                      << ", lower tight = " << bool(sol._slacks[r] <= lhsRational(r))
757  	                      << ", upper tight = " << bool(sol._slacks[r] >= rhsRational(r))
758  	                      << ", sol._dual[r] = " << sol._dual[r].str()
759  	                      << "\n");
760  	            dualViolation = sol._dual[r];
761  	         }
762  	      }
763  	
764  	      _modObj = sol._redCost;
765  	
766  	      // output violations; the reduced cost violations for artificially introduced slack columns are actually violations of the dual multipliers
767  	      MSG_INFO1(spxout, spxout
768  	                << "Max. bound violation = " << boundsViolation.str() << "\n"
769  	                << "Max. row violation = " << sideViolation.str() << "\n"
770  	                << "Max. reduced cost violation = " << redCostViolation.str() << "\n"
771  	                << "Max. dual violation = " << dualViolation.str() << "\n");
772  	
773  	      MSG_DEBUG(spxout
774  	                << std::fixed << std::setprecision(2) << std::setw(10)
775  	                << "Progress table: "
776  	                << std::setw(10) << _statistics->refinements << " & "
777  	                << std::setw(10) << _statistics->iterations << " & "
778  	                << std::setw(10) << _statistics->solvingTime->time() << " & "
779  	                << std::setw(10) << _statistics->rationalTime->time() << " & "
780  	                << std::setw(10) << boundsViolation > sideViolation ? boundsViolation :
781  	                sideViolation << " & "
782  	                << std::setw(10) << redCostViolation > dualViolation ? redCostViolation :
783  	                dualViolation << "\n");
784  	
785  	      // terminate if tolerances are satisfied
786  	      primalFeasible = (boundsViolation <= _rationalFeastol && sideViolation <= _rationalFeastol);
787  	      dualFeasible = (redCostViolation <= _rationalOpttol && dualViolation <= _rationalOpttol);
788  	
789  	      if(primalFeasible && dualFeasible)
790  	      {
791  	         if(minRounds < 0)
792  	         {
793  	            MSG_INFO1(spxout, spxout << "Tolerances reached.\n");
794  	            break;
795  	         }
796  	         else
797  	         {
798  	            MSG_INFO1(spxout, spxout <<
799  	                      "Tolerances reached but minRounds forcing additional refinement rounds.\n");
800  	         }
801  	      }
802  	
803  	      // terminate if some limit is reached
804  	      if(_isSolveStopped(stoppedTime, stoppedIter) || numFailedRefinements > 2)
805  	         break;
806  	
807  	      // check progress
808  	      maxViolation = boundsViolation;
809  	
810  	      if(sideViolation > maxViolation)
811  	         maxViolation = sideViolation;
812  	
813  	      if(redCostViolation > maxViolation)
814  	         maxViolation = redCostViolation;
815  	
816  	      if(dualViolation > maxViolation)
817  	         maxViolation = dualViolation;
818  	
819  	      bestViolation /= violationImprovementFactor;
820  	
821  	      if(maxViolation > bestViolation)
822  	      {
823  	         MSG_INFO2(spxout, spxout << "Failed to reduce violation significantly.\n");
824  	         bestViolation *= violationImprovementFactor;
825  	         numFailedRefinements++;
826  	      }
827  	      else
828  	         bestViolation = maxViolation;
829  	
830  	      // decide whether to perform rational reconstruction and/or factorization
831  	      bool forcebasic    = boolParam(SoPlexBase<R>::FORCEBASIC);
832  	      bool performRatfac = boolParam(SoPlexBase<R>::RATFAC)
833  	                           && lastStallRefinements >= intParam(SoPlexBase<R>::RATFAC_MINSTALLS) && _hasBasis
834  	                           && factorSolNewBasis;
835  	      bool performRatrec = boolParam(SoPlexBase<R>::RATREC)
836  	                           && (_statistics->refinements >= nextRatrecRefinement || performRatfac);
837  	
838  	      // if we want to force the solution to be basic we need to turn rational factorization on
839  	      performRatfac = performRatfac || forcebasic;
840  	
841  	      // attempt rational reconstruction
842  	      errorCorrection *= errorCorrectionFactor;
843  	
844  	      if(performRatrec && maxViolation > 0)
845  	      {
846  	         MSG_INFO1(spxout, spxout << "Performing rational reconstruction . . .\n");
847  	
848  	         maxViolation *= errorCorrection; // only used for sign check later
849  	         invert(maxViolation);
850  	
851  	         if(_reconstructSolutionRational(sol, _basisStatusRows, _basisStatusCols, maxViolation))
852  	         {
853  	            MSG_INFO1(spxout, spxout << "Tolerances reached.\n");
854  	            primalFeasible = true;
855  	            dualFeasible = true;
856  	
857  	            if(_hasBasis || !forcebasic)
858  	               break;
859  	         }
860  	
861  	         nextRatrecRefinement = int(_statistics->refinements * realParam(SoPlexBase<R>::RATREC_FREQ)) + 1;
862  	         MSG_DEBUG(spxout << "Next rational reconstruction after refinement " << nextRatrecRefinement <<
863  	                   ".\n");
864  	      }
865  	
866  	      // solve basis systems exactly
867  	      if((performRatfac && maxViolation > 0) || (!_hasBasis && forcebasic))
868  	      {
869  	         MSG_INFO1(spxout, spxout << "Performing rational factorization . . .\n");
870  	
871  	         bool optimal;
872  	         _factorizeColumnRational(sol, _basisStatusRows, _basisStatusCols, stoppedTime, stoppedIter, error,
873  	                                  optimal);
874  	         factorSolNewBasis = false;
875  	
876  	         if(stoppedTime)
877  	         {
878  	            MSG_INFO1(spxout, spxout << "Stopped rational factorization.\n");
879  	         }
880  	         else if(error)
881  	         {
882  	            // message was already printed; reset error flag and continue without factorization
883  	            error = false;
884  	         }
885  	         else if(optimal)
886  	         {
887  	            MSG_INFO1(spxout, spxout << "Tolerances reached.\n");
888  	            primalFeasible = true;
889  	            dualFeasible = true;
890  	            break;
891  	         }
892  	         else if(boolParam(SoPlexBase<R>::RATFACJUMP))
893  	         {
894  	            MSG_INFO1(spxout, spxout << "Jumping to exact basic solution.\n");
895  	            minRounds++;
896  	            continue;
897  	         }
898  	      }
899  	
900  	      // start refinement
901  	
902  	      // compute primal scaling factor; limit increase in scaling by tolerance used in floating point solve
903  	      maxScale = primalScale;
904  	      maxScale *= _rationalMaxscaleincr;
905  	
906  	      primalScale = boundsViolation > sideViolation ? boundsViolation : sideViolation;
907  	
908  	      if(primalScale < redCostViolation)
909  	         primalScale = redCostViolation;
910  	
911  	      assert(primalScale >= 0);
912  	
913  	      if(primalScale > 0)
914  	      {
915  	         invert(primalScale);
916  	
917  	         if(primalScale > maxScale)
918  	            primalScale = maxScale;
919  	      }
920  	      else
921  	         primalScale = maxScale;
922  	
923  	      if(boolParam(SoPlexBase<R>::POWERSCALING))
924  	         powRound(primalScale);
925  	
926  	      // apply scaled bounds
927  	      if(primalScale <= 1)
928  	      {
929  	         if(primalScale < 1)
930  	            primalScale = 1;
931  	
932  	         for(int c = numColsRational() - 1; c >= 0; c--)
933  	         {
934  	            if(_lowerFinite(_colTypes[c]))
935  	            {
936  	               if(_modLower[c] <= _rationalNegInfty)
937  	                  _solver.changeLower(c, -realParam(SoPlexBase<R>::INFTY));
938  	               else
939  	                  _solver.changeLower(c, static_cast<R>(_modLower[c]));
940  	            }
941  	
942  	            if(_upperFinite(_colTypes[c]))
943  	            {
944  	               if(_modUpper[c] >= _rationalPosInfty)
945  	                  _solver.changeUpper(c, realParam(SoPlexBase<R>::INFTY));
946  	               else
947  	                  _solver.changeUpper(c, R(_modUpper[c]));
948  	            }
949  	         }
950  	      }
951  	      else
952  	      {
953  	         MSG_INFO2(spxout, spxout << "Scaling primal by " << primalScale.str() << ".\n");
954  	
955  	         for(int c = numColsRational() - 1; c >= 0; c--)
956  	         {
957  	            if(_lowerFinite(_colTypes[c]))
958  	            {
959  	               _modLower[c] *= primalScale;
960  	
961  	               if(_modLower[c] <= _rationalNegInfty)
962  	                  _solver.changeLower(c, -realParam(SoPlexBase<R>::INFTY));
963  	               else
964  	                  _solver.changeLower(c, R(_modLower[c]));
965  	            }
966  	
967  	            if(_upperFinite(_colTypes[c]))
968  	            {
969  	               _modUpper[c] *= primalScale;
970  	
971  	               if(_modUpper[c] >= _rationalPosInfty)
972  	                  _solver.changeUpper(c, realParam(SoPlexBase<R>::INFTY));
973  	               else
974  	                  _solver.changeUpper(c, R(_modUpper[c]));
975  	            }
976  	         }
977  	      }
978  	
979  	      // apply scaled sides
980  	      assert(primalScale >= 1);
981  	
982  	      if(primalScale == 1)
983  	      {
984  	         for(int r = numRowsRational() - 1; r >= 0; r--)
985  	         {
986  	            if(_lowerFinite(_rowTypes[r]))
987  	            {
988  	               if(_modLhs[r] <= _rationalNegInfty)
989  	                  _solver.changeLhs(r, -realParam(SoPlexBase<R>::INFTY));
990  	               else
991  	                  _solver.changeLhs(r, R(_modLhs[r]));
992  	            }
993  	
994  	            if(_upperFinite(_rowTypes[r]))
995  	            {
996  	               if(_modRhs[r] >= _rationalPosInfty)
997  	                  _solver.changeRhs(r, realParam(SoPlexBase<R>::INFTY));
998  	               else
999  	                  _solver.changeRhs(r, R(_modRhs[r]));
1000 	            }
1001 	         }
1002 	      }
1003 	      else
1004 	      {
1005 	         for(int r = numRowsRational() - 1; r >= 0; r--)
1006 	         {
1007 	            if(_lowerFinite(_rowTypes[r]))
1008 	            {
1009 	               _modLhs[r] *= primalScale;
1010 	
1011 	               if(_modLhs[r] <= _rationalNegInfty)
1012 	                  _solver.changeLhs(r, -realParam(SoPlexBase<R>::INFTY));
1013 	               else
1014 	                  _solver.changeLhs(r, R(_modLhs[r]));
1015 	            }
1016 	
1017 	            if(_upperFinite(_rowTypes[r]))
1018 	            {
1019 	               _modRhs[r] *= primalScale;
1020 	
1021 	               if(_modRhs[r] >= _rationalPosInfty)
1022 	                  _solver.changeRhs(r, realParam(SoPlexBase<R>::INFTY));
1023 	               else
1024 	                  _solver.changeRhs(r, R(_modRhs[r]));
1025 	            }
1026 	         }
1027 	      }
1028 	
1029 	      // compute dual scaling factor; limit increase in scaling by tolerance used in floating point solve
1030 	      maxScale = dualScale;
1031 	      maxScale *= _rationalMaxscaleincr;
1032 	
1033 	      dualScale = redCostViolation > dualViolation ? redCostViolation : dualViolation;
1034 	      assert(dualScale >= 0);
1035 	
1036 	      if(dualScale > 0)
1037 	      {
1038 	         invert(dualScale);
1039 	
1040 	         if(dualScale > maxScale)
1041 	            dualScale = maxScale;
1042 	      }
1043 	      else
1044 	         dualScale = maxScale;
1045 	
1046 	      if(boolParam(SoPlexBase<R>::POWERSCALING))
1047 	         powRound(dualScale);
1048 	
1049 	      if(dualScale > primalScale)
1050 	         dualScale = primalScale;
1051 	
1052 	      if(dualScale < 1)
1053 	         dualScale = 1;
1054 	      else
1055 	      {
1056 	         MSG_INFO2(spxout, spxout << "Scaling dual by " << dualScale.str() << ".\n");
1057 	
1058 	         // perform dual scaling
1059 	         ///@todo remove _modObj and use dualScale * sol._redCost directly
1060 	         _modObj *= dualScale;
1061 	      }
1062 	
1063 	      // apply scaled objective function
1064 	      for(int c = numColsRational() - 1; c >= 0; c--)
1065 	      {
1066 	         if(_modObj[c] >= _rationalPosInfty)
1067 	            _solver.changeObj(c, realParam(SoPlexBase<R>::INFTY));
1068 	         else if(_modObj[c] <= _rationalNegInfty)
1069 	            _solver.changeObj(c, -realParam(SoPlexBase<R>::INFTY));
1070 	         else
1071 	            _solver.changeObj(c, R(_modObj[c]));
1072 	      }
1073 	
1074 	      for(int r = numRowsRational() - 1; r >= 0; r--)
1075 	      {
1076 	         Rational newRowObj;
1077 	
1078 	         if(_rowTypes[r] == RANGETYPE_FIXED)
1079 	            _solver.changeRowObj(r, R(0.0));
1080 	         else
1081 	         {
1082 	            newRowObj = sol._dual[r];
1083 	            newRowObj *= dualScale;
1084 	
1085 	            if(newRowObj >= _rationalPosInfty)
1086 	               _solver.changeRowObj(r, -realParam(SoPlexBase<R>::INFTY));
1087 	            else if(newRowObj <= _rationalNegInfty)
1088 	               _solver.changeRowObj(r, realParam(SoPlexBase<R>::INFTY));
1089 	            else
1090 	               _solver.changeRowObj(r, -R(newRowObj));
1091 	         }
1092 	      }
1093 	
1094 	      MSG_INFO1(spxout, spxout << "Refined floating-point solve . . .\n");
1095 	
1096 	      // ensure that artificial slack columns are basic and inequality constraints are nonbasic; otherwise we may end
1097 	      // up with dual violation on inequality constraints after removing the slack columns; do not change this in the
1098 	      // floating-point solver, though, because the solver may require its original basis to detect optimality
1099 	      if(_slackCols.num() > 0 && _hasBasis)
1100 	      {
1101 	         int numOrigCols = numColsRational() - _slackCols.num();
1102 	         assert(_slackCols.num() <= 0 || boolParam(SoPlexBase<R>::EQTRANS));
1103 	
1104 	         for(int i = 0; i < _slackCols.num(); i++)
1105 	         {
1106 	            int row = _slackCols.colVector(i).index(0);
1107 	            int col = numOrigCols + i;
1108 	
1109 	            assert(row >= 0);
1110 	            assert(row < numRowsRational());
1111 	
1112 	            if(_basisStatusRows[row] == SPxSolverBase<R>::BASIC
1113 	                  && _basisStatusCols[col] != SPxSolverBase<R>::BASIC)
1114 	            {
1115 	               _basisStatusRows[row] = _basisStatusCols[col];
1116 	               _basisStatusCols[col] = SPxSolverBase<R>::BASIC;
1117 	               _rationalLUSolver.clear();
1118 	            }
1119 	         }
1120 	      }
1121 	
1122 	      // load basis
1123 	      if(_hasBasis && _solver.basis().status() < SPxBasisBase<R>::REGULAR)
1124 	      {
1125 	         MSG_DEBUG(spxout << "basis (status = " << _solver.basis().status() << ") desc before set:\n";
1126 	                   _solver.basis().desc().dump());
1127 	         _solver.setBasis(_basisStatusRows.get_const_ptr(), _basisStatusCols.get_const_ptr());
1128 	         MSG_DEBUG(spxout << "basis (status = " << _solver.basis().status() << ") desc after set:\n";
1129 	                   _solver.basis().desc().dump());
1130 	
1131 	         _hasBasis = _solver.basis().status() > SPxBasisBase<R>::NO_PROBLEM;
1132 	         MSG_DEBUG(spxout << "setting basis in solver " << (_hasBasis ? "successful" : "failed") <<
1133 	                   " (3)\n");
1134 	      }
1135 	
1136 	      // solve modified problem
1137 	      int prevIterations = _statistics->iterations;
1138 	      _statistics->rationalTime->stop();
1139 	      result = _solveRealStable(acceptUnbounded, acceptInfeasible, primalReal, dualReal, _basisStatusRows,
1140 	                                _basisStatusCols, primalScale > 1e20 || dualScale > 1e20);
1141 	
1142 	      // count refinements and remember whether we moved to a new basis
1143 	      _statistics->refinements++;
1144 	
1145 	      if(_statistics->iterations <= prevIterations)
1146 	      {
1147 	         lastStallRefinements++;
1148 	         _statistics->stallRefinements++;
1149 	      }
1150 	      else
1151 	      {
1152 	         factorSolNewBasis = true;
1153 	         lastStallRefinements = 0;
1154 	         _statistics->pivotRefinements = _statistics->refinements;
1155 	      }
1156 	
1157 	      // evaluate result; if modified problem was not solved to optimality, stop refinement
1158 	      switch(result)
1159 	      {
1160 	      case SPxSolverBase<R>::OPTIMAL:
1161 	         MSG_INFO1(spxout, spxout << "Floating-point optimal.\n");
1162 	         break;
1163 	
1164 	      case SPxSolverBase<R>::INFEASIBLE:
1165 	         MSG_INFO1(spxout, spxout << "Floating-point infeasible.\n");
1166 	         sol._dualFarkas = dualReal;
1167 	         sol._hasDualFarkas = true;
1168 	         infeasible = true;
1169 	         _solver.clearRowObjs();
1170 	         return;
1171 	
1172 	      case SPxSolverBase<R>::UNBOUNDED:
1173 	         MSG_INFO1(spxout, spxout << "Floating-point unbounded.\n");
1174 	         unbounded = true;
1175 	         _solver.clearRowObjs();
1176 	         return;
1177 	
1178 	      case SPxSolverBase<R>::ABORT_TIME:
1179 	         stoppedTime = true;
1180 	         return;
1181 	
1182 	      case SPxSolverBase<R>::ABORT_ITER:
1183 	         stoppedIter = true;
1184 	         _solver.clearRowObjs();
1185 	         return;
1186 	
1187 	      default:
1188 	         error = true;
1189 	         _solver.clearRowObjs();
1190 	         return;
1191 	      }
1192 	
1193 	      _statistics->rationalTime->start();
1194 	
1195 	      // correct primal solution and align with basis
1196 	      MSG_DEBUG(std::cout << "Correcting primal solution.\n");
1197 	
1198 	      int primalSize = 0;
1199 	      Rational primalScaleInverse = primalScale;
1200 	      invert(primalScaleInverse);
1201 	      _primalDualDiff.clear();
1202 	
1203 	      for(int c = numColsRational() - 1; c >= 0; c--)
1204 	      {
1205 	         // force values of nonbasic variables to bounds
1206 	         typename SPxSolverBase<R>::VarStatus& basisStatusCol = _basisStatusCols[c];
1207 	
1208 	         if(basisStatusCol == SPxSolverBase<R>::ON_LOWER)
1209 	         {
1210 	            if(sol._primal[c] != lowerRational(c))
1211 	            {
1212 	               int i = _primalDualDiff.size();
1213 	               _ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
1214 	               _primalDualDiff.add(c);
1215 	               _primalDualDiff.value(i) = lowerRational(c);
1216 	               _primalDualDiff.value(i) -= sol._primal[c];
1217 	               sol._primal[c] = lowerRational(c);
1218 	            }
1219 	         }
1220 	         else if(basisStatusCol == SPxSolverBase<R>::ON_UPPER)
1221 	         {
1222 	            if(sol._primal[c] != upperRational(c))
1223 	            {
1224 	               int i = _primalDualDiff.size();
1225 	               _ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
1226 	               _primalDualDiff.add(c);
1227 	               _primalDualDiff.value(i) = upperRational(c);
1228 	               _primalDualDiff.value(i) -= sol._primal[c];
1229 	               sol._primal[c] = upperRational(c);
1230 	            }
1231 	         }
1232 	         else if(basisStatusCol == SPxSolverBase<R>::FIXED)
1233 	         {
1234 	            // it may happen that lower and upper are only equal in the Real LP but different in the rational LP; we
1235 	            // do not check this to avoid rational comparisons, but simply switch the basis status to the lower
1236 	            // bound; this is necessary, because for fixed variables any reduced cost is feasible
1237 	            basisStatusCol = SPxSolverBase<R>::ON_LOWER;
1238 	
1239 	            if(sol._primal[c] != lowerRational(c))
1240 	            {
1241 	               int i = _primalDualDiff.size();
1242 	               _ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
1243 	               _primalDualDiff.add(c);
1244 	               _primalDualDiff.value(i) = lowerRational(c);
1245 	               _primalDualDiff.value(i) -= sol._primal[c];
1246 	               sol._primal[c] = lowerRational(c);
1247 	            }
1248 	         }
1249 	         else if(basisStatusCol == SPxSolverBase<R>::ZERO)
1250 	         {
1251 	            if(sol._primal[c] != 0)
1252 	            {
1253 	               int i = _primalDualDiff.size();
1254 	               _ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
1255 	               _primalDualDiff.add(c);
1256 	               _primalDualDiff.value(i) = sol._primal[c];
1257 	               _primalDualDiff.value(i) *= -1;
1258 	               sol._primal[c] = 0;
1259 	            }
1260 	         }
1261 	         else
1262 	         {
1263 	            if(primalReal[c] == 1.0)
1264 	            {
1265 	               int i = _primalDualDiff.size();
1266 	               _ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
1267 	               _primalDualDiff.add(c);
1268 	               _primalDualDiff.value(i) = primalScaleInverse;
1269 	               sol._primal[c] += _primalDualDiff.value(i);
1270 	            }
1271 	            else if(primalReal[c] == -1.0)
1272 	            {
1273 	               int i = _primalDualDiff.size();
1274 	               _ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
1275 	               _primalDualDiff.add(c);
1276 	               _primalDualDiff.value(i) = primalScaleInverse;
1277 	               _primalDualDiff.value(i) *= -1;
1278 	               sol._primal[c] += _primalDualDiff.value(i);
1279 	            }
1280 	            else if(primalReal[c] != 0.0)
1281 	            {
1282 	               int i = _primalDualDiff.size();
1283 	               _ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
1284 	               _primalDualDiff.add(c);
1285 	               _primalDualDiff.value(i).assign(primalReal[c]);
1286 	               _primalDualDiff.value(i) *= primalScaleInverse;
1287 	               sol._primal[c] += _primalDualDiff.value(i);
1288 	            }
1289 	         }
1290 	
1291 	         if(sol._primal[c] != 0)
1292 	            primalSize++;
1293 	      }
1294 	
1295 	      // update or recompute slacks depending on which looks faster
1296 	      if(_primalDualDiff.size() < primalSize)
1297 	      {
1298 	         _rationalLP->addPrimalActivity(_primalDualDiff, sol._slacks);
1299 	#ifndef NDEBUG
1300 	         {
1301 	            VectorRational activity(numRowsRational());
1302 	            _rationalLP->computePrimalActivity(sol._primal, activity);
1303 	            assert(sol._slacks == activity);
1304 	         }
1305 	#endif
1306 	      }
1307 	      else
1308 	         _rationalLP->computePrimalActivity(sol._primal, sol._slacks);
1309 	
1310 	      const int numCorrectedPrimals = _primalDualDiff.size();
1311 	
1312 	      // correct dual solution and align with basis
1313 	      MSG_DEBUG(std::cout << "Correcting dual solution.\n");
1314 	
1315 	#ifndef NDEBUG
1316 	      {
1317 	         // compute reduced cost violation
1318 	         VectorRational debugRedCost(numColsRational());
1319 	         debugRedCost = VectorRational(_realLP->maxObj());
1320 	         debugRedCost *= -1;
1321 	         _rationalLP->subDualActivity(VectorRational(dualReal), debugRedCost);
1322 	
1323 	         Rational debugRedCostViolation = 0;
1324 	
1325 	         for(int c = numColsRational() - 1; c >= 0; c--)
1326 	         {
1327 	            if(_colTypes[c] == RANGETYPE_FIXED)
1328 	               continue;
1329 	
1330 	            const typename SPxSolverBase<R>::VarStatus& basisStatusCol = _basisStatusCols[c];
1331 	            assert(basisStatusCol != SPxSolverBase<R>::FIXED);
1332 	
1333 	            if(((maximizing && basisStatusCol != SPxSolverBase<R>::ON_LOWER) || (!maximizing
1334 	                  && basisStatusCol != SPxSolverBase<R>::ON_UPPER))
1335 	                  && debugRedCost[c] < -debugRedCostViolation)
1336 	            {
1337 	               MSG_DEBUG(std::cout << "basisStatusCol = " << basisStatusCol
1338 	                         << ", lower tight = " << bool(sol._primal[c] <= lowerRational(c))
1339 	                         << ", upper tight = " << bool(sol._primal[c] >= upperRational(c))
1340 	                         << ", obj[c] = " << _realLP->obj(c)
1341 	                         << ", debugRedCost[c] = " << debugRedCost[c].str()
1342 	                         << "\n");
1343 	               debugRedCostViolation = -debugRedCost[c];
1344 	            }
1345 	
1346 	            if(((maximizing && basisStatusCol != SPxSolverBase<R>::ON_UPPER) || (!maximizing
1347 	                  && basisStatusCol != SPxSolverBase<R>::ON_LOWER))
1348 	                  && debugRedCost[c] > debugRedCostViolation)
1349 	            {
1350 	               MSG_DEBUG(std::cout << "basisStatusCol = " << basisStatusCol
1351 	                         << ", lower tight = " << bool(sol._primal[c] <= lowerRational(c))
1352 	                         << ", upper tight = " << bool(sol._primal[c] >= upperRational(c))
1353 	                         << ", obj[c] = " << _realLP->obj(c)
1354 	                         << ", debugRedCost[c] = " << debugRedCost[c].str()
1355 	                         << "\n");
1356 	               debugRedCostViolation = debugRedCost[c];
1357 	            }
1358 	         }
1359 	
1360 	         // compute dual violation
1361 	         Rational debugDualViolation = 0;
1362 	         Rational debugBasicDualViolation = 0;
1363 	
1364 	         for(int r = numRowsRational() - 1; r >= 0; r--)
1365 	         {
1366 	            if(_rowTypes[r] == RANGETYPE_FIXED)
1367 	               continue;
1368 	
1369 	            const typename SPxSolverBase<R>::VarStatus& basisStatusRow = _basisStatusRows[r];
1370 	            assert(basisStatusRow != SPxSolverBase<R>::FIXED);
1371 	
1372 	            Rational val = (-dualScale * sol._dual[r]) - Rational(dualReal[r]);
1373 	
1374 	            if(((maximizing && basisStatusRow != SPxSolverBase<R>::ON_LOWER) || (!maximizing
1375 	                  && basisStatusRow != SPxSolverBase<R>::ON_UPPER))
1376 	                  && val > debugDualViolation)
1377 	            {
1378 	               MSG_DEBUG(std::cout << "basisStatusRow = " << basisStatusRow
1379 	                         << ", lower tight = " << bool(sol._slacks[r] <= lhsRational(r))
1380 	                         << ", upper tight = " << bool(sol._slacks[r] >= rhsRational(r))
1381 	                         << ", dualReal[r] = " << val.str()
1382 	                         << ", dualReal[r] = " << dualReal[r]
1383 	                         << "\n");
1384 	               debugDualViolation = val;
1385 	            }
1386 	
1387 	            if(((maximizing && basisStatusRow != SPxSolverBase<R>::ON_UPPER) || (!maximizing
1388 	                  && basisStatusRow != SPxSolverBase<R>::ON_LOWER))
1389 	                  && val < -debugDualViolation)
1390 	            {
1391 	               MSG_DEBUG(std::cout << "basisStatusRow = " << basisStatusRow
1392 	                         << ", lower tight = " << bool(sol._slacks[r] <= lhsRational(r))
1393 	                         << ", upper tight = " << bool(sol._slacks[r] >= rhsRational(r))
1394 	                         << ", dualReal[r] = " << val.str()
1395 	                         << ", dualReal[r] = " << dualReal[r]
1396 	                         << "\n");
1397 	               debugDualViolation = -val;
1398 	            }
1399 	
1400 	            if(basisStatusRow == SPxSolverBase<R>::BASIC && spxAbs(val) > debugBasicDualViolation)
1401 	            {
1402 	               MSG_DEBUG(std::cout << "basisStatusRow = " << basisStatusRow
1403 	                         << ", lower tight = " << bool(sol._slacks[r] <= lhsRational(r))
1404 	                         << ", upper tight = " << bool(sol._slacks[r] >= rhsRational(r))
1405 	                         << ", dualReal[r] = " << val.str()
1406 	                         << ", dualReal[r] = " << dualReal[r]
1407 	                         << "\n");
1408 	               debugBasicDualViolation = spxAbs(val);
1409 	            }
1410 	         }
1411 	
1412 	         if(R(debugRedCostViolation) > _solver.opttol() || R(debugDualViolation) > _solver.opttol()
1413 	               || debugBasicDualViolation > 1e-9)
1414 	         {
1415 	            MSG_WARNING(spxout, spxout << "Warning: floating-point dual solution with violation "
1416 	                        << debugRedCostViolation.str() << " / "
1417 	                        << debugDualViolation.str() << " / "
1418 	                        << debugBasicDualViolation.str()
1419 	                        << " (red. cost, dual, basic).\n");
1420 	         }
1421 	      }
1422 	#endif
1423 	
1424 	      Rational dualScaleInverseNeg = dualScale;
1425 	      invert(dualScaleInverseNeg);
1426 	      dualScaleInverseNeg *= -1;
1427 	      _primalDualDiff.clear();
1428 	      dualSize = 0;
1429 	
1430 	      for(int r = numRowsRational() - 1; r >= 0; r--)
1431 	      {
1432 	         typename SPxSolverBase<R>::VarStatus& basisStatusRow = _basisStatusRows[r];
1433 	
1434 	         // it may happen that left-hand and right-hand side are different in the rational, but equal in the Real LP,
1435 	         // leading to a fixed basis status; this is critical because rows with fixed basis status are ignored in the
1436 	         // computation of the dual violation; to avoid rational comparisons we do not check this but simply switch
1437 	         // to the left-hand side status
1438 	         if(basisStatusRow == SPxSolverBase<R>::FIXED)
1439 	            basisStatusRow = SPxSolverBase<R>::ON_LOWER;
1440 	
1441 	         {
1442 	            if(dualReal[r] != 0)
1443 	            {
1444 	               int i = _primalDualDiff.size();
1445 	               _ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
1446 	               _primalDualDiff.add(r);
1447 	               _primalDualDiff.value(i).assign(dualReal[r]);
1448 	               _primalDualDiff.value(i) *= dualScaleInverseNeg;
1449 	               sol._dual[r] -= _primalDualDiff.value(i);
1450 	
1451 	               dualSize++;
1452 	            }
1453 	            else
1454 	            {
1455 	               // we do not check whether the dual value is nonzero, because it probably is; this gives us an
1456 	               // overestimation of the number of nonzeros in the dual solution
1457 	               dualSize++;
1458 	            }
1459 	         }
1460 	      }
1461 	
1462 	      // update or recompute reduced cost values depending on which looks faster; adding one to the length of the
1463 	      // dual vector accounts for the objective function vector
1464 	      if(_primalDualDiff.size() < dualSize + 1)
1465 	      {
1466 	         _rationalLP->addDualActivity(_primalDualDiff, sol._redCost);
1467 	#ifndef NDEBUG
1468 	         {
1469 	            VectorRational activity(_rationalLP->maxObj());
1470 	            activity *= -1;
1471 	            _rationalLP->subDualActivity(sol._dual, activity);
1472 	         }
1473 	#endif
1474 	      }
1475 	      else
1476 	      {
1477 	         // we assume that the objective function vector has less nonzeros than the reduced cost vector, and so multiplying
1478 	         // with -1 first and subtracting the dual activity should be faster than adding the dual activity and negating
1479 	         // afterwards
1480 	         _rationalLP->getObj(sol._redCost);
1481 	         _rationalLP->subDualActivity(sol._dual, sol._redCost);
1482 	      }
1483 	
1484 	      const int numCorrectedDuals = _primalDualDiff.size();
1485 	
1486 	      if(numCorrectedPrimals + numCorrectedDuals > 0)
1487 	      {
1488 	         MSG_INFO2(spxout, spxout << "Corrected " << numCorrectedPrimals << " primal variables and " <<
1489 	                   numCorrectedDuals << " dual values.\n");
1490 	      }
1491 	   }
1492 	   while(true);
1493 	
1494 	   // correct basis status for restricted inequalities
1495 	   if(_hasBasis)
1496 	   {
1497 	      for(int r = numRowsRational() - 1; r >= 0; r--)
1498 	      {
1499 	         assert((lhsRational(r) == rhsRational(r)) == (_rowTypes[r] == RANGETYPE_FIXED));
1500 	
1501 	         if(_rowTypes[r] != RANGETYPE_FIXED && _basisStatusRows[r] == SPxSolverBase<R>::FIXED)
1502 	            _basisStatusRows[r] = (maximizing == (sol._dual[r] < 0))
1503 	                                  ? SPxSolverBase<R>::ON_LOWER
1504 	                                  : SPxSolverBase<R>::ON_UPPER;
1505 	      }
1506 	   }
1507 	
1508 	   // compute objective function values
1509 	   assert(sol._isPrimalFeasible == sol._isDualFeasible);
1510 	
1511 	   if(sol._isPrimalFeasible)
1512 	   {
1513 	      sol._objVal = sol._primal * _rationalLP->maxObj();
1514 	
1515 	      if(intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MINIMIZE)
1516 	         sol._objVal *= -1;
1517 	   }
1518 	
1519 	   // set objective coefficients for all rows to zero
1520 	   _solver.clearRowObjs();
1521 	
1522 	   // stop rational solving time
1523 	   _statistics->rationalTime->stop();
1524 	}
1525 	
1526 	
1527 	/// performs iterative refinement on the auxiliary problem for testing unboundedness
1528 	template <class R>
1529 	void SoPlexBase<R>::_performUnboundedIRStable(
1530 	   SolRational& sol,
1531 	   bool& hasUnboundedRay,
1532 	   bool& stoppedTime,
1533 	   bool& stoppedIter,
1534 	   bool& error)
1535 	{
1536 	   bool primalFeasible;
1537 	   bool dualFeasible;
1538 	   bool infeasible;
1539 	   bool unbounded;
1540 	
1541 	   // move objective function to constraints and adjust sides and bounds
1542 	   _transformUnbounded();
1543 	
1544 	   // invalidate solution
1545 	   sol.invalidate();
1546 	
1547 	   // remember current number of refinements
1548 	   int oldRefinements = _statistics->refinements;
1549 	
1550 	   // perform iterative refinement
1551 	   _performOptIRStable(sol, false, false, 0, primalFeasible, dualFeasible, infeasible, unbounded,
1552 	                       stoppedTime, stoppedIter, error);
1553 	
1554 	   // update unbounded refinement counter
1555 	   _statistics->unbdRefinements += _statistics->refinements - oldRefinements;
1556 	
1557 	   // stopped due to some limit
1558 	   if(stoppedTime || stoppedIter)
1559 	   {
1560 	      sol.invalidate();
1561 	      hasUnboundedRay = false;
1562 	      error = false;
1563 	   }
1564 	   // the unbounded problem should always be solved to optimality
1565 	   else if(error || unbounded || infeasible || !primalFeasible || !dualFeasible)
1566 	   {
1567 	      sol.invalidate();
1568 	      hasUnboundedRay = false;
1569 	      error = true;
1570 	   }
1571 	   else
1572 	   {
1573 	      const Rational& tau = sol._primal[numColsRational() - 1];
1574 	
1575 	      MSG_DEBUG(std::cout << "tau = " << tau << " (roughly " << tau.str() << ")\n");
1576 	
1577 	      assert(tau <= 1.0 + 2.0 * realParam(SoPlexBase<R>::FEASTOL));
1578 	      assert(tau >= -realParam(SoPlexBase<R>::FEASTOL));
1579 	
1580 	      // because the right-hand side and all bounds (but tau's upper bound) are zero, tau should be approximately
1581 	      // zero if basic; otherwise at its upper bound 1
1582 	      error = !(tau >= _rationalPosone || tau <= _rationalFeastol);
1583 	      assert(!error);
1584 	
1585 	      hasUnboundedRay = (tau >= 1);
1586 	   }
1587 	
1588 	   // restore problem
1589 	   _untransformUnbounded(sol, hasUnboundedRay);
1590 	}
1591 	
1592 	
1593 	
1594 	/// performs iterative refinement on the auxiliary problem for testing feasibility
1595 	template <class R>
1596 	void SoPlexBase<R>::_performFeasIRStable(
1597 	   SolRational& sol,
1598 	   bool& withDualFarkas,
1599 	   bool& stoppedTime,
1600 	   bool& stoppedIter,
1601 	   bool& error)
1602 	{
1603 	   bool primalFeasible;
1604 	   bool dualFeasible;
1605 	   bool infeasible;
1606 	   bool unbounded;
1607 	   bool success = false;
1608 	   error = false;
1609 	
1610 	#if 0
1611 	   // if the problem has been found to be infeasible and an approximate Farkas proof is available, we compute a
1612 	   // scaled unit box around the origin that provably contains no feasible solution; this currently only works for
1613 	   // equality form
1614 	   ///@todo check whether approximate Farkas proof can be used
1615 	   _computeInfeasBox(_solRational, false);
1616 	   ///@todo if approx Farkas proof is good enough then exit without doing any transformation
1617 	#endif
1618 	
1619 	   // remove objective function, shift, homogenize
1620 	   _transformFeasibility();
1621 	
1622 	   // invalidate solution
1623 	   sol.invalidate();
1624 	
1625 	   do
1626 	   {
1627 	      // remember current number of refinements
1628 	      int oldRefinements = _statistics->refinements;
1629 	
1630 	      // perform iterative refinement
1631 	      _performOptIRStable(sol, false, false, 0, primalFeasible, dualFeasible, infeasible, unbounded,
1632 	                          stoppedTime, stoppedIter, error);
1633 	
1634 	      // update feasible refinement counter
1635 	      _statistics->feasRefinements += _statistics->refinements - oldRefinements;
1636 	
1637 	      // stopped due to some limit
1638 	      if(stoppedTime || stoppedIter)
1639 	      {
1640 	         sol.invalidate();
1641 	         withDualFarkas = false;
1642 	         error = false;
1643 	      }
1644 	      // the feasibility problem should always be solved to optimality
1645 	      else if(error || unbounded || infeasible || !primalFeasible || !dualFeasible)
1646 	      {
1647 	         sol.invalidate();
1648 	         withDualFarkas = false;
1649 	         error = true;
1650 	      }
1651 	      // else we should have either a refined Farkas proof or an approximate feasible solution to the original
1652 	      else
1653 	      {
1654 	         const Rational& tau = sol._primal[numColsRational() - 1];
1655 	
1656 	         MSG_DEBUG(std::cout << "tau = " << tau << " (roughly " << tau.str() << ")\n");
1657 	
1658 	         assert(tau >= -realParam(SoPlexBase<R>::FEASTOL));
1659 	         assert(tau <= 1.0 + realParam(SoPlexBase<R>::FEASTOL));
1660 	
1661 	         error = (tau < -_rationalFeastol || tau > _rationalPosone + _rationalFeastol);
1662 	         withDualFarkas = (tau < _rationalPosone);
1663 	
1664 	         if(withDualFarkas)
1665 	         {
1666 	            _solRational._hasDualFarkas = true;
1667 	            _solRational._dualFarkas = _solRational._dual;
1668 	
1669 	#if 0
1670 	            // check if we can compute sufficiently large Farkas box
1671 	            _computeInfeasBox(_solRational, true);
1672 	#endif
1673 	
1674 	            if(true)  //@todo check if computeInfeasBox found a sufficient box
1675 	            {
1676 	
1677 	               success = true;
1678 	               sol._isPrimalFeasible = false;
1679 	            }
1680 	         }
1681 	         else
1682 	         {
1683 	            sol._isDualFeasible = false;
1684 	            success = true; //successfully found approximate feasible solution
1685 	         }
1686 	      }
1687 	   }
1688 	   while(!error && !success && !(stoppedTime || stoppedIter));
1689 	
1690 	   // restore problem
1691 	   _untransformFeasibility(sol, withDualFarkas);
1692 	}
1693 	
1694 	
1695 	
1696 	/// reduces matrix coefficient in absolute value by the lifting procedure of Thiele et al. 2013
1697 	template <class R>
1698 	void SoPlexBase<R>::_lift()
1699 	{
1700 	   MSG_DEBUG(std::cout << "Reducing matrix coefficients by lifting.\n");
1701 	
1702 	   // start timing
1703 	   _statistics->transformTime->start();
1704 	
1705 	   MSG_DEBUG(_realLP->writeFileLPBase("beforeLift.lp", 0, 0, 0));
1706 	
1707 	   // remember unlifted state
1708 	   _beforeLiftCols = numColsRational();
1709 	   _beforeLiftRows = numRowsRational();
1710 	
1711 	   // allocate vector memory
1712 	   DSVectorRational colVector;
1713 	   SVectorRational::Element liftingRowMem[2];
1714 	   SVectorRational liftingRowVector(2, liftingRowMem);
1715 	
1716 	   // search each column for large nonzeros entries
1717 	   // @todo: rethink about the static_cast TODO
1718 	   const Rational maxValue = static_cast<Rational>(realParam(SoPlexBase<R>::LIFTMAXVAL));
1719 	
1720 	   for(int i = 0; i < numColsRational(); i++)
1721 	   {
1722 	      MSG_DEBUG(std::cout << "in lifting: examining column " << i << "\n");
1723 	
1724 	      // get column vector
1725 	      colVector = colVectorRational(i);
1726 	
1727 	      bool addedLiftingRow = false;
1728 	      int liftingColumnIndex = -1;
1729 	
1730 	      // go through nonzero entries of the column
1731 	      for(int k = colVector.size() - 1; k >= 0; k--)
1732 	      {
1733 	         const Rational& value = colVector.value(k);
1734 	
1735 	         if(spxAbs(value) > maxValue)
1736 	         {
1737 	            MSG_DEBUG(std::cout << "   --> nonzero " << k << " has value " << value.str() << " in row " <<
1738 	                      colVector.index(k) << "\n");
1739 	
1740 	            // add new column equal to maxValue times original column
1741 	            if(!addedLiftingRow)
1742 	            {
1743 	               MSG_DEBUG(std::cout << "            --> adding lifting row\n");
1744 	
1745 	               assert(liftingRowVector.size() == 0);
1746 	
1747 	               liftingColumnIndex = numColsRational();
1748 	               liftingRowVector.add(i, maxValue);
1749 	               liftingRowVector.add(liftingColumnIndex, -1);
1750 	
1751 	               _rationalLP->addRow(LPRowRational(0, liftingRowVector, 0));
1752 	               _realLP->addRow(LPRowBase<R>(0.0, DSVectorBase<R>(liftingRowVector), 0.0));
1753 	
1754 	               assert(liftingColumnIndex == numColsRational() - 1);
1755 	               assert(liftingColumnIndex == numCols() - 1);
1756 	
1757 	               _rationalLP->changeBounds(liftingColumnIndex, _rationalNegInfty, _rationalPosInfty);
1758 	               _realLP->changeBounds(liftingColumnIndex, -realParam(SoPlexBase<R>::INFTY),
1759 	                                     realParam(SoPlexBase<R>::INFTY));
1760 	
1761 	               liftingRowVector.clear();
1762 	               addedLiftingRow = true;
1763 	            }
1764 	
1765 	            // get row index
1766 	            int rowIndex = colVector.index(k);
1767 	            assert(rowIndex >= 0);
1768 	            assert(rowIndex < _beforeLiftRows);
1769 	            assert(liftingColumnIndex == numColsRational() - 1);
1770 	
1771 	            MSG_DEBUG(std::cout << "            --> changing matrix\n");
1772 	
1773 	            // remove nonzero from original column
1774 	            _rationalLP->changeElement(rowIndex, i, 0);
1775 	            _realLP->changeElement(rowIndex, i, 0.0);
1776 	
1777 	            // add nonzero divided by maxValue to new column
1778 	            Rational newValue(value);
1779 	            newValue /= maxValue;
1780 	            _rationalLP->changeElement(rowIndex, liftingColumnIndex, newValue);
1781 	            _realLP->changeElement(rowIndex, liftingColumnIndex, R(newValue));
1782 	         }
1783 	      }
1784 	   }
1785 	
1786 	   // search each column for small nonzeros entries
1787 	   const Rational minValue = Rational(realParam(SoPlexBase<R>::LIFTMINVAL));
1788 	
1789 	   for(int i = 0; i < numColsRational(); i++)
1790 	   {
1791 	      MSG_DEBUG(std::cout << "in lifting: examining column " << i << "\n");
1792 	
1793 	      // get column vector
1794 	      colVector = colVectorRational(i);
1795 	
1796 	      bool addedLiftingRow = false;
1797 	      int liftingColumnIndex = -1;
1798 	
1799 	      // go through nonzero entries of the column
1800 	      for(int k = colVector.size() - 1; k >= 0; k--)
1801 	      {
1802 	         const Rational& value = colVector.value(k);
1803 	
1804 	         if(spxAbs(value) < minValue)
1805 	         {
1806 	            MSG_DEBUG(std::cout << "   --> nonzero " << k << " has value " << value.str() << " in row " <<
1807 	                      colVector.index(k) << "\n");
1808 	
1809 	            // add new column equal to maxValue times original column
1810 	            if(!addedLiftingRow)
1811 	            {
1812 	               MSG_DEBUG(std::cout << "            --> adding lifting row\n");
1813 	
1814 	               assert(liftingRowVector.size() == 0);
1815 	
1816 	               liftingColumnIndex = numColsRational();
1817 	               liftingRowVector.add(i, minValue);
1818 	               liftingRowVector.add(liftingColumnIndex, -1);
1819 	
1820 	               _rationalLP->addRow(LPRowRational(0, liftingRowVector, 0));
1821 	               _realLP->addRow(LPRowBase<R>(0.0, DSVectorBase<R>(liftingRowVector), 0.0));
1822 	
1823 	               assert(liftingColumnIndex == numColsRational() - 1);
1824 	               assert(liftingColumnIndex == numCols() - 1);
1825 	
1826 	               _rationalLP->changeBounds(liftingColumnIndex, _rationalNegInfty, _rationalPosInfty);
1827 	               _realLP->changeBounds(liftingColumnIndex, -realParam(SoPlexBase<R>::INFTY),
1828 	                                     realParam(SoPlexBase<R>::INFTY));
1829 	
1830 	               liftingRowVector.clear();
1831 	               addedLiftingRow = true;
1832 	            }
1833 	
1834 	            // get row index
1835 	            int rowIndex = colVector.index(k);
1836 	            assert(rowIndex >= 0);
1837 	            assert(rowIndex < _beforeLiftRows);
1838 	            assert(liftingColumnIndex == numColsRational() - 1);
1839 	
1840 	            MSG_DEBUG(std::cout << "            --> changing matrix\n");
1841 	
1842 	            // remove nonzero from original column
1843 	            _rationalLP->changeElement(rowIndex, i, 0);
1844 	            _realLP->changeElement(rowIndex, i, 0.0);
1845 	
1846 	            // add nonzero divided by maxValue to new column
1847 	            Rational newValue(value);
1848 	            newValue /= minValue;
1849 	            _rationalLP->changeElement(rowIndex, liftingColumnIndex, newValue);
1850 	            _realLP->changeElement(rowIndex, liftingColumnIndex, R(newValue));
1851 	         }
1852 	      }
1853 	   }
1854 	
1855 	   // adjust basis
1856 	   if(_hasBasis)
1857 	   {
1858 	      assert(numColsRational() >= _beforeLiftCols);
1859 	      assert(numRowsRational() >= _beforeLiftRows);
1860 	
1861 	      _basisStatusCols.append(numColsRational() - _beforeLiftCols, SPxSolverBase<R>::BASIC);
1862 	      _basisStatusRows.append(numRowsRational() - _beforeLiftRows, SPxSolverBase<R>::FIXED);
1863 	      _rationalLUSolver.clear();
1864 	   }
1865 	
1866 	   MSG_DEBUG(_realLP->writeFileLPBase("afterLift.lp", 0, 0, 0));
1867 	
1868 	   // stop timing
1869 	   _statistics->transformTime->stop();
1870 	
1871 	   if(numColsRational() > _beforeLiftCols || numRowsRational() > _beforeLiftRows)
1872 	   {
1873 	      MSG_INFO1(spxout, spxout << "Added " << numColsRational() - _beforeLiftCols << " columns and "
1874 	                << numRowsRational() - _beforeLiftRows << " rows to reduce large matrix coefficients\n.");
1875 	   }
1876 	}
1877 	
1878 	
1879 	
1880 	/// undoes lifting
1881 	template <class R>
1882 	void SoPlexBase<R>::_project(SolRational& sol)
1883 	{
1884 	   // start timing
1885 	   _statistics->transformTime->start();
1886 	
1887 	   // print LP if in debug mode
1888 	   MSG_DEBUG(_realLP->writeFileLPBase("beforeProject.lp", 0, 0, 0));
1889 	
1890 	   assert(numColsRational() >= _beforeLiftCols);
1891 	   assert(numRowsRational() >= _beforeLiftRows);
1892 	
1893 	   // shrink rational LP to original size
1894 	   _rationalLP->removeColRange(_beforeLiftCols, numColsRational() - 1);
1895 	   _rationalLP->removeRowRange(_beforeLiftRows, numRowsRational() - 1);
1896 	
1897 	   // shrink real LP to original size
1898 	   _realLP->removeColRange(_beforeLiftCols, numColsReal() - 1);
1899 	   _realLP->removeRowRange(_beforeLiftRows, numRowsReal() - 1);
1900 	
1901 	   // adjust solution
1902 	   if(sol.isPrimalFeasible())
1903 	   {
1904 	      sol._primal.reDim(_beforeLiftCols);
1905 	      sol._slacks.reDim(_beforeLiftRows);
1906 	   }
1907 	
1908 	   if(sol.hasPrimalRay())
1909 	   {
1910 	      sol._primalRay.reDim(_beforeLiftCols);
1911 	   }
1912 	
1913 	   ///@todo if we know the mapping between original and lifting columns, we simply need to add the reduced cost of
1914 	   ///      the lifting column to the reduced cost of the original column; this is not implemented now, because for
1915 	   ///      optimal solutions the reduced costs of the lifting columns are zero
1916 	   const Rational maxValue = Rational(realParam(SoPlexBase<R>::LIFTMAXVAL));
1917 	
1918 	   for(int i = _beforeLiftCols; i < numColsRational() && sol._isDualFeasible; i++)
1919 	   {
1920 	      if(spxAbs(Rational(maxValue * sol._redCost[i])) > _rationalOpttol)
1921 	      {
1922 	         MSG_INFO1(spxout, spxout << "Warning: lost dual solution during project phase.\n");
1923 	         sol._isDualFeasible = false;
1924 	      }
1925 	   }
1926 	
1927 	   if(sol.isDualFeasible())
1928 	   {
1929 	      sol._redCost.reDim(_beforeLiftCols);
1930 	      sol._dual.reDim(_beforeLiftRows);
1931 	   }
1932 	
1933 	   if(sol.hasDualFarkas())
1934 	   {
1935 	      sol._dualFarkas.reDim(_beforeLiftRows);
1936 	   }
1937 	
1938 	   // adjust basis
1939 	   for(int i = _beforeLiftCols; i < numColsRational() && _hasBasis; i++)
1940 	   {
1941 	      if(_basisStatusCols[i] != SPxSolverBase<R>::BASIC)
1942 	      {
1943 	         MSG_INFO1(spxout, spxout <<
1944 	                   "Warning: lost basis during project phase because of nonbasic lifting column.\n");
1945 	         _hasBasis = false;
1946 	         _rationalLUSolver.clear();
1947 	      }
1948 	   }
1949 	
1950 	   for(int i = _beforeLiftRows; i < numRowsRational() && _hasBasis; i++)
1951 	   {
1952 	      if(_basisStatusRows[i] == SPxSolverBase<R>::BASIC)
1953 	      {
1954 	         MSG_INFO1(spxout, spxout <<
1955 	                   "Warning: lost basis during project phase because of basic lifting row.\n");
1956 	         _hasBasis = false;
1957 	         _rationalLUSolver.clear();
1958 	      }
1959 	   }
1960 	
1961 	   if(_hasBasis)
1962 	   {
1963 	      _basisStatusCols.reSize(_beforeLiftCols);
1964 	      _basisStatusRows.reSize(_beforeLiftRows);
1965 	      _rationalLUSolver.clear();
1966 	   }
1967 	
1968 	   // print LP if in debug mode
1969 	   MSG_DEBUG(_realLP->writeFileLPBase("afterProject.lp", 0, 0, 0));
1970 	
1971 	   // stop timing
1972 	   _statistics->transformTime->stop();
1973 	}
1974 	
1975 	
1976 	
1977 	/// stores objective, bounds, and sides of real LP
1978 	template <class R>
1979 	void SoPlexBase<R>::_storeLPReal()
1980 	{
1981 	#ifndef SOPLEX_MANUAL_ALT
1982 	
1983 	   if(intParam(SoPlexBase<R>::SYNCMODE) == SYNCMODE_MANUAL)
1984 	   {
1985 	      _manualRealLP = *_realLP;
1986 	      return;
1987 	   }
1988 	
1989 	#endif
1990 	
1991 	   _manualLower = _realLP->lower();
1992 	   _manualUpper = _realLP->upper();
1993 	   _manualLhs = _realLP->lhs();
1994 	   _manualRhs = _realLP->rhs();
1995 	   _manualObj.reDim(_realLP->nCols());
1996 	   _realLP->getObj(_manualObj);
1997 	}
1998 	
1999 	
2000 	
2001 	/// restores objective, bounds, and sides of real LP
2002 	template <class R>
2003 	void SoPlexBase<R>::_restoreLPReal()
2004 	{
2005 	   if(intParam(SoPlexBase<R>::SYNCMODE) == SYNCMODE_MANUAL)
2006 	   {
2007 	#ifndef SOPLEX_MANUAL_ALT
2008 	      _solver.loadLP(_manualRealLP);
2009 	#else
2010 	      _realLP->changeLower(_manualLower);
2011 	      _realLP->changeUpper(_manualUpper);
2012 	      _realLP->changeLhs(_manualLhs);
2013 	      _realLP->changeRhs(_manualRhs);
2014 	      _realLP->changeObj(_manualObj);
2015 	#endif
2016 	
2017 	      if(_hasBasis)
2018 	      {
2019 	         // in manual sync mode, if the right-hand side of an equality constraint is not floating-point
2020 	         // representable, the user might have constructed the constraint in the real LP by rounding down the
2021 	         // left-hand side and rounding up the right-hand side; if the basis status is fixed, we need to adjust it
2022 	         for(int i = 0; i < _solver.nRows(); i++)
2023 	         {
2024 	            if(_basisStatusRows[i] == SPxSolverBase<R>::FIXED && _solver.lhs(i) != _solver.rhs(i))
2025 	            {
2026 	               assert(_solver.rhs(i) == spxNextafter(_solver.lhs(i), R(infinity)));
2027 	
2028 	               if(_hasSolRational && _solRational.isDualFeasible()
2029 	                     && ((intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MAXIMIZE
2030 	                          && _solRational._dual[i] > 0)
2031 	                         || (intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MINIMIZE
2032 	                             && _solRational._dual[i] < 0)))
2033 	               {
2034 	                  _basisStatusRows[i] = SPxSolverBase<R>::ON_UPPER;
2035 	               }
2036 	               else
2037 	               {
2038 	                  _basisStatusRows[i] = SPxSolverBase<R>::ON_LOWER;
2039 	               }
2040 	            }
2041 	         }
2042 	
2043 	         _solver.setBasis(_basisStatusRows.get_const_ptr(), _basisStatusCols.get_const_ptr());
2044 	         _hasBasis = (_solver.basis().status() > SPxBasisBase<R>::NO_PROBLEM);
2045 	      }
2046 	   }
2047 	   else
2048 	   {
2049 	      _realLP->changeLower(_manualLower);
2050 	      _realLP->changeUpper(_manualUpper);
2051 	      _realLP->changeLhs(_manualLhs);
2052 	      _realLP->changeRhs(_manualRhs);
2053 	      _realLP->changeObj(_manualObj);
2054 	   }
2055 	}
2056 	
2057 	
2058 	
2059 	/// introduces slack variables to transform inequality constraints into equations for both rational and real LP,
2060 	/// which should be in sync
2061 	template <class R>
2062 	void SoPlexBase<R>::_transformEquality()
2063 	{
2064 	   MSG_DEBUG(std::cout << "Transforming rows to equation form.\n");
2065 	
2066 	   // start timing
2067 	   _statistics->transformTime->start();
2068 	
2069 	   MSG_DEBUG(_realLP->writeFileLPBase("beforeTransEqu.lp", 0, 0, 0));
2070 	
2071 	   // clear array of slack columns
2072 	   _slackCols.clear();
2073 	
2074 	   // add artificial slack variables to convert inequality to equality constraints
2075 	   for(int i = 0; i < numRowsRational(); i++)
2076 	   {
2077 	      assert((lhsRational(i) == rhsRational(i)) == (_rowTypes[i] == RANGETYPE_FIXED));
2078 	
2079 	      if(_rowTypes[i] != RANGETYPE_FIXED)
2080 	      {
2081 	         _slackCols.add(_rationalZero, -rhsRational(i), *_unitVectorRational(i), -lhsRational(i));
2082 	
2083 	         if(_rationalLP->lhs(i) != 0)
2084 	            _rationalLP->changeLhs(i, _rationalZero);
2085 	
2086 	         if(_rationalLP->rhs(i) != 0)
2087 	            _rationalLP->changeRhs(i, _rationalZero);
2088 	
2089 	         assert(_rationalLP->lhs(i) == 0);
2090 	         assert(_rationalLP->rhs(i) == 0);
2091 	         _realLP->changeRange(i, R(0.0), R(0.0));
2092 	         _colTypes.append(_switchRangeType(_rowTypes[i]));
2093 	         _rowTypes[i] = RANGETYPE_FIXED;
2094 	      }
2095 	   }
2096 	
2097 	   _rationalLP->addCols(_slackCols);
2098 	   _realLP->addCols(_slackCols);
2099 	
2100 	   // adjust basis
2101 	   if(_hasBasis)
2102 	   {
2103 	      for(int i = 0; i < _slackCols.num(); i++)
2104 	      {
2105 	         int row = _slackCols.colVector(i).index(0);
2106 	
2107 	         assert(row >= 0);
2108 	         assert(row < numRowsRational());
2109 	
2110 	         switch(_basisStatusRows[row])
2111 	         {
2112 	         case SPxSolverBase<R>::ON_LOWER:
2113 	            _basisStatusCols.append(SPxSolverBase<R>::ON_UPPER);
2114 	            break;
2115 	
2116 	         case SPxSolverBase<R>::ON_UPPER:
2117 	            _basisStatusCols.append(SPxSolverBase<R>::ON_LOWER);
2118 	            break;
2119 	
2120 	         case SPxSolverBase<R>::BASIC:
2121 	         case SPxSolverBase<R>::FIXED:
2122 	         default:
2123 	            _basisStatusCols.append(_basisStatusRows[row]);
2124 	            break;
2125 	         }
2126 	
2127 	         _basisStatusRows[row] = SPxSolverBase<R>::FIXED;
2128 	      }
2129 	
2130 	      _rationalLUSolver.clear();
2131 	   }
2132 	
2133 	   MSG_DEBUG(_realLP->writeFileLPBase("afterTransEqu.lp", 0, 0, 0));
2134 	
2135 	   // stop timing
2136 	   _statistics->transformTime->stop();
2137 	
2138 	   if(_slackCols.num() > 0)
2139 	   {
2140 	      MSG_INFO1(spxout, spxout << "Added " << _slackCols.num() <<
2141 	                " slack columns to transform rows to equality form.\n");
2142 	   }
2143 	}
2144 	
2145 	
2146 	
2147 	/// restores original problem
2148 	template <class R>
2149 	void SoPlexBase<R>::_untransformEquality(SolRational& sol)
2150 	{
2151 	   // start timing
2152 	   _statistics->transformTime->start();
2153 	
2154 	   // print LP if in debug mode
2155 	   MSG_DEBUG(_realLP->writeFileLPBase("beforeUntransEqu.lp", 0, 0, 0));
2156 	
2157 	   int numCols = numColsRational();
2158 	   int numOrigCols = numColsRational() - _slackCols.num();
2159 	
2160 	   // adjust solution
2161 	   if(sol.isPrimalFeasible())
2162 	   {
2163 	      for(int i = 0; i < _slackCols.num(); i++)
2164 	      {
2165 	         int col = numOrigCols + i;
2166 	         int row = _slackCols.colVector(i).index(0);
2167 	
2168 	         assert(row >= 0);
2169 	         assert(row < numRowsRational());
2170 	
2171 	         sol._slacks[row] -= sol._primal[col];
2172 	      }
2173 	
2174 	      sol._primal.reDim(numOrigCols);
2175 	   }
2176 	
2177 	   if(sol.hasPrimalRay())
2178 	   {
2179 	      sol._primalRay.reDim(numOrigCols);
2180 	   }
2181 	
2182 	   // adjust basis
2183 	   if(_hasBasis)
2184 	   {
2185 	      for(int i = 0; i < _slackCols.num(); i++)
2186 	      {
2187 	         int col = numOrigCols + i;
2188 	         int row = _slackCols.colVector(i).index(0);
2189 	
2190 	         assert(row >= 0);
2191 	         assert(row < numRowsRational());
2192 	         assert(_basisStatusRows[row] != SPxSolverBase<R>::UNDEFINED);
2193 	         assert(_basisStatusRows[row] != SPxSolverBase<R>::ZERO || lhsRational(row) == 0);
2194 	         assert(_basisStatusRows[row] != SPxSolverBase<R>::ZERO || rhsRational(row) == 0);
2195 	         assert(_basisStatusRows[row] != SPxSolverBase<R>::BASIC
2196 	                || _basisStatusCols[col] != SPxSolverBase<R>::BASIC);
2197 	
2198 	         MSG_DEBUG(std::cout << "slack column " << col << " for row " << row
2199 	                   << ": col status=" << _basisStatusCols[col]
2200 	                   << ", row status=" << _basisStatusRows[row]
2201 	                   << ", redcost=" << sol._redCost[col].str()
2202 	                   << ", dual=" << sol._dual[row].str() << "\n");
2203 	
2204 	         if(_basisStatusRows[row] != SPxSolverBase<R>::BASIC)
2205 	         {
2206 	            switch(_basisStatusCols[col])
2207 	            {
2208 	            case SPxSolverBase<R>::ON_LOWER:
2209 	               _basisStatusRows[row] = SPxSolverBase<R>::ON_UPPER;
2210 	               break;
2211 	
2212 	            case SPxSolverBase<R>::ON_UPPER:
2213 	               _basisStatusRows[row] = SPxSolverBase<R>::ON_LOWER;
2214 	               break;
2215 	
2216 	            case SPxSolverBase<R>::BASIC:
2217 	            case SPxSolverBase<R>::FIXED:
2218 	            default:
2219 	               _basisStatusRows[row] = _basisStatusCols[col];
2220 	               break;
2221 	            }
2222 	         }
2223 	      }
2224 	
2225 	      _basisStatusCols.reSize(numOrigCols);
2226 	
2227 	      if(_slackCols.num() > 0)
2228 	         _rationalLUSolver.clear();
2229 	   }
2230 	
2231 	   // not earlier because of debug message
2232 	   if(sol.isDualFeasible())
2233 	   {
2234 	      sol._redCost.reDim(numOrigCols);
2235 	   }
2236 	
2237 	   // restore sides and remove slack columns
2238 	   for(int i = 0; i < _slackCols.num(); i++)
2239 	   {
2240 	      int col = numOrigCols + i;
2241 	      int row = _slackCols.colVector(i).index(0);
2242 	
2243 	      if(upperRational(col) != 0)
2244 	         _rationalLP->changeLhs(row, -upperRational(col));
2245 	
2246 	      if(lowerRational(col) != 0)
2247 	         _rationalLP->changeRhs(row, -lowerRational(col));
2248 	
2249 	      assert(_rationalLP->lhs(row) == -upperRational(col));
2250 	      assert(_rationalLP->rhs(row) == -lowerRational(col));
2251 	      _rowTypes[row] = _switchRangeType(_colTypes[col]);
2252 	   }
2253 	
2254 	   _rationalLP->removeColRange(numOrigCols, numCols - 1);
2255 	   _realLP->removeColRange(numOrigCols, numCols - 1);
2256 	   _colTypes.reSize(numOrigCols);
2257 	
2258 	   // objective, bounds, and sides of real LP are restored only after _solveRational()
2259 	
2260 	   // print LP if in debug mode
2261 	   MSG_DEBUG(_realLP->writeFileLPBase("afterUntransEqu.lp", 0, 0, 0));
2262 	
2263 	   // stop timing
2264 	   _statistics->transformTime->stop();
2265 	}
2266 	
2267 	
2268 	
2269 	/// transforms LP to unboundedness problem by moving the objective function to the constraints, changing right-hand
2270 	/// side and bounds to zero, and adding an auxiliary variable for the decrease in the objective function
2271 	template <class R>
2272 	void SoPlexBase<R>::_transformUnbounded()
2273 	{
2274 	   MSG_INFO1(spxout, spxout << "Setting up LP to compute primal unbounded ray.\n");
2275 	
2276 	   // start timing
2277 	   _statistics->transformTime->start();
2278 	
2279 	   // print LP if in debug mode
2280 	   MSG_DEBUG(_realLP->writeFileLPBase("beforeTransUnbounded.lp", 0, 0, 0));
2281 	
2282 	   // store bounds
2283 	   _unboundedLower.reDim(numColsRational());
2284 	   _unboundedUpper.reDim(numColsRational());
2285 	
2286 	   for(int c = numColsRational() - 1; c >= 0; c--)
2287 	   {
2288 	      if(_lowerFinite(_colTypes[c]))
2289 	         _unboundedLower[c] = lowerRational(c);
2290 	
2291 	      if(_upperFinite(_colTypes[c]))
2292 	         _unboundedUpper[c] = upperRational(c);
2293 	   }
2294 	
2295 	   // store sides
2296 	   _unboundedLhs.reDim(numRowsRational());
2297 	   _unboundedRhs.reDim(numRowsRational());
2298 	
2299 	   for(int r = numRowsRational() - 1; r >= 0; r--)
2300 	   {
2301 	      if(_lowerFinite(_rowTypes[r]))
2302 	         _unboundedLhs[r] = lhsRational(r);
2303 	
2304 	      if(_upperFinite(_rowTypes[r]))
2305 	         _unboundedRhs[r] = rhsRational(r);
2306 	   }
2307 	
2308 	   // make right-hand side zero
2309 	   for(int r = numRowsRational() - 1; r >= 0; r--)
2310 	   {
2311 	      assert((lhsRational(r) > _rationalNegInfty) == _lowerFinite(_rowTypes[r]));
2312 	
2313 	      if(_lowerFinite(_rowTypes[r]))
2314 	      {
2315 	         _rationalLP->changeLhs(r, Rational(0));
2316 	         _realLP->changeLhs(r, R(0.0));
2317 	      }
2318 	      else if(_realLP->lhs(r) > -realParam(SoPlexBase<R>::INFTY))
2319 	         _realLP->changeLhs(r, -realParam(SoPlexBase<R>::INFTY));
2320 	
2321 	      assert((rhsRational(r) < _rationalPosInfty) == _upperFinite(_rowTypes[r]));
2322 	
2323 	      if(_upperFinite(_rowTypes[r]))
2324 	      {
2325 	         _rationalLP->changeRhs(r, Rational(0));
2326 	         _realLP->changeRhs(r, R(0.0));
2327 	      }
2328 	      else if(_realLP->rhs(r) < realParam(SoPlexBase<R>::INFTY))
2329 	         _realLP->changeRhs(r, realParam(SoPlexBase<R>::INFTY));
2330 	   }
2331 	
2332 	   // transform objective function to constraint and add auxiliary variable
2333 	   int numOrigCols = numColsRational();
2334 	   DSVectorRational obj(numOrigCols + 1);
2335 	   ///@todo implement this without copying the objective function
2336 	   obj = _rationalLP->maxObj();
2337 	   obj.add(numOrigCols, -1);
2338 	   _rationalLP->addRow(LPRowRational(0, obj, 0));
2339 	   _realLP->addRow(LPRowBase<R>(0, DSVectorBase<R>(obj), 0));
2340 	   _rowTypes.append(RANGETYPE_FIXED);
2341 	
2342 	   assert(numColsRational() == numOrigCols + 1);
2343 	
2344 	   // set objective coefficient and bounds for auxiliary variable
2345 	   _rationalLP->changeMaxObj(numOrigCols, Rational(1));
2346 	   _realLP->changeMaxObj(numOrigCols, R(1.0));
2347 	
2348 	   _rationalLP->changeBounds(numOrigCols, _rationalNegInfty, 1);
2349 	   _realLP->changeBounds(numOrigCols, -realParam(SoPlexBase<R>::INFTY), 1.0);
2350 	   _colTypes.append(RANGETYPE_UPPER);
2351 	
2352 	   // set objective coefficients to zero and adjust bounds for problem variables
2353 	   for(int c = numColsRational() - 2; c >= 0; c--)
2354 	   {
2355 	      _rationalLP->changeObj(c, Rational(0));
2356 	      _realLP->changeObj(c, R(0.0));
2357 	
2358 	      assert((lowerRational(c) > _rationalNegInfty) == _lowerFinite(_colTypes[c]));
2359 	
2360 	      if(_lowerFinite(_colTypes[c]))
2361 	      {
2362 	         _rationalLP->changeLower(c, Rational(0));
2363 	         _realLP->changeLower(c, R(0.0));
2364 	      }
2365 	      else if(_realLP->lower(c) > -realParam(SoPlexBase<R>::INFTY))
2366 	         _realLP->changeLower(c, -realParam(SoPlexBase<R>::INFTY));
2367 	
2368 	      assert((upperRational(c) < _rationalPosInfty) == _upperFinite(_colTypes[c]));
2369 	
2370 	      if(_upperFinite(_colTypes[c]))
2371 	      {
2372 	         _rationalLP->changeUpper(c, Rational(0));
2373 	         _realLP->changeUpper(c, R(0.0));
2374 	      }
2375 	      else if(_realLP->upper(c) < realParam(SoPlexBase<R>::INFTY))
2376 	         _realLP->changeUpper(c, realParam(SoPlexBase<R>::INFTY));
2377 	   }
2378 	
2379 	   // adjust basis
2380 	   if(_hasBasis)
2381 	   {
2382 	      _basisStatusCols.append(SPxSolverBase<R>::ON_UPPER);
2383 	      _basisStatusRows.append(SPxSolverBase<R>::BASIC);
2384 	      _rationalLUSolver.clear();
2385 	   }
2386 	
2387 	   // print LP if in debug mode
2388 	   MSG_DEBUG(_realLP->writeFileLPBase("afterTransUnbounded.lp", 0, 0, 0));
2389 	
2390 	   // stop timing
2391 	   _statistics->transformTime->stop();
2392 	}
2393 	
2394 	
2395 	
2396 	/// undoes transformation to unboundedness problem
2397 	template <class R>
2398 	void SoPlexBase<R>::_untransformUnbounded(SolRational& sol, bool unbounded)
2399 	{
2400 	   // start timing
2401 	   _statistics->transformTime->start();
2402 	
2403 	   // print LP if in debug mode
2404 	   MSG_DEBUG(_realLP->writeFileLPBase("beforeUntransUnbounded.lp", 0, 0, 0));
2405 	
2406 	   int numOrigCols = numColsRational() - 1;
2407 	   int numOrigRows = numRowsRational() - 1;
2408 	   const Rational& tau = sol._primal[numOrigCols];
2409 	
2410 	   // adjust solution and basis
2411 	   if(unbounded)
2412 	   {
2413 	      assert(tau >= _rationalPosone);
2414 	
2415 	      sol._isPrimalFeasible = false;
2416 	      sol._hasPrimalRay = true;
2417 	      sol._isDualFeasible = false;
2418 	      sol._hasDualFarkas = false;
2419 	
2420 	      if(tau != 1)
2421 	         sol._primal /= tau;
2422 	
2423 	      sol._primalRay = sol._primal;
2424 	      sol._primalRay.reDim(numOrigCols);
2425 	
2426 	      _hasBasis = (_basisStatusCols[numOrigCols] != SPxSolverBase<R>::BASIC
2427 	                   && _basisStatusRows[numOrigRows] == SPxSolverBase<R>::BASIC);
2428 	      _basisStatusCols.reSize(numOrigCols);
2429 	      _basisStatusRows.reSize(numOrigRows);
2430 	   }
2431 	   else if(boolParam(SoPlexBase<R>::TESTDUALINF) && tau < _rationalFeastol)
2432 	   {
2433 	      const Rational& alpha = sol._dual[numOrigRows];
2434 	
2435 	      assert(sol._isDualFeasible);
2436 	      assert(alpha <= _rationalFeastol - _rationalPosone);
2437 	
2438 	      sol._isPrimalFeasible = false;
2439 	      sol._hasPrimalRay = false;
2440 	      sol._hasDualFarkas = false;
2441 	
2442 	      if(alpha != -1)
2443 	      {
2444 	         sol._dual /= -alpha;
2445 	         sol._redCost /= -alpha;
2446 	      }
2447 	
2448 	      sol._dual.reDim(numOrigRows);
2449 	      sol._redCost.reDim(numOrigCols);
2450 	   }
2451 	   else
2452 	   {
2453 	      sol.invalidate();
2454 	      _hasBasis = false;
2455 	      _basisStatusCols.reSize(numOrigCols);
2456 	      _basisStatusCols.reSize(numOrigRows);
2457 	   }
2458 	
2459 	   // recover objective function
2460 	   const SVectorRational& objRowVector = _rationalLP->rowVector(numOrigRows);
2461 	
2462 	   for(int i = objRowVector.size() - 1; i >= 0; i--)
2463 	   {
2464 	      _rationalLP->changeMaxObj(objRowVector.index(i), objRowVector.value(i));
2465 	      _realLP->changeMaxObj(objRowVector.index(i), R(objRowVector.value(i)));
2466 	   }
2467 	
2468 	   // remove objective function constraint and auxiliary variable
2469 	   _rationalLP->removeRow(numOrigRows);
2470 	   _realLP->removeRow(numOrigRows);
2471 	   _rowTypes.reSize(numOrigRows);
2472 	
2473 	   _rationalLP->removeCol(numOrigCols);
2474 	   _realLP->removeCol(numOrigCols);
2475 	   _colTypes.reSize(numOrigCols);
2476 	
2477 	   // restore objective, sides and bounds
2478 	   for(int r = numRowsRational() - 1; r >= 0; r--)
2479 	   {
2480 	      if(_lowerFinite(_rowTypes[r]))
2481 	      {
2482 	         _rationalLP->changeLhs(r, _unboundedLhs[r]);
2483 	         _realLP->changeLhs(r, R(_unboundedLhs[r]));
2484 	      }
2485 	
2486 	      if(_upperFinite(_rowTypes[r]))
2487 	      {
2488 	         _rationalLP->changeRhs(r, _unboundedRhs[r]);
2489 	         _realLP->changeRhs(r, R(_unboundedRhs[r]));
2490 	      }
2491 	
2492 	      assert((lhsRational(r) > _rationalNegInfty) == _lowerFinite(_rowTypes[r]));
2493 	      assert((rhsRational(r) < _rationalPosInfty) == _upperFinite(_rowTypes[r]));
2494 	      assert((lhsReal(r) > -realParam(SoPlexBase<R>::INFTY)) == _lowerFinite(_rowTypes[r]));
2495 	      assert((rhsReal(r) < realParam(SoPlexBase<R>::INFTY)) == _upperFinite(_rowTypes[r]));
2496 	   }
2497 	
2498 	   for(int c = numColsRational() - 1; c >= 0; c--)
2499 	   {
2500 	      if(_lowerFinite(_colTypes[c]))
2501 	      {
2502 	         _rationalLP->changeLower(c, _unboundedLower[c]);
2503 	         _realLP->changeLower(c, R(_unboundedLower[c]));
2504 	      }
2505 	
2506 	      if(_upperFinite(_colTypes[c]))
2507 	      {
2508 	         _rationalLP->changeUpper(c, _unboundedUpper[c]);
2509 	         _realLP->changeUpper(c, R(_unboundedUpper[c]));
2510 	      }
2511 	
2512 	      assert((lowerRational(c) > _rationalNegInfty) == _lowerFinite(_colTypes[c]));
2513 	      assert((upperRational(c) < _rationalPosInfty) == _upperFinite(_colTypes[c]));
2514 	      assert((lowerReal(c) > -realParam(SoPlexBase<R>::INFTY)) == _lowerFinite(_colTypes[c]));
2515 	      assert((upperReal(c) < realParam(SoPlexBase<R>::INFTY)) == _upperFinite(_colTypes[c]));
2516 	   }
2517 	
2518 	   // invalidate rational basis factorization
2519 	   _rationalLUSolver.clear();
2520 	
2521 	   // print LP if in debug mode
2522 	   MSG_DEBUG(_realLP->writeFileLPBase("afterUntransUnbounded.lp", 0, 0, 0));
2523 	
2524 	   // stop timing
2525 	   _statistics->transformTime->stop();
2526 	}
2527 	
2528 	
2529 	
2530 	/// store basis
2531 	template <class R>
2532 	void SoPlexBase<R>::_storeBasis()
2533 	{
2534 	   assert(!_storedBasis);
2535 	
2536 	   if(_hasBasis)
2537 	   {
2538 	      _storedBasis = true;
2539 	      _storedBasisStatusCols = _basisStatusCols;
2540 	      _storedBasisStatusRows = _basisStatusRows;
2541 	   }
2542 	   else
2543 	      _storedBasis = false;
2544 	}
2545 	
2546 	
2547 	
2548 	/// restore basis
2549 	template <class R>
2550 	void SoPlexBase<R>::_restoreBasis()
2551 	{
2552 	   if(_storedBasis)
2553 	   {
2554 	      _hasBasis = true;
2555 	      _basisStatusCols = _storedBasisStatusCols;
2556 	      _basisStatusRows = _storedBasisStatusRows;
2557 	      _storedBasis = false;
2558 	   }
2559 	}
2560 	
2561 	
2562 	
2563 	/// transforms LP to feasibility problem by removing the objective function, shifting variables, and homogenizing the
2564 	/// right-hand side
2565 	template <class R>
2566 	void SoPlexBase<R>::_transformFeasibility()
2567 	{
2568 	   MSG_INFO1(spxout, spxout << "Setting up LP to test for feasibility.\n");
2569 	
2570 	   // start timing
2571 	   _statistics->transformTime->start();
2572 	
2573 	   // print LP if in debug mode
2574 	   MSG_DEBUG(_realLP->writeFileLPBase("beforeTransFeas.lp", 0, 0, 0));
2575 	
2576 	   // store objective function
2577 	   _feasObj.reDim(numColsRational());
2578 	
2579 	   for(int c = numColsRational() - 1; c >= 0; c--)
2580 	      _feasObj[c] = _rationalLP->maxObj(c);
2581 	
2582 	   // store bounds
2583 	   _feasLower.reDim(numColsRational());
2584 	   _feasUpper.reDim(numColsRational());
2585 	
2586 	   for(int c = numColsRational() - 1; c >= 0; c--)
2587 	   {
2588 	      if(_lowerFinite(_colTypes[c]))
2589 	         _feasLower[c] = lowerRational(c);
2590 	
2591 	      if(_upperFinite(_colTypes[c]))
2592 	         _feasUpper[c] = upperRational(c);
2593 	   }
2594 	
2595 	   // store sides
2596 	   _feasLhs.reDim(numRowsRational());
2597 	   _feasRhs.reDim(numRowsRational());
2598 	
2599 	   for(int r = numRowsRational() - 1; r >= 0; r--)
2600 	   {
2601 	      if(_lowerFinite(_rowTypes[r]))
2602 	         _feasLhs[r] = lhsRational(r);
2603 	
2604 	      if(_upperFinite(_rowTypes[r]))
2605 	         _feasRhs[r] = rhsRational(r);
2606 	   }
2607 	
2608 	   // set objective coefficients to zero; shift primal space such as to guarantee that the zero solution is within
2609 	   // the bounds
2610 	   Rational shiftValue;
2611 	   Rational shiftValue2;
2612 	
2613 	   for(int c = numColsRational() - 1; c >= 0; c--)
2614 	   {
2615 	      _rationalLP->changeMaxObj(c, Rational(0));
2616 	      _realLP->changeMaxObj(c, R(0.0));
2617 	
2618 	      if(lowerRational(c) > 0)
2619 	      {
2620 	         const SVectorRational& colVector = colVectorRational(c);
2621 	
2622 	         for(int i = 0; i < colVector.size(); i++)
2623 	         {
2624 	            shiftValue = colVector.value(i);
2625 	            shiftValue *= lowerRational(c);
2626 	            int r = colVector.index(i);
2627 	
2628 	            assert((lhsRational(r) > _rationalNegInfty) == _lowerFinite(_rowTypes[r]));
2629 	            assert((rhsRational(r) < _rationalPosInfty) == _upperFinite(_rowTypes[r]));
2630 	
2631 	            if(_lowerFinite(_rowTypes[r]) && _upperFinite(_rowTypes[r]))
2632 	            {
2633 	               shiftValue2 = lhsRational(r);
2634 	               shiftValue2 -= shiftValue;
2635 	               _rationalLP->changeLhs(r, shiftValue2);
2636 	               _realLP->changeLhs(r, R(shiftValue2));
2637 	
2638 	               shiftValue -= rhsRational(r);
2639 	               shiftValue *= -1;
2640 	               _rationalLP->changeRhs(r, shiftValue);
2641 	               _realLP->changeRhs(r, R(shiftValue));
2642 	            }
2643 	            else if(_lowerFinite(_rowTypes[r]))
2644 	            {
2645 	               shiftValue -= lhsRational(r);
2646 	               shiftValue *= -1;
2647 	               _rationalLP->changeLhs(r, shiftValue);
2648 	               _realLP->changeLhs(r, R(shiftValue));
2649 	            }
2650 	            else if(_upperFinite(_rowTypes[r]))
2651 	            {
2652 	               shiftValue -= rhsRational(r);
2653 	               shiftValue *= -1;
2654 	               _rationalLP->changeRhs(r, shiftValue);
2655 	               _realLP->changeRhs(r, R(shiftValue));
2656 	            }
2657 	         }
2658 	
2659 	         assert((upperRational(c) < _rationalPosInfty) == _upperFinite(_colTypes[c]));
2660 	
2661 	         if(_upperFinite(_colTypes[c]))
2662 	         {
2663 	            _rationalLP->changeBounds(c, 0, upperRational(c) - lowerRational(c));
2664 	            _realLP->changeBounds(c, 0.0, R(upperRational(c)));
2665 	         }
2666 	         else if(_realLP->upper(c) < realParam(SoPlexBase<R>::INFTY))
2667 	         {
2668 	            _rationalLP->changeLower(c, Rational(0));
2669 	            _realLP->changeBounds(c, 0.0, realParam(SoPlexBase<R>::INFTY));
2670 	         }
2671 	         else
2672 	         {
2673 	            _rationalLP->changeLower(c, Rational(0));
2674 	            _realLP->changeLower(c, R(0.0));
2675 	         }
2676 	      }
2677 	      else if(upperRational(c) < 0)
2678 	      {
2679 	         const SVectorRational& colVector = colVectorRational(c);
2680 	
2681 	         for(int i = 0; i < colVector.size(); i++)
2682 	         {
2683 	            shiftValue = colVector.value(i);
2684 	            shiftValue *= upperRational(c);
2685 	            int r = colVector.index(i);
2686 	
2687 	            assert((lhsRational(r) > _rationalNegInfty) == _lowerFinite(_rowTypes[r]));
2688 	            assert((rhsRational(r) < _rationalPosInfty) == _upperFinite(_rowTypes[r]));
2689 	
2690 	            if(_lowerFinite(_rowTypes[r]) && _upperFinite(_rowTypes[r]))
2691 	            {
2692 	               shiftValue2 = lhsRational(r);
2693 	               shiftValue2 -= shiftValue;
2694 	               _rationalLP->changeLhs(r, shiftValue2);
2695 	               _realLP->changeLhs(r, R(shiftValue2));
2696 	
2697 	               shiftValue -= rhsRational(r);
2698 	               shiftValue *= -1;
2699 	               _rationalLP->changeRhs(r, shiftValue);
2700 	               _realLP->changeRhs(r, R(shiftValue));
2701 	            }
2702 	            else if(_lowerFinite(_rowTypes[r]))
2703 	            {
2704 	               shiftValue -= lhsRational(r);
2705 	               shiftValue *= -1;
2706 	               _rationalLP->changeLhs(r, shiftValue);
2707 	               _realLP->changeLhs(r, R(shiftValue));
2708 	            }
2709 	            else if(_upperFinite(_rowTypes[r]))
2710 	            {
2711 	               shiftValue -= rhsRational(r);
2712 	               shiftValue *= -1;
2713 	               _rationalLP->changeRhs(r, shiftValue);
2714 	               _realLP->changeRhs(r, R(shiftValue));
2715 	            }
2716 	         }
2717 	
2718 	         assert((lowerRational(c) > _rationalNegInfty) == _lowerFinite(_colTypes[c]));
2719 	
2720 	         if(_lowerFinite(_colTypes[c]))
2721 	         {
2722 	            _rationalLP->changeBounds(c, lowerRational(c) - upperRational(c), 0);
2723 	            _realLP->changeBounds(c, R(lowerRational(c)), 0.0);
2724 	         }
2725 	         else if(_realLP->lower(c) > -realParam(SoPlexBase<R>::INFTY))
2726 	         {
2727 	            _rationalLP->changeUpper(c, Rational(0));
2728 	            _realLP->changeBounds(c, -realParam(SoPlexBase<R>::INFTY), 0.0);
2729 	         }
2730 	         else
2731 	         {
2732 	            _rationalLP->changeUpper(c, Rational(0));
2733 	            _realLP->changeUpper(c, R(0.0));
2734 	         }
2735 	      }
2736 	      else
2737 	      {
2738 	         if(_lowerFinite(_colTypes[c]))
2739 	            _realLP->changeLower(c, R(lowerRational(c)));
2740 	         else if(_realLP->lower(c) > -realParam(SoPlexBase<R>::INFTY))
2741 	            _realLP->changeLower(c, -realParam(SoPlexBase<R>::INFTY));
2742 	
2743 	         if(_upperFinite(_colTypes[c]))
2744 	            _realLP->changeUpper(c, R(upperRational(c)));
2745 	         else if(_realLP->upper(c) < realParam(SoPlexBase<R>::INFTY))
2746 	            _realLP->changeUpper(c, realParam(SoPlexBase<R>::INFTY));
2747 	      }
2748 	
2749 	      assert(lowerReal(c) <= upperReal(c));
2750 	   }
2751 	
2752 	   // homogenize sides
2753 	   _tauColVector.clear();
2754 	
2755 	   for(int r = numRowsRational() - 1; r >= 0; r--)
2756 	   {
2757 	      if(lhsRational(r) > 0)
2758 	      {
2759 	         _tauColVector.add(r, lhsRational(r));
2760 	         assert((rhsRational(r) < _rationalPosInfty) == _upperFinite(_rowTypes[r]));
2761 	
2762 	         if(_upperFinite(_rowTypes[r]))
2763 	         {
2764 	            _rationalLP->changeRange(r, 0, rhsRational(r) - lhsRational(r));
2765 	            _realLP->changeRange(r, 0.0, R(rhsRational(r)));
2766 	         }
2767 	         else
2768 	         {
2769 	            _rationalLP->changeLhs(r, Rational(0));
2770 	            _realLP->changeLhs(r, R(0.0));
2771 	
2772 	            if(_realLP->rhs(r) < realParam(SoPlexBase<R>::INFTY))
2773 	               _realLP->changeRhs(r, realParam(SoPlexBase<R>::INFTY));
2774 	         }
2775 	      }
2776 	      else if(rhsRational(r) < 0)
2777 	      {
2778 	         _tauColVector.add(r, rhsRational(r));
2779 	         assert((lhsRational(r) > _rationalNegInfty) == _lowerFinite(_rowTypes[r]));
2780 	
2781 	         if(_lowerFinite(_rowTypes[r]))
2782 	         {
2783 	            _rationalLP->changeRange(r, lhsRational(r) - rhsRational(r), 0);
2784 	            _realLP->changeRange(r, R(lhsRational(r)), 0.0);
2785 	         }
2786 	         else
2787 	         {
2788 	            _rationalLP->changeRhs(r, Rational(0));
2789 	            _realLP->changeRhs(r, R(0.0));
2790 	
2791 	            if(_realLP->lhs(r) > -realParam(SoPlexBase<R>::INFTY))
2792 	               _realLP->changeLhs(r, -realParam(SoPlexBase<R>::INFTY));
2793 	         }
2794 	      }
2795 	      else
2796 	      {
2797 	         if(_lowerFinite(_rowTypes[r]))
2798 	            _realLP->changeLhs(r, R(lhsRational(r)));
2799 	         else if(_realLP->lhs(r) > -realParam(SoPlexBase<R>::INFTY))
2800 	            _realLP->changeLhs(r, -realParam(SoPlexBase<R>::INFTY));
2801 	
2802 	         if(_upperFinite(_rowTypes[r]))
2803 	            _realLP->changeRhs(r, R(rhsRational(r)));
2804 	         else if(_realLP->rhs(r) < realParam(SoPlexBase<R>::INFTY))
2805 	            _realLP->changeRhs(r, realParam(SoPlexBase<R>::INFTY));
2806 	      }
2807 	
2808 	      assert(rhsReal(r) <= rhsReal(r));
2809 	   }
2810 	
2811 	   ///@todo exploit this case by returning without LP solving
2812 	   if(_tauColVector.size() == 0)
2813 	   {
2814 	      MSG_INFO3(spxout, spxout << "LP is trivially feasible.\n");
2815 	   }
2816 	
2817 	   // add artificial column
2818 	   SPxColId id;
2819 	   _tauColVector *= -1;
2820 	   _rationalLP->addCol(id,
2821 	                       LPColRational((intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MAXIMIZE ?
2822 	                                      _rationalPosone : _rationalNegone),
2823 	                                     _tauColVector, 1, 0));
2824 	   _realLP->addCol(id,
2825 	                   LPColBase<R>((intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MAXIMIZE ? 1.0 : -1.0),
2826 	                                DSVectorBase<R>(_tauColVector), 1.0, 0.0));
2827 	   _colTypes.append(RANGETYPE_BOXED);
2828 	
2829 	   // adjust basis
2830 	   if(_hasBasis)
2831 	   {
2832 	      _basisStatusCols.append(SPxSolverBase<R>::ON_UPPER);
2833 	   }
2834 	
2835 	   // invalidate rational basis factorization
2836 	   _rationalLUSolver.clear();
2837 	
2838 	   // print LP if in debug mode
2839 	   MSG_DEBUG(_realLP->writeFileLPBase("afterTransFeas.lp", 0, 0, 0));
2840 	
2841 	   // stop timing
2842 	   _statistics->transformTime->stop();
2843 	}
2844 	
2845 	
2846 	
2847 	/// undoes transformation to feasibility problem
2848 	template <class R>
2849 	void SoPlexBase<R>::_untransformFeasibility(SolRational& sol, bool infeasible)
2850 	{
2851 	   // start timing
2852 	   _statistics->transformTime->start();
2853 	
2854 	   // print LP if in debug mode
2855 	   MSG_DEBUG(_realLP->writeFileLPBase("beforeUntransFeas.lp", 0, 0, 0));
2856 	
2857 	   int numOrigCols = numColsRational() - 1;
2858 	
2859 	   // adjust solution and basis
2860 	   if(infeasible)
2861 	   {
2862 	      assert(sol._isDualFeasible);
2863 	      assert(sol._primal[numOrigCols] < 1);
2864 	
2865 	      sol._isPrimalFeasible = false;
2866 	      sol._hasPrimalRay = false;
2867 	      sol._isDualFeasible = false;
2868 	      sol._hasDualFarkas = true;
2869 	
2870 	      sol._dualFarkas = sol._dual;
2871 	
2872 	      _hasBasis = false;
2873 	      _basisStatusCols.reSize(numOrigCols);
2874 	   }
2875 	   else if(sol._isPrimalFeasible)
2876 	   {
2877 	      assert(sol._primal[numOrigCols] >= 1);
2878 	
2879 	      sol._hasPrimalRay = false;
2880 	      sol._isDualFeasible = false;
2881 	      sol._hasDualFarkas = false;
2882 	
2883 	      if(sol._primal[numOrigCols] != 1)
2884 	      {
2885 	         sol._slacks /= sol._primal[numOrigCols];
2886 	
2887 	         for(int i = 0; i < numOrigCols; i++)
2888 	            sol._primal[i] /= sol._primal[numOrigCols];
2889 	
2890 	         sol._primal[numOrigCols] = 1;
2891 	      }
2892 	
2893 	      sol._primal.reDim(numOrigCols);
2894 	      sol._slacks -= _rationalLP->colVector(numOrigCols);
2895 	
2896 	      _hasBasis = (_basisStatusCols[numOrigCols] != SPxSolverBase<R>::BASIC);
2897 	      _basisStatusCols.reSize(numOrigCols);
2898 	   }
2899 	   else
2900 	   {
2901 	      _hasBasis = false;
2902 	      _basisStatusCols.reSize(numOrigCols);
2903 	   }
2904 	
2905 	   // restore right-hand side
2906 	   for(int r = numRowsRational() - 1; r >= 0; r--)
2907 	   {
2908 	      assert(rhsRational(r) >= _rationalPosInfty || lhsRational(r) <= _rationalNegInfty
2909 	             || _feasLhs[r] - lhsRational(r) == _feasRhs[r] - rhsRational(r));
2910 	
2911 	      if(_lowerFinite(_rowTypes[r]))
2912 	      {
2913 	         _rationalLP->changeLhs(r, _feasLhs[r]);
2914 	         _realLP->changeLhs(r, R(_feasLhs[r]));
2915 	      }
2916 	      else if(_realLP->lhs(r) > -realParam(SoPlexBase<R>::INFTY))
2917 	         _realLP->changeLhs(r, -realParam(SoPlexBase<R>::INFTY));
2918 	
2919 	      assert(_lowerFinite(_rowTypes[r]) == (lhsRational(r) > _rationalNegInfty));
2920 	      assert(_lowerFinite(_rowTypes[r]) == (lhsReal(r) > -realParam(SoPlexBase<R>::INFTY)));
2921 	
2922 	      if(_upperFinite(_rowTypes[r]))
2923 	      {
2924 	         _rationalLP->changeRhs(r, _feasRhs[r]);
2925 	         _realLP->changeRhs(r, R(_feasRhs[r]));
2926 	      }
2927 	      else if(_realLP->rhs(r) < realParam(SoPlexBase<R>::INFTY))
2928 	         _realLP->changeRhs(r, realParam(SoPlexBase<R>::INFTY));
2929 	
2930 	      assert(_upperFinite(_rowTypes[r]) == (rhsRational(r) < _rationalPosInfty));
2931 	      assert(_upperFinite(_rowTypes[r]) == (rhsReal(r) < realParam(SoPlexBase<R>::INFTY)));
2932 	
2933 	      assert(lhsReal(r) <= rhsReal(r));
2934 	   }
2935 	
2936 	   // unshift primal space and restore objective coefficients
2937 	   Rational shiftValue;
2938 	
2939 	   for(int c = numOrigCols - 1; c >= 0; c--)
2940 	   {
2941 	      bool shifted = (_lowerFinite(_colTypes[c]) && _feasLower[c] > 0) || (_upperFinite(_colTypes[c])
2942 	                     && _feasUpper[c] < 0);
2943 	      assert(shifted || !_lowerFinite(_colTypes[c]) || _feasLower[c] == lowerRational(c));
2944 	      assert(shifted || !_upperFinite(_colTypes[c]) || _feasUpper[c] == upperRational(c));
2945 	      assert(upperRational(c) >= _rationalPosInfty || lowerRational(c) <= _rationalNegInfty
2946 	             || _feasLower[c] - lowerRational(c) == _feasUpper[c] - upperRational(c));
2947 	
2948 	      if(shifted)
2949 	      {
2950 	         if(_lowerFinite(_colTypes[c]))
2951 	         {
2952 	            shiftValue = _feasLower[c];
2953 	            shiftValue -= lowerRational(c);
2954 	         }
2955 	         else if(_upperFinite(_colTypes[c]))
2956 	         {
2957 	            shiftValue = _feasUpper[c];
2958 	            shiftValue -= upperRational(c);
2959 	         }
2960 	
2961 	         if(sol._isPrimalFeasible)
2962 	         {
2963 	            sol._primal[c] += shiftValue;
2964 	            sol._slacks.multAdd(shiftValue, _rationalLP->colVector(c));
2965 	         }
2966 	      }
2967 	
2968 	      if(_lowerFinite(_colTypes[c]))
2969 	      {
2970 	         if(shifted)
2971 	            _rationalLP->changeLower(c, _feasLower[c]);
2972 	
2973 	         _realLP->changeLower(c, R(_feasLower[c]));
2974 	      }
2975 	      else if(_realLP->lower(c) > -realParam(SoPlexBase<R>::INFTY))
2976 	         _realLP->changeLower(c, -realParam(SoPlexBase<R>::INFTY));
2977 	
2978 	      assert(_lowerFinite(_colTypes[c]) == (lowerRational(c) > -_rationalPosInfty));
2979 	      assert(_lowerFinite(_colTypes[c]) == (lowerReal(c) > -realParam(SoPlexBase<R>::INFTY)));
2980 	
2981 	      if(_upperFinite(_colTypes[c]))
2982 	      {
2983 	         if(shifted)
2984 	            _rationalLP->changeUpper(c, _feasUpper[c]);
2985 	
2986 	         _realLP->changeUpper(c, R(upperRational(c)));
2987 	      }
2988 	      else if(_realLP->upper(c) < realParam(SoPlexBase<R>::INFTY))
2989 	         _realLP->changeUpper(c, realParam(SoPlexBase<R>::INFTY));
2990 	
2991 	      assert(_upperFinite(_colTypes[c]) == (upperRational(c) < _rationalPosInfty));
2992 	      assert(_upperFinite(_colTypes[c]) == (upperReal(c) < realParam(SoPlexBase<R>::INFTY)));
2993 	
2994 	      _rationalLP->changeMaxObj(c, _feasObj[c]);
2995 	      _realLP->changeMaxObj(c, R(_feasObj[c]));
2996 	
2997 	      assert(lowerReal(c) <= upperReal(c));
2998 	   }
2999 	
3000 	   // remove last column
3001 	   _rationalLP->removeCol(numOrigCols);
3002 	   _realLP->removeCol(numOrigCols);
3003 	   _colTypes.reSize(numOrigCols);
3004 	
3005 	   // invalidate rational basis factorization
3006 	   _rationalLUSolver.clear();
3007 	
3008 	   // print LP if in debug mode
3009 	   MSG_DEBUG(_realLP->writeFileLPBase("afterUntransFeas.lp", 0, 0, 0));
3010 	
3011 	   // stop timing
3012 	   _statistics->transformTime->stop();
3013 	
3014 	#ifndef NDEBUG
3015 	
3016 	   if(sol._isPrimalFeasible)
3017 	   {
3018 	      VectorRational activity(numRowsRational());
3019 	      _rationalLP->computePrimalActivity(sol._primal, activity);
3020 	      assert(sol._slacks == activity);
3021 	   }
3022 	
3023 	#endif
3024 	}
3025 	
3026 	/** computes radius of infeasibility box implied by an approximate Farkas' proof
3027 	
3028 	 Given constraints of the form \f$ lhs <= Ax <= rhs \f$, a farkas proof y should satisfy \f$ y^T A = 0 \f$ and
3029 	 \f$ y_+^T lhs - y_-^T rhs > 0 \f$, where \f$ y_+, y_- \f$ denote the positive and negative parts of \f$ y \f$.
3030 	 If \f$ y \f$ is approximate, it may not satisfy \f$ y^T A = 0 \f$ exactly, but the proof is still valid as long
3031 	 as the following holds for all potentially feasible \f$ x \f$:
3032 	
3033 	 \f[
3034 	    y^T Ax < (y_+^T lhs - y_-^T rhs)              (*)
3035 	 \f]
3036 	
3037 	 we may therefore calculate \f$ y^T A \f$ and \f$ y_+^T lhs - y_-^T rhs \f$ exactly and check if the upper and lower
3038 	 bounds on \f$ x \f$ imply that all feasible \f$ x \f$ satisfy (*), and if not then compute bounds on \f$ x \f$ to
3039 	 guarantee (*).  The simplest way to do this is to compute
3040 	
3041 	 \f[
3042 	    B = (y_+^T lhs - y_-^T rhs) / \sum_i(|(y^T A)_i|)
3043 	 \f]
3044 	
3045 	 noting that if every component of \f$ x \f$ has \f$ |x_i| < B \f$, then (*) holds.
3046 	
3047 	 \f$ B \f$ can be increased by iteratively including variable bounds smaller than \f$ B \f$.  The speed of this
3048 	 method can be further improved by using interval arithmetic for all computations.  For related information see
3049 	 Sec. 4 of Neumaier and Shcherbina, Mathematical Programming A, 2004.
3050 	
3051 	 Set transformed to true if this method is called after _transformFeasibility().
3052 	*/
3053 	template <class R>
3054 	void SoPlexBase<R>::_computeInfeasBox(SolRational& sol, bool transformed)
3055 	{
3056 	   assert(sol.hasDualFarkas());
3057 	
3058 	   const VectorRational& lower = transformed ? _feasLower : lowerRational();
3059 	   const VectorRational& upper = transformed ? _feasUpper : upperRational();
3060 	   const VectorRational& lhs = transformed ? _feasLhs : lhsRational();
3061 	   const VectorRational& rhs = transformed ? _feasRhs : rhsRational();
3062 	   const VectorRational& y = sol._dualFarkas;
3063 	
3064 	   const int numRows = numRowsRational();
3065 	   const int numCols = transformed ? numColsRational() - 1 : numColsRational();
3066 	
3067 	   SSVectorRational ytransA(numColsRational());
3068 	   Rational ytransb;
3069 	   Rational temp;
3070 	
3071 	   // prepare ytransA and ytransb; since we want exact arithmetic, we set the zero threshold of the semi-sparse
3072 	   // vector to zero
3073 	   ytransA.setEpsilon(0);
3074 	   ytransA.clear();
3075 	   ytransb = 0;
3076 	
3077 	   ///@todo this currently works only if all constraints are equations aggregate rows and sides using the multipliers of the Farkas ray
3078 	   for(int r = 0; r < numRows; r++)
3079 	   {
3080 	      ytransA += y[r] * _rationalLP->rowVector(r);
3081 	      ytransb += y[r] * (y[r] > 0 ? lhs[r] : rhs[r]);
3082 	   }
3083 	
3084 	   // if we work on the feasibility problem, we ignore the last column
3085 	   if(transformed)
3086 	      ytransA.reDim(numCols);
3087 	
3088 	   MSG_DEBUG(std::cout << "ytransb = " << ytransb.str() << "\n");
3089 	
3090 	   // if we choose minus ytransb as vector of multipliers for the bound constraints on the variables, we obtain an
3091 	   // exactly feasible dual solution for the LP with zero objective function; we aggregate the bounds of the
3092 	   // variables accordingly and store its negation in temp
3093 	   temp = 0;
3094 	   bool isTempFinite = true;
3095 	
3096 	   for(int c = 0; c < numCols && isTempFinite; c++)
3097 	   {
3098 	      const Rational& minusRedCost = ytransA[c];
3099 	
3100 	      if(minusRedCost > 0)
3101 	      {
3102 	         assert((upper[c] < _rationalPosInfty) == _upperFinite(_colTypes[c]));
3103 	
3104 	         if(_upperFinite(_colTypes[c]))
3105 	            temp += minusRedCost * upper[c];
3106 	         else
3107 	            isTempFinite = false;
3108 	      }
3109 	      else if(minusRedCost < 0)
3110 	      {
3111 	         assert((lower[c] > _rationalNegInfty) == _lowerFinite(_colTypes[c]));
3112 	
3113 	         if(_lowerFinite(_colTypes[c]))
3114 	            temp += minusRedCost * lower[c];
3115 	         else
3116 	            isTempFinite = false;
3117 	      }
3118 	   }
3119 	
3120 	   MSG_DEBUG(std::cout << "max ytransA*[x_l,x_u] = " << (isTempFinite ? temp.str() : "infinite") <<
3121 	             "\n");
3122 	
3123 	   // ytransb - temp is the increase in the dual objective along the Farkas ray; if this is positive, the dual is
3124 	   // unbounded and certifies primal infeasibility
3125 	   if(isTempFinite && temp < ytransb)
3126 	   {
3127 	      MSG_INFO1(spxout, spxout << "Farkas infeasibility proof verified exactly. (1)\n");
3128 	      return;
3129 	   }
3130 	
3131 	   // ensure that array of nonzero elements in ytransA is available
3132 	   assert(ytransA.isSetup());
3133 	   ytransA.setup();
3134 	
3135 	   // if ytransb is negative, try to make it zero by including a positive lower bound or a negative upper bound
3136 	   if(ytransb < 0)
3137 	   {
3138 	      for(int c = 0; c < numCols; c++)
3139 	      {
3140 	         if(lower[c] > 0)
3141 	         {
3142 	            ytransA.setValue(c, ytransA[c] - ytransb / lower[c]);
3143 	            ytransb = 0;
3144 	            break;
3145 	         }
3146 	         else if(upper[c] < 0)
3147 	         {
3148 	            ytransA.setValue(c, ytransA[c] - ytransb / upper[c]);
3149 	            ytransb = 0;
3150 	            break;
3151 	         }
3152 	      }
3153 	   }
3154 	
3155 	   // if ytransb is still zero then the zero solution is inside the bounds and cannot be cut off by the Farkas
3156 	   // constraint; in this case, we cannot compute a Farkas box
3157 	   if(ytransb < 0)
3158 	   {
3159 	      MSG_INFO1(spxout, spxout <<
3160 	                "Approximate Farkas proof to weak.  Could not compute Farkas box. (1)\n");
3161 	      return;
3162 	   }
3163 	
3164 	   // compute the one norm of ytransA
3165 	   temp = 0;
3166 	   const int size = ytransA.size();
3167 	
3168 	   for(int n = 0; n < size; n++)
3169 	      temp += spxAbs(ytransA.value(n));
3170 	
3171 	   // if the one norm is zero then ytransA is zero the Farkas proof should have been verified above
3172 	   assert(temp != 0);
3173 	
3174 	   // initialize variables in loop: size of Farkas box B, flag whether B has been increased, and number of current
3175 	   // nonzero in ytransA
3176 	   Rational B = ytransb / temp;
3177 	   bool success = false;
3178 	   int n = 0;
3179 	
3180 	   // loop through nonzeros of ytransA
3181 	   MSG_DEBUG(std::cout << "B = " << B.str() << "\n");
3182 	   assert(ytransb >= 0);
3183 	
3184 	   while(true)
3185 	   {
3186 	      // if all nonzeros have been inspected once without increasing B, we abort; otherwise, we start another round
3187 	      if(n >= ytransA.size())
3188 	      {
3189 	         if(!success)
3190 	            break;
3191 	
3192 	         success = false;
3193 	         n = 0;
3194 	      }
3195 	
3196 	      // get Farkas multiplier of the bound constraint as minus the value in ytransA
3197 	      const Rational& minusRedCost = ytransA.value(n);
3198 	      int colIdx = ytransA.index(n);
3199 	
3200 	      // if the multiplier is positive we inspect the lower bound: if it is finite and within the Farkas box, we can
3201 	      // increase B by including it in the Farkas proof
3202 	      assert((upper[colIdx] < _rationalPosInfty) == _upperFinite(_colTypes[colIdx]));
3203 	      assert((lower[colIdx] > _rationalNegInfty) == _lowerFinite(_colTypes[colIdx]));
3204 	
3205 	      if(minusRedCost < 0 && lower[colIdx] > -B && _lowerFinite(_colTypes[colIdx]))
3206 	      {
3207 	         ytransA.clearNum(n);
3208 	         ytransb -= minusRedCost * lower[colIdx];
3209 	         temp += minusRedCost;
3210 	
3211 	         assert(ytransb >= 0);
3212 	         assert(temp >= 0);
3213 	         assert(temp == 0 || ytransb / temp > B);
3214 	
3215 	         // if ytransA and ytransb are zero, we have 0^T x >= 0 and cannot compute a Farkas box
3216 	         if(temp == 0 && ytransb == 0)
3217 	         {
3218 	            MSG_INFO1(spxout, spxout <<
3219 	                      "Approximate Farkas proof to weak.  Could not compute Farkas box. (2)\n");
3220 	            return;
3221 	         }
3222 	         // if ytransb is positive and ytransA is zero, we have 0^T x > 0, proving infeasibility
3223 	         else if(temp == 0)
3224 	         {
3225 	            assert(ytransb > 0);
3226 	            MSG_INFO1(spxout, spxout << "Farkas infeasibility proof verified exactly. (2)\n");
3227 	            return;
3228 	         }
3229 	         else
3230 	         {
3231 	            B = ytransb / temp;
3232 	            MSG_DEBUG(std::cout << "B = " << B.str() << "\n");
3233 	         }
3234 	
3235 	         success = true;
3236 	      }
3237 	      // if the multiplier is negative we inspect the upper bound: if it is finite and within the Farkas box, we can
3238 	      // increase B by including it in the Farkas proof
3239 	      else if(minusRedCost > 0 && upper[colIdx] < B && _upperFinite(_colTypes[colIdx]))
3240 	      {
3241 	         ytransA.clearNum(n);
3242 	         ytransb -= minusRedCost * upper[colIdx];
3243 	         temp -= minusRedCost;
3244 	
3245 	         assert(ytransb >= 0);
3246 	         assert(temp >= 0);
3247 	         assert(temp == 0 || ytransb / temp > B);
3248 	
3249 	         // if ytransA and ytransb are zero, we have 0^T x >= 0 and cannot compute a Farkas box
3250 	         if(temp == 0 && ytransb == 0)
3251 	         {
3252 	            MSG_INFO1(spxout, spxout <<
3253 	                      "Approximate Farkas proof to weak.  Could not compute Farkas box. (2)\n");
3254 	            return;
3255 	         }
3256 	         // if ytransb is positive and ytransA is zero, we have 0^T x > 0, proving infeasibility
3257 	         else if(temp == 0)
3258 	         {
3259 	            assert(ytransb > 0);
3260 	            MSG_INFO1(spxout, spxout << "Farkas infeasibility proof verified exactly. (2)\n");
3261 	            return;
3262 	         }
3263 	         else
3264 	         {
3265 	            B = ytransb / temp;
3266 	            MSG_DEBUG(std::cout << "B = " << B.str() << "\n");
3267 	         }
3268 	
3269 	         success = true;
3270 	      }
3271 	      // the multiplier is zero, we can ignore the bound constraints on this variable
3272 	      else if(minusRedCost == 0)
3273 	         ytransA.clearNum(n);
3274 	      // currently this bound cannot be used to increase B; we will check it again in the next round, because B might
3275 	      // have increased by then
3276 	      else
3277 	         n++;
3278 	   }
3279 	
3280 	   if(B > 0)
3281 	   {
3282 	      MSG_INFO1(spxout, spxout <<
3283 	                "Computed Farkas box: provably no feasible solutions with components less than "
3284 	                << B.str() << " in absolute value.\n");
3285 	   }
3286 	}
3287 	
3288 	
3289 	
3290 	
3291 	// General specializations
3292 	/// solves real LP during iterative refinement
3293 	template <class R>
3294 	typename SPxSolverBase<R>::Status SoPlexBase<R>::_solveRealForRational(bool fromscratch,
3295 	      VectorBase<R>& primal, VectorBase<R>& dual,
3296 	      DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusRows,
3297 	      DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusCols)
3298 	{
3299 	   assert(_isConsistent());
3300 	
3301 	   assert(_solver.nRows() == numRowsRational());
3302 	   assert(_solver.nCols() == numColsRational());
3303 	   assert(primal.dim() == numColsRational());
3304 	   assert(dual.dim() == numRowsRational());
3305 	
3306 	   typename SPxSolverBase<R>::Status result = SPxSolverBase<R>::UNKNOWN;
3307 	
3308 	#ifndef SOPLEX_MANUAL_ALT
3309 	
3310 	   if(fromscratch || !_hasBasis)
3311 	      _enableSimplifierAndScaler();
3312 	   else
3313 	      _disableSimplifierAndScaler();
3314 	
3315 	#else
3316 	   _disableSimplifierAndScaler();
3317 	#endif
3318 	
3319 	   // reset basis to slack basis when solving from scratch
3320 	   if(fromscratch)
3321 	      _solver.reLoad();
3322 	
3323 	   // start timing
3324 	   _statistics->syncTime->start();
3325 	
3326 	   // if preprocessing is applied, we need to restore the original LP at the end
3327 	   SPxLPRational* rationalLP = 0;
3328 	
3329 	   if(_simplifier != 0 || _scaler != nullptr)
3330 	   {
3331 	      spx_alloc(rationalLP);
3332 	      rationalLP = new(rationalLP) SPxLPRational(_solver);
3333 	   }
3334 	
3335 	   // with preprocessing or solving from scratch, the basis may change, hence invalidate the
3336 	   // rational basis factorization
3337 	   if(_simplifier != nullptr || _scaler != nullptr || fromscratch)
3338 	      _rationalLUSolver.clear();
3339 	
3340 	   // stop timing
3341 	   _statistics->syncTime->stop();
3342 	
3343 	   try
3344 	   {
3345 	      // apply problem simplification
3346 	      typename SPxSimplifier<R>::Result simplificationStatus = SPxSimplifier<R>::OKAY;
3347 	
3348 	      if(_simplifier != 0)
3349 	      {
3350 	         // do not remove bounds of boxed variables or sides of ranged rows if bound flipping is used
3351 	         bool keepbounds = intParam(SoPlexBase<R>::RATIOTESTER) == SoPlexBase<R>::RATIOTESTER_BOUNDFLIPPING;
3352 	         Real remainingTime = _solver.getMaxTime() - _solver.time();
3353 	         simplificationStatus = _simplifier->simplify(_solver, realParam(SoPlexBase<R>::EPSILON_ZERO),
3354 	                                realParam(SoPlexBase<R>::FPFEASTOL), realParam(SoPlexBase<R>::FPOPTTOL), remainingTime, keepbounds,
3355 	                                _solver.random.getSeed());
3356 	      }
3357 	
3358 	      // apply scaling after the simplification
3359 	      if(_scaler != nullptr && simplificationStatus == SPxSimplifier<R>::OKAY)
3360 	         _scaler->scale(_solver, false);
3361 	
3362 	      // run the simplex method if problem has not been solved by the simplifier
3363 	      if(simplificationStatus == SPxSimplifier<R>::OKAY)
3364 	      {
3365 	         MSG_INFO1(spxout, spxout << std::endl);
3366 	
3367 	         _solveRealLPAndRecordStatistics();
3368 	
3369 	         MSG_INFO1(spxout, spxout << std::endl);
3370 	      }
3371 	
3372 	      ///@todo move to private helper methods
3373 	      // evaluate status flag
3374 	      if(simplificationStatus == SPxSimplifier<R>::INFEASIBLE)
3375 	         result = SPxSolverBase<R>::INFEASIBLE;
3376 	      else if(simplificationStatus == SPxSimplifier<R>::DUAL_INFEASIBLE)
3377 	         result = SPxSolverBase<R>::INForUNBD;
3378 	      else if(simplificationStatus == SPxSimplifier<R>::UNBOUNDED)
3379 	         result = SPxSolverBase<R>::UNBOUNDED;
3380 	      else if(simplificationStatus == SPxSimplifier<R>::VANISHED
3381 	              || simplificationStatus == SPxSimplifier<R>::OKAY)
3382 	      {
3383 	         result = simplificationStatus == SPxSimplifier<R>::VANISHED ? SPxSolverBase<R>::OPTIMAL :
3384 	                  _solver.status();
3385 	
3386 	         ///@todo move to private helper methods
3387 	         // process result
(1) Event switch_selector_expr_is_constant: selector expression is constant
(2) Event caretline: ^
Also see events: [template_instantiation_context][template_instantiation_context][template_instantiation_context][template_instantiation_context]
3388 	         switch(result)
3389 	         {
3390 	         case SPxSolverBase<R>::OPTIMAL:
3391 	
3392 	            // unsimplify if simplifier is active and LP is solved to optimality; this must be done here and not at solution
3393 	            // query, because we want to have the basis for the original problem
3394 	            if(_simplifier != 0)
3395 	            {
3396 	               assert(!_simplifier->isUnsimplified());
3397 	               assert(simplificationStatus == SPxSimplifier<R>::VANISHED
3398 	                      || simplificationStatus == SPxSimplifier<R>::OKAY);
3399 	
3400 	               bool vanished = simplificationStatus == SPxSimplifier<R>::VANISHED;
3401 	
3402 	               // get solution vectors for transformed problem
3403 	               VectorBase<R> tmpPrimal(vanished ? 0 : _solver.nCols());
3404 	               VectorBase<R> tmpSlacks(vanished ? 0 : _solver.nRows());
3405 	               VectorBase<R> tmpDual(vanished ? 0 : _solver.nRows());
3406 	               VectorBase<R> tmpRedCost(vanished ? 0 : _solver.nCols());
3407 	
3408 	               if(!vanished)
3409 	               {
3410 	                  assert(_solver.status() == SPxSolverBase<R>::OPTIMAL);
3411 	
3412 	                  _solver.getPrimalSol(tmpPrimal);
3413 	                  _solver.getSlacks(tmpSlacks);
3414 	                  _solver.getDualSol(tmpDual);
3415 	                  _solver.getRedCostSol(tmpRedCost);
3416 	
3417 	                  // unscale vectors
3418 	                  if(_scaler != nullptr)
3419 	                  {
3420 	                     _scaler->unscalePrimal(_solver, tmpPrimal);
3421 	                     _scaler->unscaleSlacks(_solver, tmpSlacks);
3422 	                     _scaler->unscaleDual(_solver, tmpDual);
3423 	                     _scaler->unscaleRedCost(_solver, tmpRedCost);
3424 	                  }
3425 	
3426 	                  // get basis of transformed problem
3427 	                  basisStatusRows.reSize(_solver.nRows());
3428 	                  basisStatusCols.reSize(_solver.nCols());
3429 	                  _solver.getBasis(basisStatusRows.get_ptr(), basisStatusCols.get_ptr(), basisStatusRows.size(),
3430 	                                   basisStatusCols.size());
3431 	               }
3432 	
3433 	               ///@todo catch exception
3434 	               _simplifier->unsimplify(tmpPrimal, tmpDual, tmpSlacks, tmpRedCost, basisStatusRows.get_ptr(),
3435 	                                       basisStatusCols.get_ptr());
3436 	
3437 	               // store basis for original problem
3438 	               basisStatusRows.reSize(numRowsRational());
3439 	               basisStatusCols.reSize(numColsRational());
3440 	               _simplifier->getBasis(basisStatusRows.get_ptr(), basisStatusCols.get_ptr(), basisStatusRows.size(),
3441 	                                     basisStatusCols.size());
3442 	               _hasBasis = true;
3443 	
3444 	               primal = _simplifier->unsimplifiedPrimal();
3445 	               dual = _simplifier->unsimplifiedDual();
3446 	            }
3447 	            else
3448 	            {
3449 	               _solver.getPrimalSol(primal);
3450 	               _solver.getDualSol(dual);
3451 	
3452 	               // unscale vectors
3453 	               if(_scaler != nullptr)
3454 	               {
3455 	                  _scaler->unscalePrimal(_solver, primal);
3456 	                  _scaler->unscaleDual(_solver, dual);
3457 	               }
3458 	
3459 	               // get basis of transformed problem
3460 	               basisStatusRows.reSize(_solver.nRows());
3461 	               basisStatusCols.reSize(_solver.nCols());
3462 	               _solver.getBasis(basisStatusRows.get_ptr(), basisStatusCols.get_ptr(), basisStatusRows.size(),
3463 	                                basisStatusCols.size());
3464 	               _hasBasis = true;
3465 	            }
3466 	
3467 	            break;
3468 	
3469 	         case SPxSolverBase<R>::ABORT_CYCLING:
3470 	            if(_simplifier == 0 && boolParam(SoPlexBase<R>::ACCEPTCYCLING))
3471 	            {
3472 	               _solver.getPrimalSol(primal);
3473 	               _solver.getDualSol(dual);
3474 	
3475 	               // unscale vectors
3476 	               if(_scaler != nullptr)
3477 	               {
3478 	                  _scaler->unscalePrimal(_solver, primal);
3479 	                  _scaler->unscaleDual(_solver, dual);
3480 	               }
3481 	            }
3482 	
3483 	         // intentional fallthrough
3484 	         case SPxSolverBase<R>::ABORT_TIME:
3485 	         case SPxSolverBase<R>::ABORT_ITER:
3486 	         case SPxSolverBase<R>::ABORT_VALUE:
3487 	         case SPxSolverBase<R>::REGULAR:
3488 	         case SPxSolverBase<R>::RUNNING:
3489 	         case SPxSolverBase<R>::UNBOUNDED:
3490 	            _hasBasis = (_solver.basis().status() > SPxBasisBase<R>::NO_PROBLEM);
3491 	
3492 	            if(_hasBasis && _simplifier == 0)
3493 	            {
3494 	               basisStatusRows.reSize(_solver.nRows());
3495 	               basisStatusCols.reSize(_solver.nCols());
3496 	               _solver.getBasis(basisStatusRows.get_ptr(), basisStatusCols.get_ptr(), basisStatusRows.size(),
3497 	                                basisStatusCols.size());
3498 	            }
3499 	            else
3500 	            {
3501 	               _hasBasis = false;
3502 	               _rationalLUSolver.clear();
3503 	            }
3504 	
3505 	            break;
3506 	
3507 	         case SPxSolverBase<R>::INFEASIBLE:
3508 	
3509 	            // if simplifier is active we can currently not return a Farkas ray or basis
3510 	            if(_simplifier != 0)
3511 	            {
3512 	               _hasBasis = false;
3513 	               _rationalLUSolver.clear();
3514 	               break;
3515 	            }
3516 	
3517 	            // return Farkas ray as dual solution
3518 	            _solver.getDualfarkas(dual);
3519 	
3520 	            // unscale vectors
3521 	            if(_scaler != nullptr)
3522 	               _scaler->unscaleDual(_solver, dual);
3523 	
3524 	            // get basis of transformed problem
3525 	            basisStatusRows.reSize(_solver.nRows());
3526 	            basisStatusCols.reSize(_solver.nCols());
3527 	            _solver.getBasis(basisStatusRows.get_ptr(), basisStatusCols.get_ptr(), basisStatusRows.size(),
3528 	                             basisStatusCols.size());
3529 	            _hasBasis = true;
3530 	            break;
3531 	
3532 	         case SPxSolverBase<R>::INForUNBD:
3533 	         case SPxSolverBase<R>::SINGULAR:
3534 	         default:
3535 	            _hasBasis = false;
3536 	            _rationalLUSolver.clear();
3537 	            break;
3538 	         }
3539 	      }
3540 	   }
3541 	   catch(...)
3542 	   {
3543 	      MSG_INFO1(spxout, spxout << "Exception thrown during floating-point solve.\n");
3544 	      result = SPxSolverBase<R>::ERROR;
3545 	      _hasBasis = false;
3546 	      _rationalLUSolver.clear();
3547 	
3548 	   }
3549 	
3550 	   // restore original LP if necessary
3551 	   if(_simplifier != 0 || _scaler != nullptr)
3552 	   {
3553 	      assert(rationalLP != 0);
3554 	      _solver.loadLP((SPxLPBase<R>)(*rationalLP));
3555 	      rationalLP->~SPxLPRational();
3556 	      spx_free(rationalLP);
3557 	
3558 	      if(_hasBasis)
3559 	         _solver.setBasis(basisStatusRows.get_ptr(), basisStatusCols.get_ptr());
3560 	   }
3561 	
3562 	   return result;
3563 	}
3564 	
3565 	/// solves real LP with recovery mechanism
3566 	template <class R>
3567 	typename SPxSolverBase<R>::Status SoPlexBase<R>::_solveRealStable(bool acceptUnbounded,
3568 	      bool acceptInfeasible, VectorBase<R>& primal, VectorBase<R>& dual,
3569 	      DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusRows,
3570 	      DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusCols,
3571 	      const bool forceNoSimplifier)
3572 	{
3573 	   typename SPxSolverBase<R>::Status result = SPxSolverBase<R>::UNKNOWN;
3574 	
3575 	   bool fromScratch = false;
3576 	   bool solved = false;
3577 	   bool solvedFromScratch = false;
3578 	   bool initialSolve = true;
3579 	   bool increasedMarkowitz = false;
3580 	   bool relaxedTolerances = false;
3581 	   bool tightenedTolerances = false;
3582 	   bool switchedScaler = false;
3583 	   bool switchedSimplifier = false;
3584 	   bool switchedRatiotester = false;
3585 	   bool switchedPricer = false;
3586 	   bool turnedoffPre = false;
3587 	
3588 	   R markowitz = _slufactor.markowitz();
3589 	   int ratiotester = intParam(SoPlexBase<R>::RATIOTESTER);
3590 	   int pricer = intParam(SoPlexBase<R>::PRICER);
3591 	   int simplifier = intParam(SoPlexBase<R>::SIMPLIFIER);
3592 	   int scaler = intParam(SoPlexBase<R>::SCALER);
3593 	   int type = intParam(SoPlexBase<R>::ALGORITHM);
3594 	
3595 	   if(forceNoSimplifier)
3596 	      setIntParam(SoPlexBase<R>::SIMPLIFIER, SoPlexBase<R>::SIMPLIFIER_OFF);
3597 	
3598 	   while(true)
3599 	   {
3600 	      assert(!increasedMarkowitz || GE(_slufactor.markowitz(), R(0.9)));
3601 	
3602 	      result = _solveRealForRational(fromScratch, primal, dual, basisStatusRows, basisStatusCols);
3603 	
3604 	      solved = (result == SPxSolverBase<R>::OPTIMAL)
3605 	               || (result == SPxSolverBase<R>::INFEASIBLE && acceptInfeasible)
3606 	               || (result == SPxSolverBase<R>::UNBOUNDED && acceptUnbounded);
3607 	
3608 	      if(solved || result == SPxSolverBase<R>::ABORT_TIME || result == SPxSolverBase<R>::ABORT_ITER)
3609 	         break;
3610 	
3611 	      if(initialSolve)
3612 	      {
3613 	         MSG_INFO1(spxout, spxout << "Numerical troubles during floating-point solve." << std::endl);
3614 	         initialSolve = false;
3615 	      }
3616 	
3617 	      if(!turnedoffPre
3618 	            && (intParam(SoPlexBase<R>::SIMPLIFIER) != SoPlexBase<R>::SIMPLIFIER_OFF
3619 	                || intParam(SoPlexBase<R>::SCALER) != SoPlexBase<R>::SCALER_OFF))
3620 	      {
3621 	         MSG_INFO1(spxout, spxout << "Turning off preprocessing." << std::endl);
3622 	
3623 	         turnedoffPre = true;
3624 	
3625 	         setIntParam(SoPlexBase<R>::SCALER, SoPlexBase<R>::SCALER_OFF);
3626 	         setIntParam(SoPlexBase<R>::SIMPLIFIER, SoPlexBase<R>::SIMPLIFIER_OFF);
3627 	
3628 	         fromScratch = true;
3629 	         solvedFromScratch = true;
3630 	         continue;
3631 	      }
3632 	
3633 	      setIntParam(SoPlexBase<R>::SCALER, scaler);
3634 	      setIntParam(SoPlexBase<R>::SIMPLIFIER, simplifier);
3635 	
3636 	      if(!increasedMarkowitz)
3637 	      {
3638 	         MSG_INFO1(spxout, spxout << "Increasing Markowitz threshold." << std::endl);
3639 	
3640 	         _slufactor.setMarkowitz(0.9);
3641 	         increasedMarkowitz = true;
3642 	
3643 	         try
3644 	         {
3645 	            _solver.factorize();
3646 	            continue;
3647 	         }
3648 	         catch(...)
3649 	         {
3650 	            MSG_DEBUG(std::cout << std::endl << "Factorization failed." << std::endl);
3651 	         }
3652 	      }
3653 	
3654 	      if(!solvedFromScratch)
3655 	      {
3656 	         MSG_INFO1(spxout, spxout << "Solving from scratch." << std::endl);
3657 	
3658 	         fromScratch = true;
3659 	         solvedFromScratch = true;
3660 	         continue;
3661 	      }
3662 	
3663 	      setIntParam(SoPlexBase<R>::RATIOTESTER, ratiotester);
3664 	      setIntParam(SoPlexBase<R>::PRICER, pricer);
3665 	
3666 	      if(!switchedScaler)
3667 	      {
3668 	         MSG_INFO1(spxout, spxout << "Switching scaling." << std::endl);
3669 	
3670 	         if(scaler == int(SoPlexBase<R>::SCALER_OFF))
3671 	            setIntParam(SoPlexBase<R>::SCALER, SoPlexBase<R>::SCALER_BIEQUI);
3672 	         else
3673 	            setIntParam(SoPlexBase<R>::SCALER, SoPlexBase<R>::SCALER_OFF);
3674 	
3675 	         fromScratch = true;
3676 	         solvedFromScratch = true;
3677 	         switchedScaler = true;
3678 	         continue;
3679 	      }
3680 	
3681 	      if(!switchedSimplifier && !forceNoSimplifier)
3682 	      {
3683 	         MSG_INFO1(spxout, spxout << "Switching simplification." << std::endl);
3684 	
3685 	         if(simplifier == int(SoPlexBase<R>::SIMPLIFIER_OFF))
3686 	            setIntParam(SoPlexBase<R>::SIMPLIFIER, SoPlexBase<R>::SIMPLIFIER_INTERNAL);
3687 	         else
3688 	            setIntParam(SoPlexBase<R>::SIMPLIFIER, SoPlexBase<R>::SIMPLIFIER_OFF);
3689 	
3690 	         fromScratch = true;
3691 	         solvedFromScratch = true;
3692 	         switchedSimplifier = true;
3693 	         continue;
3694 	      }
3695 	
3696 	      setIntParam(SoPlexBase<R>::SIMPLIFIER, SoPlexBase<R>::SIMPLIFIER_OFF);
3697 	
3698 	      if(!relaxedTolerances)
3699 	      {
3700 	         MSG_INFO1(spxout, spxout << "Relaxing tolerances." << std::endl);
3701 	
3702 	         setIntParam(SoPlexBase<R>::ALGORITHM, SoPlexBase<R>::ALGORITHM_PRIMAL);
3703 	         _solver.setDelta((_solver.feastol() * 1e3 > 1e-3) ? 1e-3 : (_solver.feastol() * 1e3));
3704 	         relaxedTolerances = _solver.feastol() >= 1e-3;
3705 	         solvedFromScratch = false;
3706 	         continue;
3707 	      }
3708 	
3709 	      if(!tightenedTolerances && result != SPxSolverBase<R>::INFEASIBLE)
3710 	      {
3711 	         MSG_INFO1(spxout, spxout << "Tightening tolerances." << std::endl);
3712 	
3713 	         setIntParam(SoPlexBase<R>::ALGORITHM, SoPlexBase<R>::ALGORITHM_DUAL);
3714 	         _solver.setDelta(_solver.feastol() * 1e-3 < 1e-9 ? 1e-9 : _solver.feastol() * 1e-3);
3715 	         tightenedTolerances = _solver.feastol() <= 1e-9;
3716 	         solvedFromScratch = false;
3717 	         continue;
3718 	      }
3719 	
3720 	      setIntParam(SoPlexBase<R>::ALGORITHM, type);
3721 	
3722 	      if(!switchedRatiotester)
3723 	      {
3724 	         MSG_INFO1(spxout, spxout << "Switching ratio test." << std::endl);
3725 	
3726 	         _solver.setType(_solver.type() == SPxSolverBase<R>::LEAVE ? SPxSolverBase<R>::ENTER :
3727 	                         SPxSolverBase<R>::LEAVE);
3728 	
3729 	         if(_solver.ratiotester() != (SPxRatioTester<R>*)&_ratiotesterTextbook)
3730 	            setIntParam(SoPlexBase<R>::RATIOTESTER, RATIOTESTER_TEXTBOOK);
3731 	         else
3732 	            setIntParam(SoPlexBase<R>::RATIOTESTER, RATIOTESTER_FAST);
3733 	
3734 	         switchedRatiotester = true;
3735 	         solvedFromScratch = false;
3736 	         continue;
3737 	      }
3738 	
3739 	      if(!switchedPricer)
3740 	      {
3741 	         MSG_INFO1(spxout, spxout << "Switching pricer." << std::endl);
3742 	
3743 	         _solver.setType(_solver.type() == SPxSolverBase<R>::LEAVE ? SPxSolverBase<R>::ENTER :
3744 	                         SPxSolverBase<R>::LEAVE);
3745 	
3746 	         if(_solver.pricer() != (SPxPricer<R>*)&_pricerDevex)
3747 	            setIntParam(SoPlexBase<R>::PRICER, PRICER_DEVEX);
3748 	         else
3749 	            setIntParam(SoPlexBase<R>::PRICER, PRICER_STEEP);
3750 	
3751 	         switchedPricer = true;
3752 	         solvedFromScratch = false;
3753 	         continue;
3754 	      }
3755 	
3756 	      MSG_INFO1(spxout, spxout << "Giving up." << std::endl);
3757 	
3758 	      break;
3759 	   }
3760 	
3761 	   _solver.setFeastol(realParam(SoPlexBase<R>::FPFEASTOL));
3762 	   _solver.setOpttol(realParam(SoPlexBase<R>::FPOPTTOL));
3763 	   _slufactor.setMarkowitz(markowitz);
3764 	
3765 	   setIntParam(SoPlexBase<R>::RATIOTESTER, ratiotester);
3766 	   setIntParam(SoPlexBase<R>::PRICER, pricer);
3767 	   setIntParam(SoPlexBase<R>::SIMPLIFIER, simplifier);
3768 	   setIntParam(SoPlexBase<R>::SCALER, scaler);
3769 	   setIntParam(SoPlexBase<R>::ALGORITHM, type);
3770 	
3771 	   return result;
3772 	}
3773 	
3774 	/// computes rational inverse of basis matrix as defined by _rationalLUSolverBind
3775 	template <class R>
3776 	void SoPlexBase<R>::_computeBasisInverseRational()
3777 	{
3778 	   assert(_rationalLUSolver.status() == SLinSolverRational::UNLOADED
3779 	          || _rationalLUSolver.status() == SLinSolverRational::TIME);
3780 	
3781 	   const int matrixdim = numRowsRational();
3782 	   assert(_rationalLUSolverBind.size() == matrixdim);
3783 	
3784 	   Array< const SVectorRational* > matrix(matrixdim);
3785 	   _rationalLUSolverBind.reSize(matrixdim);
3786 	
3787 	   for(int i = 0; i < matrixdim; i++)
3788 	   {
3789 	      if(_rationalLUSolverBind[i] >= 0)
3790 	      {
3791 	         assert(_rationalLUSolverBind[i] < numColsRational());
3792 	         matrix[i] = &colVectorRational(_rationalLUSolverBind[i]);
3793 	      }
3794 	      else
3795 	      {
3796 	         assert(-1 - _rationalLUSolverBind[i] >= 0);
3797 	         assert(-1 - _rationalLUSolverBind[i] < numRowsRational());
3798 	         matrix[i] = _unitVectorRational(-1 - _rationalLUSolverBind[i]);
3799 	      }
3800 	   }
3801 	
3802 	   // load and factorize rational basis matrix
3803 	   if(realParam(SoPlexBase<R>::TIMELIMIT) < realParam(SoPlexBase<R>::INFTY))
3804 	      _rationalLUSolver.setTimeLimit((double)realParam(SoPlexBase<R>::TIMELIMIT) -
3805 	                                     _statistics->solvingTime->time());
3806 	   else
3807 	      _rationalLUSolver.setTimeLimit(-1.0);
3808 	
3809 	   _rationalLUSolver.load(matrix.get_ptr(), matrixdim);
3810 	
3811 	   // record statistics
3812 	   _statistics->luFactorizationTimeRational += _rationalLUSolver.getFactorTime();
3813 	   _statistics->luFactorizationsRational += _rationalLUSolver.getFactorCount();
3814 	   _rationalLUSolver.resetCounters();
3815 	
3816 	   if(_rationalLUSolver.status() == SLinSolverRational::TIME)
3817 	   {
3818 	      MSG_INFO2(spxout, spxout << "Rational factorization hit time limit.\n");
3819 	   }
3820 	   else if(_rationalLUSolver.status() != SLinSolverRational::OK)
3821 	   {
3822 	      MSG_INFO1(spxout, spxout << "Error performing rational LU factorization.\n");
3823 	   }
3824 	
3825 	   return;
3826 	}
3827 	
3828 	
3829 	
3830 	/// factorizes rational basis matrix in column representation
3831 	template <class R>
3832 	void SoPlexBase<R>::_factorizeColumnRational(SolRational& sol,
3833 	      DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusRows,
3834 	      DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusCols, bool& stoppedTime,
3835 	      bool& stoppedIter, bool& error, bool& optimal)
3836 	{
3837 	   // start rational solving time
3838 	   _statistics->rationalTime->start();
3839 	
3840 	   stoppedTime = false;
3841 	   stoppedIter = false;
3842 	   error = false;
3843 	   optimal = false;
3844 	
3845 	   const bool maximizing = (intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MAXIMIZE);
3846 	   const int matrixdim = numRowsRational();
3847 	   bool loadMatrix = (_rationalLUSolver.status() == SLinSolverRational::UNLOADED
3848 	                      || _rationalLUSolver.status() == SLinSolverRational::TIME);
3849 	   int numBasicRows;
3850 	
3851 	   assert(loadMatrix || matrixdim == _rationalLUSolver.dim());
3852 	   assert(loadMatrix || matrixdim == _rationalLUSolverBind.size());
3853 	
3854 	   if(!loadMatrix && (matrixdim != _rationalLUSolver.dim()
3855 	                      || matrixdim != _rationalLUSolverBind.size()))
3856 	   {
3857 	      MSG_WARNING(spxout, spxout <<
3858 	                  "Warning: dimensioning error in rational matrix factorization (recovered).\n");
3859 	      loadMatrix = true;
3860 	   }
3861 	
3862 	   _workSol._primal.reDim(matrixdim);
3863 	   _workSol._slacks.reDim(matrixdim);
3864 	   _workSol._dual.reDim(matrixdim);
3865 	   _workSol._redCost.reDim(numColsRational() > matrixdim ? numColsRational() : matrixdim);
3866 	
3867 	   if(loadMatrix)
3868 	      _rationalLUSolverBind.reSize(matrixdim);
3869 	
3870 	   VectorRational& basicPrimalRhs = _workSol._slacks;
3871 	   VectorRational& basicDualRhs = _workSol._redCost;
3872 	   VectorRational& basicPrimal = _workSol._primal;
3873 	   VectorRational& basicDual = _workSol._dual;
3874 	
3875 	   Rational violation;
3876 	   Rational primalViolation;
3877 	   Rational dualViolation;
3878 	   bool primalFeasible = false;
3879 	   bool dualFeasible = false;
3880 	
3881 	   assert(basisStatusCols.size() == numColsRational());
3882 	   assert(basisStatusRows.size() == numRowsRational());
3883 	
3884 	   int j = 0;
3885 	
3886 	   for(int i = 0; i < basisStatusRows.size(); i++)
3887 	   {
3888 	      if(basisStatusRows[i] == SPxSolverBase<R>::BASIC && j < matrixdim)
3889 	      {
3890 	         basicPrimalRhs[i] = 0;
3891 	         basicDualRhs[j] = 0;
3892 	
3893 	         if(loadMatrix)
3894 	            _rationalLUSolverBind[j] = -1 - i;
3895 	
3896 	         j++;
3897 	      }
3898 	      else if(basisStatusRows[i] == SPxSolverBase<R>::ON_LOWER)
3899 	         basicPrimalRhs[i] = lhsRational(i);
3900 	      else if(basisStatusRows[i] == SPxSolverBase<R>::ON_UPPER)
3901 	         basicPrimalRhs[i] = rhsRational(i);
3902 	      else if(basisStatusRows[i] == SPxSolverBase<R>::ZERO)
3903 	         basicPrimalRhs[i] = 0;
3904 	      else if(basisStatusRows[i] == SPxSolverBase<R>::FIXED)
3905 	      {
3906 	         assert(lhsRational(i) == rhsRational(i));
3907 	         basicPrimalRhs[i] = lhsRational(i);
3908 	      }
3909 	      else if(basisStatusRows[i] == SPxSolverBase<R>::UNDEFINED)
3910 	      {
3911 	         MSG_INFO1(spxout, spxout << "Undefined basis status of row in rational factorization.\n");
3912 	         error = true;
3913 	         goto TERMINATE;
3914 	      }
3915 	      else
3916 	      {
3917 	         assert(basisStatusRows[i] == SPxSolverBase<R>::BASIC);
3918 	         MSG_INFO1(spxout, spxout << "Too many basic rows in rational factorization.\n");
3919 	         error = true;
3920 	         goto TERMINATE;
3921 	      }
3922 	   }
3923 	
3924 	   numBasicRows = j;
3925 	
3926 	   for(int i = 0; i < basisStatusCols.size(); i++)
3927 	   {
3928 	      if(basisStatusCols[i] == SPxSolverBase<R>::BASIC && j < matrixdim)
3929 	      {
3930 	         basicDualRhs[j] = objRational(i);
3931 	
3932 	         if(loadMatrix)
3933 	            _rationalLUSolverBind[j] = i;
3934 	
3935 	         j++;
3936 	      }
3937 	      else if(basisStatusCols[i] == SPxSolverBase<R>::ON_LOWER)
3938 	         basicPrimalRhs.multAdd(-lowerRational(i), colVectorRational(i));
3939 	      else if(basisStatusCols[i] == SPxSolverBase<R>::ON_UPPER)
3940 	         basicPrimalRhs.multAdd(-upperRational(i), colVectorRational(i));
3941 	      else if(basisStatusCols[i] == SPxSolverBase<R>::ZERO)
3942 	      {}
3943 	      else if(basisStatusCols[i] == SPxSolverBase<R>::FIXED)
3944 	      {
3945 	         assert(lowerRational(i) == upperRational(i));
3946 	         basicPrimalRhs.multAdd(-lowerRational(i), colVectorRational(i));
3947 	      }
3948 	      else if(basisStatusCols[i] == SPxSolverBase<R>::UNDEFINED)
3949 	      {
3950 	         MSG_INFO1(spxout, spxout << "Undefined basis status of column in rational factorization.\n");
3951 	         error = true;
3952 	         goto TERMINATE;
3953 	      }
3954 	      else
3955 	      {
3956 	         assert(basisStatusCols[i] == SPxSolverBase<R>::BASIC);
3957 	         MSG_INFO1(spxout, spxout << "Too many basic columns in rational factorization.\n");
3958 	         error = true;
3959 	         goto TERMINATE;
3960 	      }
3961 	   }
3962 	
3963 	   if(j != matrixdim)
3964 	   {
3965 	      MSG_INFO1(spxout, spxout << "Too few basic entries in rational factorization.\n");
3966 	      error = true;
3967 	      goto TERMINATE;
3968 	   }
3969 	
3970 	   // load and factorize rational basis matrix
3971 	   if(loadMatrix)
3972 	      _computeBasisInverseRational();
3973 	
3974 	   if(_rationalLUSolver.status() == SLinSolverRational::TIME)
3975 	   {
3976 	      stoppedTime = true;
3977 	      return;
3978 	   }
3979 	   else if(_rationalLUSolver.status() != SLinSolverRational::OK)
3980 	   {
3981 	      error = true;
3982 	      return;
3983 	   }
3984 	
3985 	   assert(_rationalLUSolver.status() == SLinSolverRational::OK);
3986 	
3987 	   // solve for primal solution
3988 	   if(realParam(SoPlexBase<R>::TIMELIMIT) < realParam(SoPlexBase<R>::INFTY))
3989 	      _rationalLUSolver.setTimeLimit(Real(realParam(SoPlexBase<R>::TIMELIMIT)) -
3990 	                                     _statistics->solvingTime->time());
3991 	   else
3992 	      _rationalLUSolver.setTimeLimit(-1.0);
3993 	
3994 	   _rationalLUSolver.solveRight(basicPrimal, basicPrimalRhs);
3995 	
3996 	   // record statistics
3997 	   _statistics->luSolveTimeRational += _rationalLUSolver.getSolveTime();
3998 	   _rationalLUSolver.resetCounters();
3999 	
4000 	   if(_isSolveStopped(stoppedTime, stoppedIter))
4001 	   {
4002 	      MSG_INFO2(spxout, spxout << "Rational factorization hit time limit while solving for primal.\n");
4003 	      return;
4004 	   }
4005 	
4006 	   // check bound violation on basic rows and columns
4007 	   j = 0;
4008 	   primalViolation = 0;
4009 	   primalFeasible = true;
4010 	
4011 	   for(int i = 0; i < basisStatusRows.size(); i++)
4012 	   {
4013 	      if(basisStatusRows[i] == SPxSolverBase<R>::BASIC)
4014 	      {
4015 	         assert(j < matrixdim);
4016 	         assert(_rationalLUSolverBind[j] == -1 - i);
4017 	         violation = lhsRational(i);
4018 	         violation += basicPrimal[j];
4019 	
4020 	         if(violation > primalViolation)
4021 	         {
4022 	            primalFeasible = false;
4023 	            primalViolation = violation;
4024 	         }
4025 	
4026 	         violation = rhsRational(i);
4027 	         violation += basicPrimal[j];
4028 	         violation *= -1;
4029 	
4030 	         if(violation > primalViolation)
4031 	         {
4032 	            primalFeasible = false;
4033 	            primalViolation = violation;
4034 	         }
4035 	
4036 	         j++;
4037 	      }
4038 	   }
4039 	
4040 	   for(int i = 0; i < basisStatusCols.size(); i++)
4041 	   {
4042 	      if(basisStatusCols[i] == SPxSolverBase<R>::BASIC)
4043 	      {
4044 	         assert(j < matrixdim);
4045 	         assert(_rationalLUSolverBind[j] == i);
4046 	
4047 	         if(basicPrimal[j] < lowerRational(i))
4048 	         {
4049 	            violation = lowerRational(i);
4050 	            violation -= basicPrimal[j];
4051 	
4052 	            if(violation > primalViolation)
4053 	            {
4054 	               primalFeasible = false;
4055 	               primalViolation = violation;
4056 	            }
4057 	         }
4058 	
4059 	         if(basicPrimal[j] > upperRational(i))
4060 	         {
4061 	            violation = basicPrimal[j];
4062 	            violation -= upperRational(i);
4063 	
4064 	            if(violation > primalViolation)
4065 	            {
4066 	               primalFeasible = false;
4067 	               primalViolation = violation;
4068 	            }
4069 	         }
4070 	
4071 	         j++;
4072 	      }
4073 	   }
4074 	
4075 	   if(!primalFeasible)
4076 	   {
4077 	      MSG_INFO1(spxout, spxout << "Rational solution primal infeasible.\n");
4078 	   }
4079 	
4080 	   // solve for dual solution
4081 	   if(realParam(SoPlexBase<R>::TIMELIMIT) < realParam(SoPlexBase<R>::INFTY))
4082 	      _rationalLUSolver.setTimeLimit(Real(realParam(SoPlexBase<R>::TIMELIMIT)) -
4083 	                                     _statistics->solvingTime->time());
4084 	   else
4085 	      _rationalLUSolver.setTimeLimit(-1.0);
4086 	
4087 	   _rationalLUSolver.solveLeft(basicDual, basicDualRhs);
4088 	
4089 	   // record statistics
4090 	   _statistics->luSolveTimeRational += _rationalLUSolver.getSolveTime();
4091 	   _rationalLUSolver.resetCounters();
4092 	
4093 	   if(_isSolveStopped(stoppedTime, stoppedIter))
4094 	   {
4095 	      MSG_INFO2(spxout, spxout << "Rational factorization hit time limit while solving for dual.\n");
4096 	      return;
4097 	   }
4098 	
4099 	   // check dual violation on nonbasic rows
4100 	   dualViolation = 0;
4101 	   dualFeasible = true;
4102 	
4103 	   for(int i = 0; i < basisStatusRows.size(); i++)
4104 	   {
4105 	      if(_rowTypes[i] == RANGETYPE_FIXED
4106 	            && (basisStatusRows[i] == SPxSolverBase<R>::ON_LOWER
4107 	                || basisStatusRows[i] == SPxSolverBase<R>::ON_UPPER))
4108 	      {
4109 	         assert(lhsRational(i) == rhsRational(i));
4110 	         basisStatusRows[i] = SPxSolverBase<R>::FIXED;
4111 	      }
4112 	
4113 	      assert(basisStatusRows[i] != SPxSolverBase<R>::BASIC || basicDual[i] == 0);
4114 	
4115 	      if(basisStatusRows[i] == SPxSolverBase<R>::BASIC || basisStatusRows[i] == SPxSolverBase<R>::FIXED)
4116 	         continue;
4117 	      else if(basicDual[i] < 0)
4118 	      {
4119 	         if(((maximizing && basisStatusRows[i] != SPxSolverBase<R>::ON_LOWER) || (!maximizing
4120 	               && basisStatusRows[i] != SPxSolverBase<R>::ON_UPPER))
4121 	               && (basisStatusRows[i] != SPxSolverBase<R>::ZERO || rhsRational(i) != 0))
4122 	         {
4123 	            dualFeasible = false;
4124 	            violation = -basicDual[i];
4125 	
4126 	            if(violation > dualViolation)
4127 	               dualViolation = violation;
4128 	
4129 	            MSG_DEBUG(spxout << "negative dual multliplier for row " << i
4130 	                      << " with dual " << basicDual[i].str()
4131 	                      << " and status " << basisStatusRows[i]
4132 	                      << " and [lhs,rhs] = [" << lhsRational(i).str() << "," << rhsRational(i).str() << "]"
4133 	                      << "\n");
4134 	         }
4135 	      }
4136 	      else if(basicDual[i] > 0)
4137 	      {
4138 	         if(((maximizing && basisStatusRows[i] != SPxSolverBase<R>::ON_UPPER) || (!maximizing
4139 	               && basisStatusRows[i] != SPxSolverBase<R>::ON_LOWER))
4140 	               && (basisStatusRows[i] != SPxSolverBase<R>::ZERO || lhsRational(i) == 0))
4141 	         {
4142 	            dualFeasible = false;
4143 	
4144 	            if(basicDual[i] > dualViolation)
4145 	               dualViolation = basicDual[i];
4146 	
4147 	            MSG_DEBUG(spxout << "positive dual multliplier for row " << i
4148 	                      << " with dual " << basicDual[i].str()
4149 	                      << " and status " << basisStatusRows[i]
4150 	                      << " and [lhs,rhs] = [" << lhsRational(i).str() << "," << rhsRational(i).str() << "]"
4151 	                      << "\n");
4152 	         }
4153 	      }
4154 	   }
4155 	
4156 	   // check reduced cost violation on nonbasic columns
4157 	   for(int i = 0; i < basisStatusCols.size(); i++)
4158 	   {
4159 	      if(_colTypes[i] == RANGETYPE_FIXED
4160 	            && (basisStatusCols[i] == SPxSolverBase<R>::ON_LOWER
4161 	                || basisStatusCols[i] == SPxSolverBase<R>::ON_UPPER))
4162 	      {
4163 	         assert(lowerRational(i) == upperRational(i));
4164 	         basisStatusCols[i] = SPxSolverBase<R>::FIXED;
4165 	      }
4166 	
4167 	      assert(basisStatusCols[i] != SPxSolverBase<R>::BASIC
4168 	             || basicDual * colVectorRational(i) == objRational(i));
4169 	
4170 	      if(basisStatusCols[i] == SPxSolverBase<R>::BASIC || basisStatusCols[i] == SPxSolverBase<R>::FIXED)
4171 	         continue;
4172 	      else
4173 	      {
4174 	         _workSol._redCost[i] = basicDual * colVectorRational(i);
4175 	         _workSol._redCost[i] -= objRational(i);
4176 	
4177 	         if(_workSol._redCost[i] > 0)
4178 	         {
4179 	            if(((maximizing && basisStatusCols[i] != SPxSolverBase<R>::ON_LOWER) || (!maximizing
4180 	                  && basisStatusCols[i] != SPxSolverBase<R>::ON_UPPER))
4181 	                  && (basisStatusCols[i] != SPxSolverBase<R>::ZERO || upperRational(i) != 0))
4182 	            {
4183 	               dualFeasible = false;
4184 	
4185 	               if(_workSol._redCost[i] > dualViolation)
4186 	                  dualViolation = _workSol._redCost[i];
4187 	            }
4188 	
4189 	            _workSol._redCost[i] *= -1;
4190 	         }
4191 	         else if(_workSol._redCost[i] < 0)
4192 	         {
4193 	            _workSol._redCost[i] *= -1;
4194 	
4195 	            if(((maximizing && basisStatusCols[i] != SPxSolverBase<R>::ON_UPPER) || (!maximizing
4196 	                  && basisStatusCols[i] != SPxSolverBase<R>::ON_LOWER))
4197 	                  && (basisStatusCols[i] != SPxSolverBase<R>::ZERO || lowerRational(i) != 0))
4198 	            {
4199 	               dualFeasible = false;
4200 	
4201 	               if(_workSol._redCost[i] > dualViolation)
4202 	                  dualViolation = _workSol._redCost[i];
4203 	            }
4204 	         }
4205 	         else
4206 	            _workSol._redCost[i] *= -1;
4207 	      }
4208 	   }
4209 	
4210 	   if(!dualFeasible)
4211 	   {
4212 	      MSG_INFO1(spxout, spxout << "Rational solution dual infeasible.\n");
4213 	   }
4214 	
4215 	   // store solution
4216 	   optimal = primalFeasible && dualFeasible;
4217 	
4218 	   if(optimal || boolParam(SoPlexBase<R>::RATFACJUMP))
4219 	   {
4220 	      _hasBasis = true;
4221 	
4222 	      if(&basisStatusRows != &_basisStatusRows)
4223 	         _basisStatusRows = basisStatusRows;
4224 	
4225 	      if(&basisStatusCols != &_basisStatusCols)
4226 	         _basisStatusCols = basisStatusCols;
4227 	
4228 	      sol._primal.reDim(numColsRational());
4229 	      j = numBasicRows;
4230 	
4231 	      for(int i = 0; i < basisStatusCols.size(); i++)
4232 	      {
4233 	         if(basisStatusCols[i] == SPxSolverBase<R>::BASIC)
4234 	         {
4235 	            assert(j < matrixdim);
4236 	            assert(_rationalLUSolverBind[j] == i);
4237 	            sol._primal[i] = basicPrimal[j];
4238 	            j++;
4239 	         }
4240 	         else if(basisStatusCols[i] == SPxSolverBase<R>::ON_LOWER)
4241 	            sol._primal[i] = lowerRational(i);
4242 	         else if(basisStatusCols[i] == SPxSolverBase<R>::ON_UPPER)
4243 	            sol._primal[i] = upperRational(i);
4244 	         else if(basisStatusCols[i] == SPxSolverBase<R>::ZERO)
4245 	            sol._primal[i] = 0;
4246 	         else if(basisStatusCols[i] == SPxSolverBase<R>::FIXED)
4247 	         {
4248 	            assert(lowerRational(i) == upperRational(i));
4249 	            sol._primal[i] = lowerRational(i);
4250 	         }
4251 	         else
4252 	         {
4253 	            assert(basisStatusCols[i] == SPxSolverBase<R>::UNDEFINED);
4254 	            MSG_INFO1(spxout, spxout << "Undefined basis status of column in rational factorization.\n");
4255 	            error = true;
4256 	            goto TERMINATE;
4257 	         }
4258 	      }
4259 	
4260 	      sol._slacks.reDim(numRowsRational());
4261 	      _rationalLP->computePrimalActivity(sol._primal, sol._slacks);
4262 	      sol._isPrimalFeasible = true;
4263 	
4264 	      sol._dual = basicDual;
4265 	
4266 	      for(int i = 0; i < numColsRational(); i++)
4267 	      {
4268 	         if(basisStatusCols[i] == SPxSolverBase<R>::BASIC)
4269 	            sol._redCost[i] = 0;
4270 	         else if(basisStatusCols[i] == SPxSolverBase<R>::FIXED)
4271 	         {
4272 	            sol._redCost[i] = basicDual * colVectorRational(i);
4273 	            sol._redCost[i] -= objRational(i);
4274 	            sol._redCost[i] *= -1;
4275 	         }
4276 	         else
4277 	            sol._redCost[i] = _workSol._redCost[i];
4278 	      }
4279 	
4280 	      sol._isDualFeasible  = true;
4281 	   }
4282 	   else
4283 	   {
4284 	      _rationalLUSolver.clear();
4285 	   }
4286 	
4287 	
4288 	TERMINATE:
4289 	   // stop rational solving time
4290 	   _statistics->rationalTime->stop();
4291 	   return;
4292 	}
4293 	
4294 	/// attempts rational reconstruction of primal-dual solution
4295 	template <class R>
4296 	bool SoPlexBase<R>::_reconstructSolutionRational(SolRational& sol,
4297 	      DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusRows,
4298 	      DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusCols,
4299 	      const Rational& denomBoundSquared)
4300 	{
4301 	   bool success;
4302 	   bool isSolBasic;
4303 	   DIdxSet basicIndices(numColsRational());
4304 	
4305 	   success = false;
4306 	   isSolBasic = true;
4307 	
4308 	   if(!sol.isPrimalFeasible() || !sol.isDualFeasible())
4309 	      return success;
4310 	
4311 	   // start timing and increment statistics counter
4312 	   _statistics->reconstructionTime->start();
4313 	   _statistics->rationalReconstructions++;
4314 	
4315 	   // reconstruct primal vector
4316 	   _workSol._primal = sol._primal;
4317 	
4318 	   for(int j = 0; j < numColsRational(); ++j)
4319 	   {
4320 	      if(basisStatusCols[j] == SPxSolverBase<R>::BASIC)
4321 	         basicIndices.addIdx(j);
4322 	   }
4323 	
4324 	   success = reconstructVector(_workSol._primal, denomBoundSquared, &basicIndices);
4325 	
4326 	   if(!success)
4327 	   {
4328 	      MSG_INFO1(spxout, spxout << "Rational reconstruction of primal solution failed.\n");
4329 	      _statistics->reconstructionTime->stop();
4330 	      return success;
4331 	   }
4332 	
4333 	   MSG_DEBUG(spxout << "Rational reconstruction of primal solution successful.\n");
4334 	
4335 	   // check violation of bounds
4336 	   for(int c = numColsRational() - 1; c >= 0; c--)
4337 	   {
4338 	      // we want to notify the user whether the reconstructed solution is basic; otherwise, this would be redundant
4339 	      typename SPxSolverBase<R>::VarStatus& basisStatusCol = _basisStatusCols[c];
4340 	
4341 	      if((basisStatusCol == SPxSolverBase<R>::FIXED && _workSol._primal[c] != lowerRational(c))
4342 	            || (basisStatusCol == SPxSolverBase<R>::ON_LOWER && _workSol._primal[c] != lowerRational(c))
4343 	            || (basisStatusCol == SPxSolverBase<R>::ON_UPPER && _workSol._primal[c] != upperRational(c))
4344 	            || (basisStatusCol == SPxSolverBase<R>::ZERO && _workSol._primal[c] != 0)
4345 	            || (basisStatusCol == SPxSolverBase<R>::UNDEFINED))
4346 	      {
4347 	         isSolBasic = false;
4348 	      }
4349 	
4350 	      if(_lowerFinite(_colTypes[c]) && _workSol._primal[c] < lowerRational(c))
4351 	      {
4352 	         MSG_DEBUG(std::cout << "Lower bound of variable " << c << " violated by " <<
4353 	                   (lowerRational(c) - _workSol._primal[c]).str() << "\n");
4354 	         MSG_INFO1(spxout, spxout << "Reconstructed solution primal infeasible (1).\n");
4355 	         _statistics->reconstructionTime->stop();
4356 	         return false;
4357 	      }
4358 	
4359 	      if(_upperFinite(_colTypes[c]) && _workSol._primal[c] > upperRational(c))
4360 	      {
4361 	         MSG_DEBUG(std::cout << "Upper bound of variable " << c << " violated by " <<
4362 	                   (_workSol._primal[c] - upperRational(c)).str() << "\n");
4363 	         MSG_INFO1(spxout, spxout << "Reconstructed solution primal infeasible (2).\n");
4364 	         _statistics->reconstructionTime->stop();
4365 	         return false;
4366 	      }
4367 	   }
4368 	
4369 	   // compute slacks
4370 	   ///@todo we should compute them one by one so we can abort when encountering an infeasibility
4371 	   _workSol._slacks.reDim(numRowsRational());
4372 	   _rationalLP->computePrimalActivity(_workSol._primal, _workSol._slacks);
4373 	
4374 	   // check violation of sides
4375 	   for(int r = numRowsRational() - 1; r >= 0; r--)
4376 	   {
4377 	      // we want to notify the user whether the reconstructed solution is basic; otherwise, this would be redundant
4378 	      typename SPxSolverBase<R>::VarStatus& basisStatusRow = _basisStatusRows[r];
4379 	
4380 	      if((basisStatusRow == SPxSolverBase<R>::FIXED && _workSol._slacks[r] != lhsRational(r))
4381 	            || (basisStatusRow == SPxSolverBase<R>::ON_LOWER && _workSol._slacks[r] != lhsRational(r))
4382 	            || (basisStatusRow == SPxSolverBase<R>::ON_UPPER && _workSol._slacks[r] != rhsRational(r))
4383 	            || (basisStatusRow == SPxSolverBase<R>::ZERO && _workSol._slacks[r] != 0)
4384 	            || (basisStatusRow == SPxSolverBase<R>::UNDEFINED))
4385 	      {
4386 	         isSolBasic = false;
4387 	      }
4388 	
4389 	      if(_lowerFinite(_rowTypes[r]) && _workSol._slacks[r] < lhsRational(r))
4390 	      {
4391 	         MSG_DEBUG(std::cout << "Lhs of row " << r << " violated by " <<
4392 	                   (lhsRational(r) - _workSol._slacks[r]).str() << "\n");
4393 	         MSG_INFO1(spxout, spxout << "Reconstructed solution primal infeasible (3).\n");
4394 	         _statistics->reconstructionTime->stop();
4395 	         return false;
4396 	      }
4397 	
4398 	      if(_upperFinite(_rowTypes[r]) && _workSol._slacks[r] > rhsRational(r))
4399 	      {
4400 	         MSG_DEBUG(std::cout << "Rhs of row " << r << " violated by " <<
4401 	                   (_workSol._slacks[r] - rhsRational(r)) << "\n");
4402 	         MSG_INFO1(spxout, spxout << "Reconstructed solution primal infeasible (4).\n");
4403 	         _statistics->reconstructionTime->stop();
4404 	         return false;
4405 	      }
4406 	   }
4407 	
4408 	   // reconstruct dual vector
4409 	   _workSol._dual = sol._dual;
4410 	
4411 	   success = reconstructVector(_workSol._dual, denomBoundSquared);
4412 	
4413 	   if(!success)
4414 	   {
4415 	      MSG_INFO1(spxout, spxout << "Rational reconstruction of dual solution failed.\n");
4416 	      _statistics->reconstructionTime->stop();
4417 	      return success;
4418 	   }
4419 	
4420 	   MSG_DEBUG(spxout << "Rational reconstruction of dual vector successful.\n");
4421 	
4422 	   // check dual multipliers before reduced costs because this check is faster since it does not require the
4423 	   // computation of reduced costs
4424 	   const bool maximizing = (intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MAXIMIZE);
4425 	
4426 	   for(int r = numRowsRational() - 1; r >= 0; r--)
4427 	   {
4428 	      int sig = sign(_workSol._dual[r]);
4429 	
4430 	      if((!maximizing && sig > 0) || (maximizing && sig < 0))
4431 	      {
4432 	         if(!_lowerFinite(_rowTypes[r]) || _workSol._slacks[r] > lhsRational(r))
4433 	         {
4434 	            MSG_DEBUG(std::cout << "complementary slackness violated by row " << r
4435 	                      << " with dual " << _workSol._dual[r].str()
4436 	                      << " and slack " << _workSol._slacks[r].str()
4437 	                      << " not at lhs " << lhsRational(r).str()
4438 	                      << "\n");
4439 	            MSG_INFO1(spxout, spxout << "Reconstructed solution dual infeasible (1).\n");
4440 	            _statistics->reconstructionTime->stop();
4441 	            return false;
4442 	         }
4443 	
4444 	         if(_basisStatusRows[r] != SPxSolverBase<R>::ON_LOWER
4445 	               && _basisStatusRows[r] != SPxSolverBase<R>::FIXED)
4446 	         {
4447 	            if(_basisStatusRows[r] == SPxSolverBase<R>::BASIC
4448 	                  || _basisStatusRows[r] == SPxSolverBase<R>::UNDEFINED)
4449 	               isSolBasic = false;
4450 	            else
4451 	               _basisStatusRows[r] = SPxSolverBase<R>::ON_LOWER;
4452 	         }
4453 	      }
4454 	      else if((!maximizing && sig < 0) || (maximizing && sig > 0))
4455 	      {
4456 	         if(!_upperFinite(_rowTypes[r]) || _workSol._slacks[r] < rhsRational(r))
4457 	         {
4458 	            MSG_DEBUG(std::cout << "complementary slackness violated by row " << r
4459 	                      << " with dual " << _workSol._dual[r].str()
4460 	                      << " and slack " << _workSol._slacks[r].str()
4461 	                      << " not at rhs " << rhsRational(r).str()
4462 	                      << "\n");
4463 	            MSG_INFO1(spxout, spxout << "Reconstructed solution dual infeasible (2).\n");
4464 	            _statistics->reconstructionTime->stop();
4465 	            return false;
4466 	         }
4467 	
4468 	         if(_basisStatusRows[r] != SPxSolverBase<R>::ON_UPPER
4469 	               && _basisStatusRows[r] != SPxSolverBase<R>::FIXED)
4470 	         {
4471 	            if(_basisStatusRows[r] == SPxSolverBase<R>::BASIC
4472 	                  || _basisStatusRows[r] == SPxSolverBase<R>::UNDEFINED)
4473 	               isSolBasic = false;
4474 	            else
4475 	               _basisStatusRows[r] = SPxSolverBase<R>::ON_UPPER;
4476 	         }
4477 	      }
4478 	   }
4479 	
4480 	   // compute reduced cost vector; we assume that the objective function vector has less nonzeros than the reduced
4481 	   // cost vector, and so multiplying with -1 first and subtracting the dual activity should be faster than adding
4482 	   // the dual activity and negating afterwards
4483 	   ///@todo we should compute them one by one so we can abort when encountering an infeasibility
4484 	   _workSol._redCost.reDim(numColsRational());
4485 	   _rationalLP->getObj(_workSol._redCost);
4486 	   _rationalLP->subDualActivity(_workSol._dual, _workSol._redCost);
4487 	
4488 	   // check reduced cost violation
4489 	   for(int c = numColsRational() - 1; c >= 0; c--)
4490 	   {
4491 	      int sig = sign(_workSol._redCost[c]);
4492 	
4493 	      if((!maximizing && sig > 0) || (maximizing && sig < 0))
4494 	      {
4495 	         if(!_lowerFinite(_colTypes[c]) || _workSol._primal[c] > lowerRational(c))
4496 	         {
4497 	            MSG_DEBUG(std::cout << "complementary slackness violated by column " << c
4498 	                      << " with reduced cost " << _workSol._redCost[c].str()
4499 	                      << " and value " << _workSol._primal[c].str()
4500 	                      << " not at lower bound " << lowerRational(c).str()
4501 	                      << "\n");
4502 	            MSG_INFO1(spxout, spxout << "Reconstructed solution dual infeasible (3).\n");
4503 	            _statistics->reconstructionTime->stop();
4504 	            return false;
4505 	         }
4506 	
4507 	         if(_basisStatusCols[c] != SPxSolverBase<R>::ON_LOWER
4508 	               && _basisStatusCols[c] != SPxSolverBase<R>::FIXED)
4509 	         {
4510 	            if(_basisStatusCols[c] == SPxSolverBase<R>::BASIC
4511 	                  || _basisStatusCols[c] == SPxSolverBase<R>::UNDEFINED)
4512 	               isSolBasic = false;
4513 	            else
4514 	               _basisStatusCols[c] = SPxSolverBase<R>::ON_LOWER;
4515 	         }
4516 	      }
4517 	      else if((!maximizing && sig < 0) || (maximizing && sig > 0))
4518 	      {
4519 	         if(!_upperFinite(_colTypes[c]) || _workSol._primal[c] < upperRational(c))
4520 	         {
4521 	            MSG_DEBUG(std::cout << "complementary slackness violated by column " << c
4522 	                      << " with reduced cost " << _workSol._redCost[c].str()
4523 	                      << " and value " << _workSol._primal[c].str()
4524 	                      << " not at upper bound " << upperRational(c).str()
4525 	                      << "\n");
4526 	            MSG_INFO1(spxout, spxout << "Reconstructed solution dual infeasible (4).\n");
4527 	            _statistics->reconstructionTime->stop();
4528 	            return false;
4529 	         }
4530 	
4531 	         if(_basisStatusCols[c] != SPxSolverBase<R>::ON_UPPER
4532 	               && _basisStatusCols[c] != SPxSolverBase<R>::FIXED)
4533 	         {
4534 	            if(_basisStatusCols[c] == SPxSolverBase<R>::BASIC
4535 	                  || _basisStatusCols[c] == SPxSolverBase<R>::UNDEFINED)
4536 	               isSolBasic = false;
4537 	            else
4538 	               _basisStatusCols[c] = SPxSolverBase<R>::ON_UPPER;
4539 	         }
4540 	      }
4541 	   }
4542 	
4543 	   // update solution
4544 	   sol._primal = _workSol._primal;
4545 	   sol._slacks = _workSol._slacks;
4546 	   sol._dual = _workSol._dual;
4547 	   sol._redCost = _workSol._redCost;
4548 	
4549 	   if(!isSolBasic)
4550 	   {
4551 	      MSG_WARNING(spxout, spxout << "Warning: Reconstructed solution not basic.\n");
4552 	      _hasBasis = false;
4553 	   }
4554 	
4555 	   // stop timing
4556 	   _statistics->reconstructionTime->stop();
4557 	
4558 	   return success;
4559 	}
4560 	} // namespace soplex
4561