#include <iostream>
#include <assert.h>
#include "soplex.h"
#include "soplex/statistics.h"
#include "soplex/slufactor_rational.h"
#include "soplex/ratrecon.h"
namespace soplex
{
template <class R>
void SoPlexBase<R>::_optimizeRational(volatile bool* interrupt)
{
#ifndef SOPLEX_WITH_BOOST
MSG_ERROR(std::cerr << "ERROR: rational solve without Boost not defined!" << std::endl;)
return;
#else
bool hasUnboundedRay = false;
bool infeasibilityNotCertified = false;
bool unboundednessNotCertified = false;
_statistics->solvingTime->start();
_statistics->preprocessingTime->start();
_lastSolveMode = SOLVEMODE_RATIONAL;
if(!_isRealLPLoaded)
{
assert(_realLP != &_solver);
_solver.loadLP(*_realLP);
spx_free(_realLP);
_realLP = &_solver;
_isRealLPLoaded = true;
}
else if(_hasBasis)
{
_basisStatusRows.reSize(numRows());
_basisStatusCols.reSize(numCols());
_solver.getBasis(_basisStatusRows.get_ptr(), _basisStatusCols.get_ptr(), _basisStatusRows.size(),
_basisStatusCols.size());
}
_storeLPReal();
if(realParam(SoPlexBase<R>::OBJLIMIT_LOWER) > -realParam(SoPlexBase<R>::INFTY)
|| realParam(SoPlexBase<R>::OBJLIMIT_UPPER) < realParam(SoPlexBase<R>::INFTY))
{
MSG_INFO2(spxout, spxout << "Deactivating objective limit.\n");
}
_solver.setTerminationValue(realParam(SoPlexBase<R>::INFTY));
_statistics->preprocessingTime->stop();
if(boolParam(SoPlexBase<R>::LIFTING))
_lift();
int oldRepresentation = intParam(SoPlexBase<R>::REPRESENTATION);
setIntParam(SoPlexBase<R>::REPRESENTATION, SoPlexBase<R>::REPRESENTATION_COLUMN);
int oldRatiotester = intParam(SoPlexBase<R>::RATIOTESTER);
setIntParam(SoPlexBase<R>::RATIOTESTER, SoPlexBase<R>::RATIOTESTER_FAST);
#ifdef SOPLEX_WITH_CPX
int oldEqtrans = boolParam(SoPlexBase<R>::EQTRANS);
setBoolParam(SoPlexBase<R>::EQTRANS, true);
#endif
if(boolParam(SoPlexBase<R>::EQTRANS))
_transformEquality();
_storedBasis = false;
bool stoppedTime;
bool stoppedIter;
do
{
bool primalFeasible = false;
bool dualFeasible = false;
bool infeasible = false;
bool unbounded = false;
bool error = false;
stoppedTime = false;
stoppedIter = false;
_performOptIRStable(_solRational, !unboundednessNotCertified, !infeasibilityNotCertified, 0,
primalFeasible, dualFeasible, infeasible, unbounded, stoppedTime, stoppedIter, error);
if(error)
{
_status = SPxSolverBase<R>::ERROR;
break;
}
else if(stoppedTime)
{
_status = SPxSolverBase<R>::ABORT_TIME;
break;
}
else if(stoppedIter)
{
_status = SPxSolverBase<R>::ABORT_ITER;
break;
}
else if(unbounded && !unboundednessNotCertified)
{
SolRational solUnbounded;
_performUnboundedIRStable(solUnbounded, hasUnboundedRay, stoppedTime, stoppedIter, error);
assert(!hasUnboundedRay || solUnbounded.hasPrimalRay());
assert(!solUnbounded.hasPrimalRay() || hasUnboundedRay);
if(error)
{
MSG_INFO1(spxout, spxout << "Error while testing for unboundedness.\n");
_status = SPxSolverBase<R>::ERROR;
break;
}
if(hasUnboundedRay)
{
MSG_INFO1(spxout, spxout << "Dual infeasible. Primal unbounded ray available.\n");
}
else
{
MSG_INFO1(spxout, spxout << "Dual feasible. Rejecting primal unboundedness.\n");
}
unboundednessNotCertified = !hasUnboundedRay;
if(stoppedTime)
{
_status = SPxSolverBase<R>::ABORT_TIME;
break;
}
else if(stoppedIter)
{
_status = SPxSolverBase<R>::ABORT_ITER;
break;
}
_performFeasIRStable(_solRational, infeasible, stoppedTime, stoppedIter, error);
if(hasUnboundedRay)
{
_solRational._primalRay = solUnbounded._primalRay;
_solRational._hasPrimalRay = true;
}
if(error)
{
MSG_INFO1(spxout, spxout << "Error while testing for feasibility.\n");
_status = SPxSolverBase<R>::ERROR;
break;
}
else if(stoppedTime)
{
_status = SPxSolverBase<R>::ABORT_TIME;
break;
}
else if(stoppedIter)
{
_status = SPxSolverBase<R>::ABORT_ITER;
break;
}
else if(infeasible)
{
MSG_INFO1(spxout, spxout << "Primal infeasible. Dual Farkas ray available.\n");
_status = SPxSolverBase<R>::INFEASIBLE;
break;
}
else if(hasUnboundedRay)
{
MSG_INFO1(spxout, spxout << "Primal feasible and unbounded.\n");
_status = SPxSolverBase<R>::UNBOUNDED;
break;
}
else
{
MSG_INFO1(spxout, spxout << "Primal feasible and bounded.\n");
continue;
}
}
else if(infeasible && !infeasibilityNotCertified)
{
_storeBasis();
_performFeasIRStable(_solRational, infeasible, stoppedTime, stoppedIter, error);
if(error)
{
MSG_INFO1(spxout, spxout << "Error while testing for infeasibility.\n");
_status = SPxSolverBase<R>::ERROR;
_restoreBasis();
break;
}
infeasibilityNotCertified = !infeasible;
if(stoppedTime)
{
_status = SPxSolverBase<R>::ABORT_TIME;
_restoreBasis();
break;
}
else if(stoppedIter)
{
_status = SPxSolverBase<R>::ABORT_ITER;
_restoreBasis();
break;
}
if(infeasible && boolParam(SoPlexBase<R>::TESTDUALINF))
{
SolRational solUnbounded;
_performUnboundedIRStable(solUnbounded, hasUnboundedRay, stoppedTime, stoppedIter, error);
assert(!hasUnboundedRay || solUnbounded.hasPrimalRay());
assert(!solUnbounded.hasPrimalRay() || hasUnboundedRay);
if(error)
{
MSG_INFO1(spxout, spxout << "Error while testing for dual infeasibility.\n");
_status = SPxSolverBase<R>::ERROR;
_restoreBasis();
break;
}
if(hasUnboundedRay)
{
MSG_INFO1(spxout, spxout << "Dual infeasible. Primal unbounded ray available.\n");
_solRational._primalRay = solUnbounded._primalRay;
_solRational._hasPrimalRay = true;
}
else if(solUnbounded._isDualFeasible)
{
MSG_INFO1(spxout, spxout << "Dual feasible. Storing dual multipliers.\n");
_solRational._dual = solUnbounded._dual;
_solRational._redCost = solUnbounded._redCost;
_solRational._isDualFeasible = true;
}
else
{
assert(false);
MSG_INFO1(spxout, spxout << "Not dual infeasible.\n");
}
}
_restoreBasis();
if(infeasible)
{
MSG_INFO1(spxout, spxout << "Primal infeasible. Dual Farkas ray available.\n");
_status = SPxSolverBase<R>::INFEASIBLE;
break;
}
else if(hasUnboundedRay)
{
MSG_INFO1(spxout, spxout << "Primal feasible and unbounded.\n");
_status = SPxSolverBase<R>::UNBOUNDED;
break;
}
else
{
MSG_INFO1(spxout, spxout << "Primal feasible. Optimizing again.\n");
continue;
}
}
else if(primalFeasible && dualFeasible)
{
MSG_INFO1(spxout, spxout << "Solved to optimality.\n");
_status = SPxSolverBase<R>::OPTIMAL;
break;
}
else
{
MSG_INFO1(spxout, spxout << "Terminating without success.\n");
break;
}
}
while(!_isSolveStopped(stoppedTime, stoppedIter));
if(_status == SPxSolverBase<R>::OPTIMAL || _status == SPxSolverBase<R>::INFEASIBLE
|| _status == SPxSolverBase<R>::UNBOUNDED)
_hasSolRational = true;
if(boolParam(SoPlexBase<R>::EQTRANS))
_untransformEquality(_solRational);
#ifdef SOPLEX_WITH_CPX
setBoolParam(SoPlexBase<R>::EQTRANS, oldEqtrans);
#endif
setIntParam(SoPlexBase<R>::REPRESENTATION, oldRepresentation);
setIntParam(SoPlexBase<R>::RATIOTESTER, oldRatiotester);
if(boolParam(SoPlexBase<R>::LIFTING))
_project(_solRational);
_restoreLPReal();
if(_hasBasis)
{
assert(_isRealLPLoaded);
_solver.setBasis(_basisStatusRows.get_const_ptr(), _basisStatusCols.get_const_ptr());
_hasBasis = (_solver.basis().status() > SPxBasisBase<R>::NO_PROBLEM);
switch(_status)
{
case SPxSolverBase<R>::OPTIMAL:
_solver.setBasisStatus(SPxBasisBase<R>::OPTIMAL);
break;
case SPxSolverBase<R>::INFEASIBLE:
_solver.setBasisStatus(SPxBasisBase<R>::INFEASIBLE);
break;
case SPxSolverBase<R>::UNBOUNDED:
_solver.setBasisStatus(SPxBasisBase<R>::UNBOUNDED);
break;
default:
break;
}
}
_statistics->solvingTime->stop();
#endif
}
template <class R>
void SoPlexBase<R>::_performOptIRStable(
SolRational& sol,
bool acceptUnbounded,
bool acceptInfeasible,
int minRounds,
bool& primalFeasible,
bool& dualFeasible,
bool& infeasible,
bool& unbounded,
bool& stoppedTime,
bool& stoppedIter,
bool& error)
{
_statistics->rationalTime->start();
primalFeasible = false;
dualFeasible = false;
infeasible = false;
unbounded = false;
stoppedTime = false;
stoppedIter = false;
error = false;
_solver.setFeastol(realParam(SoPlexBase<R>::FPFEASTOL));
_solver.setOpttol(realParam(SoPlexBase<R>::FPOPTTOL));
typename SPxSolverBase<R>::Status result = SPxSolverBase<R>::UNKNOWN;
_modLower.reDim(numColsRational(), false);
_modUpper.reDim(numColsRational(), false);
_modLhs.reDim(numRowsRational(), false);
_modRhs.reDim(numRowsRational(), false);
_modObj.reDim(numColsRational(), false);
VectorBase<R> primalReal(numColsRational());
VectorBase<R> dualReal(numRowsRational());
Rational boundsViolation;
Rational sideViolation;
Rational redCostViolation;
Rational dualViolation;
Rational primalScale;
Rational dualScale;
Rational maxScale;
MSG_INFO1(spxout, spxout << "Initial floating-point solve . . .\n");
if(_hasBasis)
{
assert(_basisStatusRows.size() == numRowsRational());
assert(_basisStatusCols.size() == numColsRational());
_solver.setBasis(_basisStatusRows.get_const_ptr(), _basisStatusCols.get_const_ptr());
_hasBasis = (_solver.basis().status() > SPxBasisBase<R>::NO_PROBLEM);
}
for(int r = numRowsRational() - 1; r >= 0; r--)
{
assert(_solver.maxRowObj(r) == 0.0);
}
_statistics->rationalTime->stop();
result = _solveRealStable(acceptUnbounded, acceptInfeasible, primalReal, dualReal, _basisStatusRows,
_basisStatusCols);
switch(result)
{
case SPxSolverBase<R>::OPTIMAL:
MSG_INFO1(spxout, spxout << "Floating-point optimal.\n");
break;
case SPxSolverBase<R>::INFEASIBLE:
MSG_INFO1(spxout, spxout << "Floating-point infeasible.\n");
if(_hasBasis)
{
sol._dualFarkas = dualReal;
sol._hasDualFarkas = true;
}
else
sol._hasDualFarkas = false;
infeasible = true;
return;
case SPxSolverBase<R>::UNBOUNDED:
MSG_INFO1(spxout, spxout << "Floating-point unbounded.\n");
unbounded = true;
return;
case SPxSolverBase<R>::ABORT_TIME:
stoppedTime = true;
return;
case SPxSolverBase<R>::ABORT_ITER:
stoppedIter = true;
return;
default:
error = true;
return;
}
_statistics->rationalTime->start();
sol._primal.reDim(numColsRational(), false);
sol._slacks.reDim(numRowsRational(), false);
sol._dual.reDim(numRowsRational(), false);
sol._redCost.reDim(numColsRational(), false);
sol._isPrimalFeasible = true;
sol._isDualFeasible = true;
for(int c = numColsRational() - 1; c >= 0; c--)
{
typename SPxSolverBase<R>::VarStatus& basisStatusCol = _basisStatusCols[c];
if(basisStatusCol == SPxSolverBase<R>::ON_LOWER)
sol._primal[c] = lowerRational(c);
else if(basisStatusCol == SPxSolverBase<R>::ON_UPPER)
sol._primal[c] = upperRational(c);
else if(basisStatusCol == SPxSolverBase<R>::FIXED)
{
sol._primal[c] = lowerRational(c);
basisStatusCol = SPxSolverBase<R>::ON_LOWER;
}
else if(basisStatusCol == SPxSolverBase<R>::ZERO)
sol._primal[c] = 0;
else
sol._primal[c].assign(primalReal[c]);
}
_rationalLP->computePrimalActivity(sol._primal, sol._slacks);
int dualSize = 0;
for(int r = numRowsRational() - 1; r >= 0; r--)
{
typename SPxSolverBase<R>::VarStatus& basisStatusRow = _basisStatusRows[r];
if(basisStatusRow == SPxSolverBase<R>::FIXED)
basisStatusRow = SPxSolverBase<R>::ON_LOWER;
{
sol._dual[r].assign(dualReal[r]);
if(dualReal[r] != 0.0)
dualSize++;
}
}
_rationalLP->getObj(sol._redCost);
_rationalLP->subDualActivity(sol._dual, sol._redCost);
primalScale = _rationalPosone;
dualScale = _rationalPosone;
Rational maxViolation;
Rational bestViolation = _rationalPosInfty;
const Rational violationImprovementFactor = 16;
const Rational errorCorrectionFactor = 1.1;
Rational errorCorrection = 2;
int numFailedRefinements = 0;
DataArray< typename SPxSolverBase<R>::VarStatus > basisStatusRowsFirst;
DataArray< typename SPxSolverBase<R>::VarStatus > basisStatusColsFirst;
const bool maximizing = (intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MAXIMIZE);
const int maxDimRational = numColsRational() > numRowsRational() ? numColsRational() :
numRowsRational();
SolRational factorSol;
bool factorSolNewBasis = true;
int lastStallRefinements = 0;
int nextRatrecRefinement = 0;
do
{
minRounds--;
MSG_DEBUG(std::cout << "Computing primal violations.\n");
boundsViolation = 0;
for(int c = numColsRational() - 1; c >= 0; c--)
{
assert((lowerRational(c) > _rationalNegInfty) == _lowerFinite(_colTypes[c]));
if(_lowerFinite(_colTypes[c]))
{
if(lowerRational(c) == 0)
{
_modLower[c] = sol._primal[c];
_modLower[c] *= -1;
if(_modLower[c] > boundsViolation)
boundsViolation = _modLower[c];
}
else
{
_modLower[c] = lowerRational(c);
_modLower[c] -= sol._primal[c];
if(_modLower[c] > boundsViolation)
boundsViolation = _modLower[c];
}
}
assert((upperRational(c) < _rationalPosInfty) == _upperFinite(_colTypes[c]));
if(_upperFinite(_colTypes[c]))
{
if(upperRational(c) == 0)
{
_modUpper[c] = sol._primal[c];
_modUpper[c] *= -1;
if(_modUpper[c] < -boundsViolation)
boundsViolation = -_modUpper[c];
}
else
{
_modUpper[c] = upperRational(c);
_modUpper[c] -= sol._primal[c];
if(_modUpper[c] < -boundsViolation)
boundsViolation = -_modUpper[c];
}
}
}
sideViolation = 0;
for(int r = numRowsRational() - 1; r >= 0; r--)
{
const typename SPxSolverBase<R>::VarStatus& basisStatusRow = _basisStatusRows[r];
assert((lhsRational(r) > _rationalNegInfty) == _lowerFinite(_rowTypes[r]));
if(_lowerFinite(_rowTypes[r]))
{
if(lhsRational(r) == 0)
{
_modLhs[r] = sol._slacks[r];
_modLhs[r] *= -1;
}
else
{
_modLhs[r] = lhsRational(r);
_modLhs[r] -= sol._slacks[r];
}
if(_modLhs[r] > sideViolation)
sideViolation = _modLhs[r];
else if(basisStatusRow == SPxSolverBase<R>::ON_LOWER && _modLhs[r] < -sideViolation)
sideViolation = -_modLhs[r];
}
assert((rhsRational(r) < _rationalPosInfty) == _upperFinite(_rowTypes[r]));
if(_upperFinite(_rowTypes[r]))
{
if(rhsRational(r) == 0)
{
_modRhs[r] = sol._slacks[r];
_modRhs[r] *= -1;
}
else
{
_modRhs[r] = rhsRational(r);
_modRhs[r] -= sol._slacks[r];
}
if(_modRhs[r] < -sideViolation)
sideViolation = -_modRhs[r];
else if(basisStatusRow == SPxSolverBase<R>::ON_UPPER && _modRhs[r] > sideViolation)
sideViolation = _modRhs[r];
}
}
MSG_DEBUG(std::cout << "Computing dual violations.\n");
redCostViolation = 0;
for(int c = numColsRational() - 1; c >= 0; c--)
{
if(_colTypes[c] == RANGETYPE_FIXED)
continue;
const typename SPxSolverBase<R>::VarStatus& basisStatusCol = _basisStatusCols[c];
assert(basisStatusCol != SPxSolverBase<R>::FIXED);
if(((maximizing && basisStatusCol != SPxSolverBase<R>::ON_LOWER) || (!maximizing
&& basisStatusCol != SPxSolverBase<R>::ON_UPPER))
&& sol._redCost[c] < -redCostViolation)
{
MSG_DEBUG(std::cout << "basisStatusCol = " << basisStatusCol
<< ", lower tight = " << bool(sol._primal[c] <= lowerRational(c))
<< ", upper tight = " << bool(sol._primal[c] >= upperRational(c))
<< ", sol._redCost[c] = " << sol._redCost[c].str()
<< "\n");
redCostViolation = -sol._redCost[c];
}
if(((maximizing && basisStatusCol != SPxSolverBase<R>::ON_UPPER) || (!maximizing
&& basisStatusCol != SPxSolverBase<R>::ON_LOWER))
&& sol._redCost[c] > redCostViolation)
{
MSG_DEBUG(std::cout << "basisStatusCol = " << basisStatusCol
<< ", lower tight = " << bool(sol._primal[c] <= lowerRational(c))
<< ", upper tight = " << bool(sol._primal[c] >= upperRational(c))
<< ", sol._redCost[c] = " << sol._redCost[c].str()
<< "\n");
redCostViolation = sol._redCost[c];
}
}
dualViolation = 0;
for(int r = numRowsRational() - 1; r >= 0; r--)
{
if(_rowTypes[r] == RANGETYPE_FIXED)
continue;
const typename SPxSolverBase<R>::VarStatus& basisStatusRow = _basisStatusRows[r];
assert(basisStatusRow != SPxSolverBase<R>::FIXED);
if(((maximizing && basisStatusRow != SPxSolverBase<R>::ON_LOWER) || (!maximizing
&& basisStatusRow != SPxSolverBase<R>::ON_UPPER))
&& sol._dual[r] < -dualViolation)
{
MSG_DEBUG(std::cout << "basisStatusRow = " << basisStatusRow
<< ", lower tight = " << bool(sol._slacks[r] <= lhsRational(r))
<< ", upper tight = " << bool(sol._slacks[r] >= rhsRational(r))
<< ", sol._dual[r] = " << sol._dual[r].str()
<< "\n");
dualViolation = -sol._dual[r];
}
if(((maximizing && basisStatusRow != SPxSolverBase<R>::ON_UPPER) || (!maximizing
&& basisStatusRow != SPxSolverBase<R>::ON_LOWER))
&& sol._dual[r] > dualViolation)
{
MSG_DEBUG(std::cout << "basisStatusRow = " << basisStatusRow
<< ", lower tight = " << bool(sol._slacks[r] <= lhsRational(r))
<< ", upper tight = " << bool(sol._slacks[r] >= rhsRational(r))
<< ", sol._dual[r] = " << sol._dual[r].str()
<< "\n");
dualViolation = sol._dual[r];
}
}
_modObj = sol._redCost;
MSG_INFO1(spxout, spxout
<< "Max. bound violation = " << boundsViolation.str() << "\n"
<< "Max. row violation = " << sideViolation.str() << "\n"
<< "Max. reduced cost violation = " << redCostViolation.str() << "\n"
<< "Max. dual violation = " << dualViolation.str() << "\n");
MSG_DEBUG(spxout
<< std::fixed << std::setprecision(2) << std::setw(10)
<< "Progress table: "
<< std::setw(10) << _statistics->refinements << " & "
<< std::setw(10) << _statistics->iterations << " & "
<< std::setw(10) << _statistics->solvingTime->time() << " & "
<< std::setw(10) << _statistics->rationalTime->time() << " & "
<< std::setw(10) << boundsViolation > sideViolation ? boundsViolation :
sideViolation << " & "
<< std::setw(10) << redCostViolation > dualViolation ? redCostViolation :
dualViolation << "\n");
primalFeasible = (boundsViolation <= _rationalFeastol && sideViolation <= _rationalFeastol);
dualFeasible = (redCostViolation <= _rationalOpttol && dualViolation <= _rationalOpttol);
if(primalFeasible && dualFeasible)
{
if(minRounds < 0)
{
MSG_INFO1(spxout, spxout << "Tolerances reached.\n");
break;
}
else
{
MSG_INFO1(spxout, spxout <<
"Tolerances reached but minRounds forcing additional refinement rounds.\n");
}
}
if(_isSolveStopped(stoppedTime, stoppedIter) || numFailedRefinements > 2)
break;
maxViolation = boundsViolation;
if(sideViolation > maxViolation)
maxViolation = sideViolation;
if(redCostViolation > maxViolation)
maxViolation = redCostViolation;
if(dualViolation > maxViolation)
maxViolation = dualViolation;
bestViolation /= violationImprovementFactor;
if(maxViolation > bestViolation)
{
MSG_INFO2(spxout, spxout << "Failed to reduce violation significantly.\n");
bestViolation *= violationImprovementFactor;
numFailedRefinements++;
}
else
bestViolation = maxViolation;
bool forcebasic = boolParam(SoPlexBase<R>::FORCEBASIC);
bool performRatfac = boolParam(SoPlexBase<R>::RATFAC)
&& lastStallRefinements >= intParam(SoPlexBase<R>::RATFAC_MINSTALLS) && _hasBasis
&& factorSolNewBasis;
bool performRatrec = boolParam(SoPlexBase<R>::RATREC)
&& (_statistics->refinements >= nextRatrecRefinement || performRatfac);
performRatfac = performRatfac || forcebasic;
errorCorrection *= errorCorrectionFactor;
if(performRatrec && maxViolation > 0)
{
MSG_INFO1(spxout, spxout << "Performing rational reconstruction . . .\n");
maxViolation *= errorCorrection; invert(maxViolation);
if(_reconstructSolutionRational(sol, _basisStatusRows, _basisStatusCols, maxViolation))
{
MSG_INFO1(spxout, spxout << "Tolerances reached.\n");
primalFeasible = true;
dualFeasible = true;
if(_hasBasis || !forcebasic)
break;
}
nextRatrecRefinement = int(_statistics->refinements * realParam(SoPlexBase<R>::RATREC_FREQ)) + 1;
MSG_DEBUG(spxout << "Next rational reconstruction after refinement " << nextRatrecRefinement <<
".\n");
}
if((performRatfac && maxViolation > 0) || (!_hasBasis && forcebasic))
{
MSG_INFO1(spxout, spxout << "Performing rational factorization . . .\n");
bool optimal;
_factorizeColumnRational(sol, _basisStatusRows, _basisStatusCols, stoppedTime, stoppedIter, error,
optimal);
factorSolNewBasis = false;
if(stoppedTime)
{
MSG_INFO1(spxout, spxout << "Stopped rational factorization.\n");
}
else if(error)
{
error = false;
}
else if(optimal)
{
MSG_INFO1(spxout, spxout << "Tolerances reached.\n");
primalFeasible = true;
dualFeasible = true;
break;
}
else if(boolParam(SoPlexBase<R>::RATFACJUMP))
{
MSG_INFO1(spxout, spxout << "Jumping to exact basic solution.\n");
minRounds++;
continue;
}
}
maxScale = primalScale;
maxScale *= _rationalMaxscaleincr;
primalScale = boundsViolation > sideViolation ? boundsViolation : sideViolation;
if(primalScale < redCostViolation)
primalScale = redCostViolation;
assert(primalScale >= 0);
if(primalScale > 0)
{
invert(primalScale);
if(primalScale > maxScale)
primalScale = maxScale;
}
else
primalScale = maxScale;
if(boolParam(SoPlexBase<R>::POWERSCALING))
powRound(primalScale);
if(primalScale <= 1)
{
if(primalScale < 1)
primalScale = 1;
for(int c = numColsRational() - 1; c >= 0; c--)
{
if(_lowerFinite(_colTypes[c]))
{
if(_modLower[c] <= _rationalNegInfty)
_solver.changeLower(c, -realParam(SoPlexBase<R>::INFTY));
else
_solver.changeLower(c, static_cast<R>(_modLower[c]));
}
if(_upperFinite(_colTypes[c]))
{
if(_modUpper[c] >= _rationalPosInfty)
_solver.changeUpper(c, realParam(SoPlexBase<R>::INFTY));
else
_solver.changeUpper(c, R(_modUpper[c]));
}
}
}
else
{
MSG_INFO2(spxout, spxout << "Scaling primal by " << primalScale.str() << ".\n");
for(int c = numColsRational() - 1; c >= 0; c--)
{
if(_lowerFinite(_colTypes[c]))
{
_modLower[c] *= primalScale;
if(_modLower[c] <= _rationalNegInfty)
_solver.changeLower(c, -realParam(SoPlexBase<R>::INFTY));
else
_solver.changeLower(c, R(_modLower[c]));
}
if(_upperFinite(_colTypes[c]))
{
_modUpper[c] *= primalScale;
if(_modUpper[c] >= _rationalPosInfty)
_solver.changeUpper(c, realParam(SoPlexBase<R>::INFTY));
else
_solver.changeUpper(c, R(_modUpper[c]));
}
}
}
assert(primalScale >= 1);
if(primalScale == 1)
{
for(int r = numRowsRational() - 1; r >= 0; r--)
{
if(_lowerFinite(_rowTypes[r]))
{
if(_modLhs[r] <= _rationalNegInfty)
_solver.changeLhs(r, -realParam(SoPlexBase<R>::INFTY));
else
_solver.changeLhs(r, R(_modLhs[r]));
}
if(_upperFinite(_rowTypes[r]))
{
if(_modRhs[r] >= _rationalPosInfty)
_solver.changeRhs(r, realParam(SoPlexBase<R>::INFTY));
else
_solver.changeRhs(r, R(_modRhs[r]));
}
}
}
else
{
for(int r = numRowsRational() - 1; r >= 0; r--)
{
if(_lowerFinite(_rowTypes[r]))
{
_modLhs[r] *= primalScale;
if(_modLhs[r] <= _rationalNegInfty)
_solver.changeLhs(r, -realParam(SoPlexBase<R>::INFTY));
else
_solver.changeLhs(r, R(_modLhs[r]));
}
if(_upperFinite(_rowTypes[r]))
{
_modRhs[r] *= primalScale;
if(_modRhs[r] >= _rationalPosInfty)
_solver.changeRhs(r, realParam(SoPlexBase<R>::INFTY));
else
_solver.changeRhs(r, R(_modRhs[r]));
}
}
}
maxScale = dualScale;
maxScale *= _rationalMaxscaleincr;
dualScale = redCostViolation > dualViolation ? redCostViolation : dualViolation;
assert(dualScale >= 0);
if(dualScale > 0)
{
invert(dualScale);
if(dualScale > maxScale)
dualScale = maxScale;
}
else
dualScale = maxScale;
if(boolParam(SoPlexBase<R>::POWERSCALING))
powRound(dualScale);
if(dualScale > primalScale)
dualScale = primalScale;
if(dualScale < 1)
dualScale = 1;
else
{
MSG_INFO2(spxout, spxout << "Scaling dual by " << dualScale.str() << ".\n");
_modObj *= dualScale;
}
for(int c = numColsRational() - 1; c >= 0; c--)
{
if(_modObj[c] >= _rationalPosInfty)
_solver.changeObj(c, realParam(SoPlexBase<R>::INFTY));
else if(_modObj[c] <= _rationalNegInfty)
_solver.changeObj(c, -realParam(SoPlexBase<R>::INFTY));
else
_solver.changeObj(c, R(_modObj[c]));
}
for(int r = numRowsRational() - 1; r >= 0; r--)
{
Rational newRowObj;
if(_rowTypes[r] == RANGETYPE_FIXED)
_solver.changeRowObj(r, R(0.0));
else
{
newRowObj = sol._dual[r];
newRowObj *= dualScale;
if(newRowObj >= _rationalPosInfty)
_solver.changeRowObj(r, -realParam(SoPlexBase<R>::INFTY));
else if(newRowObj <= _rationalNegInfty)
_solver.changeRowObj(r, realParam(SoPlexBase<R>::INFTY));
else
_solver.changeRowObj(r, -R(newRowObj));
}
}
MSG_INFO1(spxout, spxout << "Refined floating-point solve . . .\n");
if(_slackCols.num() > 0 && _hasBasis)
{
int numOrigCols = numColsRational() - _slackCols.num();
assert(_slackCols.num() <= 0 || boolParam(SoPlexBase<R>::EQTRANS));
for(int i = 0; i < _slackCols.num(); i++)
{
int row = _slackCols.colVector(i).index(0);
int col = numOrigCols + i;
assert(row >= 0);
assert(row < numRowsRational());
if(_basisStatusRows[row] == SPxSolverBase<R>::BASIC
&& _basisStatusCols[col] != SPxSolverBase<R>::BASIC)
{
_basisStatusRows[row] = _basisStatusCols[col];
_basisStatusCols[col] = SPxSolverBase<R>::BASIC;
_rationalLUSolver.clear();
}
}
}
if(_hasBasis && _solver.basis().status() < SPxBasisBase<R>::REGULAR)
{
MSG_DEBUG(spxout << "basis (status = " << _solver.basis().status() << ") desc before set:\n";
_solver.basis().desc().dump());
_solver.setBasis(_basisStatusRows.get_const_ptr(), _basisStatusCols.get_const_ptr());
MSG_DEBUG(spxout << "basis (status = " << _solver.basis().status() << ") desc after set:\n";
_solver.basis().desc().dump());
_hasBasis = _solver.basis().status() > SPxBasisBase<R>::NO_PROBLEM;
MSG_DEBUG(spxout << "setting basis in solver " << (_hasBasis ? "successful" : "failed") <<
" (3)\n");
}
int prevIterations = _statistics->iterations;
_statistics->rationalTime->stop();
result = _solveRealStable(acceptUnbounded, acceptInfeasible, primalReal, dualReal, _basisStatusRows,
_basisStatusCols, primalScale > 1e20 || dualScale > 1e20);
_statistics->refinements++;
if(_statistics->iterations <= prevIterations)
{
lastStallRefinements++;
_statistics->stallRefinements++;
}
else
{
factorSolNewBasis = true;
lastStallRefinements = 0;
_statistics->pivotRefinements = _statistics->refinements;
}
switch(result)
{
case SPxSolverBase<R>::OPTIMAL:
MSG_INFO1(spxout, spxout << "Floating-point optimal.\n");
break;
case SPxSolverBase<R>::INFEASIBLE:
MSG_INFO1(spxout, spxout << "Floating-point infeasible.\n");
sol._dualFarkas = dualReal;
sol._hasDualFarkas = true;
infeasible = true;
_solver.clearRowObjs();
return;
case SPxSolverBase<R>::UNBOUNDED:
MSG_INFO1(spxout, spxout << "Floating-point unbounded.\n");
unbounded = true;
_solver.clearRowObjs();
return;
case SPxSolverBase<R>::ABORT_TIME:
stoppedTime = true;
return;
case SPxSolverBase<R>::ABORT_ITER:
stoppedIter = true;
_solver.clearRowObjs();
return;
default:
error = true;
_solver.clearRowObjs();
return;
}
_statistics->rationalTime->start();
MSG_DEBUG(std::cout << "Correcting primal solution.\n");
int primalSize = 0;
Rational primalScaleInverse = primalScale;
invert(primalScaleInverse);
_primalDualDiff.clear();
for(int c = numColsRational() - 1; c >= 0; c--)
{
typename SPxSolverBase<R>::VarStatus& basisStatusCol = _basisStatusCols[c];
if(basisStatusCol == SPxSolverBase<R>::ON_LOWER)
{
if(sol._primal[c] != lowerRational(c))
{
int i = _primalDualDiff.size();
_ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
_primalDualDiff.add(c);
_primalDualDiff.value(i) = lowerRational(c);
_primalDualDiff.value(i) -= sol._primal[c];
sol._primal[c] = lowerRational(c);
}
}
else if(basisStatusCol == SPxSolverBase<R>::ON_UPPER)
{
if(sol._primal[c] != upperRational(c))
{
int i = _primalDualDiff.size();
_ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
_primalDualDiff.add(c);
_primalDualDiff.value(i) = upperRational(c);
_primalDualDiff.value(i) -= sol._primal[c];
sol._primal[c] = upperRational(c);
}
}
else if(basisStatusCol == SPxSolverBase<R>::FIXED)
{
basisStatusCol = SPxSolverBase<R>::ON_LOWER;
if(sol._primal[c] != lowerRational(c))
{
int i = _primalDualDiff.size();
_ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
_primalDualDiff.add(c);
_primalDualDiff.value(i) = lowerRational(c);
_primalDualDiff.value(i) -= sol._primal[c];
sol._primal[c] = lowerRational(c);
}
}
else if(basisStatusCol == SPxSolverBase<R>::ZERO)
{
if(sol._primal[c] != 0)
{
int i = _primalDualDiff.size();
_ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
_primalDualDiff.add(c);
_primalDualDiff.value(i) = sol._primal[c];
_primalDualDiff.value(i) *= -1;
sol._primal[c] = 0;
}
}
else
{
if(primalReal[c] == 1.0)
{
int i = _primalDualDiff.size();
_ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
_primalDualDiff.add(c);
_primalDualDiff.value(i) = primalScaleInverse;
sol._primal[c] += _primalDualDiff.value(i);
}
else if(primalReal[c] == -1.0)
{
int i = _primalDualDiff.size();
_ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
_primalDualDiff.add(c);
_primalDualDiff.value(i) = primalScaleInverse;
_primalDualDiff.value(i) *= -1;
sol._primal[c] += _primalDualDiff.value(i);
}
else if(primalReal[c] != 0.0)
{
int i = _primalDualDiff.size();
_ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
_primalDualDiff.add(c);
_primalDualDiff.value(i).assign(primalReal[c]);
_primalDualDiff.value(i) *= primalScaleInverse;
sol._primal[c] += _primalDualDiff.value(i);
}
}
if(sol._primal[c] != 0)
primalSize++;
}
if(_primalDualDiff.size() < primalSize)
{
_rationalLP->addPrimalActivity(_primalDualDiff, sol._slacks);
#ifndef NDEBUG
{
VectorRational activity(numRowsRational());
_rationalLP->computePrimalActivity(sol._primal, activity);
assert(sol._slacks == activity);
}
#endif
}
else
_rationalLP->computePrimalActivity(sol._primal, sol._slacks);
const int numCorrectedPrimals = _primalDualDiff.size();
MSG_DEBUG(std::cout << "Correcting dual solution.\n");
#ifndef NDEBUG
{
VectorRational debugRedCost(numColsRational());
debugRedCost = VectorRational(_realLP->maxObj());
debugRedCost *= -1;
_rationalLP->subDualActivity(VectorRational(dualReal), debugRedCost);
Rational debugRedCostViolation = 0;
for(int c = numColsRational() - 1; c >= 0; c--)
{
if(_colTypes[c] == RANGETYPE_FIXED)
continue;
const typename SPxSolverBase<R>::VarStatus& basisStatusCol = _basisStatusCols[c];
assert(basisStatusCol != SPxSolverBase<R>::FIXED);
if(((maximizing && basisStatusCol != SPxSolverBase<R>::ON_LOWER) || (!maximizing
&& basisStatusCol != SPxSolverBase<R>::ON_UPPER))
&& debugRedCost[c] < -debugRedCostViolation)
{
MSG_DEBUG(std::cout << "basisStatusCol = " << basisStatusCol
<< ", lower tight = " << bool(sol._primal[c] <= lowerRational(c))
<< ", upper tight = " << bool(sol._primal[c] >= upperRational(c))
<< ", obj[c] = " << _realLP->obj(c)
<< ", debugRedCost[c] = " << debugRedCost[c].str()
<< "\n");
debugRedCostViolation = -debugRedCost[c];
}
if(((maximizing && basisStatusCol != SPxSolverBase<R>::ON_UPPER) || (!maximizing
&& basisStatusCol != SPxSolverBase<R>::ON_LOWER))
&& debugRedCost[c] > debugRedCostViolation)
{
MSG_DEBUG(std::cout << "basisStatusCol = " << basisStatusCol
<< ", lower tight = " << bool(sol._primal[c] <= lowerRational(c))
<< ", upper tight = " << bool(sol._primal[c] >= upperRational(c))
<< ", obj[c] = " << _realLP->obj(c)
<< ", debugRedCost[c] = " << debugRedCost[c].str()
<< "\n");
debugRedCostViolation = debugRedCost[c];
}
}
Rational debugDualViolation = 0;
Rational debugBasicDualViolation = 0;
for(int r = numRowsRational() - 1; r >= 0; r--)
{
if(_rowTypes[r] == RANGETYPE_FIXED)
continue;
const typename SPxSolverBase<R>::VarStatus& basisStatusRow = _basisStatusRows[r];
assert(basisStatusRow != SPxSolverBase<R>::FIXED);
Rational val = (-dualScale * sol._dual[r]) - Rational(dualReal[r]);
if(((maximizing && basisStatusRow != SPxSolverBase<R>::ON_LOWER) || (!maximizing
&& basisStatusRow != SPxSolverBase<R>::ON_UPPER))
&& val > debugDualViolation)
{
MSG_DEBUG(std::cout << "basisStatusRow = " << basisStatusRow
<< ", lower tight = " << bool(sol._slacks[r] <= lhsRational(r))
<< ", upper tight = " << bool(sol._slacks[r] >= rhsRational(r))
<< ", dualReal[r] = " << val.str()
<< ", dualReal[r] = " << dualReal[r]
<< "\n");
debugDualViolation = val;
}
if(((maximizing && basisStatusRow != SPxSolverBase<R>::ON_UPPER) || (!maximizing
&& basisStatusRow != SPxSolverBase<R>::ON_LOWER))
&& val < -debugDualViolation)
{
MSG_DEBUG(std::cout << "basisStatusRow = " << basisStatusRow
<< ", lower tight = " << bool(sol._slacks[r] <= lhsRational(r))
<< ", upper tight = " << bool(sol._slacks[r] >= rhsRational(r))
<< ", dualReal[r] = " << val.str()
<< ", dualReal[r] = " << dualReal[r]
<< "\n");
debugDualViolation = -val;
}
if(basisStatusRow == SPxSolverBase<R>::BASIC && spxAbs(val) > debugBasicDualViolation)
{
MSG_DEBUG(std::cout << "basisStatusRow = " << basisStatusRow
<< ", lower tight = " << bool(sol._slacks[r] <= lhsRational(r))
<< ", upper tight = " << bool(sol._slacks[r] >= rhsRational(r))
<< ", dualReal[r] = " << val.str()
<< ", dualReal[r] = " << dualReal[r]
<< "\n");
debugBasicDualViolation = spxAbs(val);
}
}
if(R(debugRedCostViolation) > _solver.opttol() || R(debugDualViolation) > _solver.opttol()
|| debugBasicDualViolation > 1e-9)
{
MSG_WARNING(spxout, spxout << "Warning: floating-point dual solution with violation "
<< debugRedCostViolation.str() << " / "
<< debugDualViolation.str() << " / "
<< debugBasicDualViolation.str()
<< " (red. cost, dual, basic).\n");
}
}
#endif
Rational dualScaleInverseNeg = dualScale;
invert(dualScaleInverseNeg);
dualScaleInverseNeg *= -1;
_primalDualDiff.clear();
dualSize = 0;
for(int r = numRowsRational() - 1; r >= 0; r--)
{
typename SPxSolverBase<R>::VarStatus& basisStatusRow = _basisStatusRows[r];
if(basisStatusRow == SPxSolverBase<R>::FIXED)
basisStatusRow = SPxSolverBase<R>::ON_LOWER;
{
if(dualReal[r] != 0)
{
int i = _primalDualDiff.size();
_ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
_primalDualDiff.add(r);
_primalDualDiff.value(i).assign(dualReal[r]);
_primalDualDiff.value(i) *= dualScaleInverseNeg;
sol._dual[r] -= _primalDualDiff.value(i);
dualSize++;
}
else
{
dualSize++;
}
}
}
if(_primalDualDiff.size() < dualSize + 1)
{
_rationalLP->addDualActivity(_primalDualDiff, sol._redCost);
#ifndef NDEBUG
{
VectorRational activity(_rationalLP->maxObj());
activity *= -1;
_rationalLP->subDualActivity(sol._dual, activity);
}
#endif
}
else
{
_rationalLP->getObj(sol._redCost);
_rationalLP->subDualActivity(sol._dual, sol._redCost);
}
const int numCorrectedDuals = _primalDualDiff.size();
if(numCorrectedPrimals + numCorrectedDuals > 0)
{
MSG_INFO2(spxout, spxout << "Corrected " << numCorrectedPrimals << " primal variables and " <<
numCorrectedDuals << " dual values.\n");
}
}
while(true);
if(_hasBasis)
{
for(int r = numRowsRational() - 1; r >= 0; r--)
{
assert((lhsRational(r) == rhsRational(r)) == (_rowTypes[r] == RANGETYPE_FIXED));
if(_rowTypes[r] != RANGETYPE_FIXED && _basisStatusRows[r] == SPxSolverBase<R>::FIXED)
_basisStatusRows[r] = (maximizing == (sol._dual[r] < 0))
? SPxSolverBase<R>::ON_LOWER
: SPxSolverBase<R>::ON_UPPER;
}
}
assert(sol._isPrimalFeasible == sol._isDualFeasible);
if(sol._isPrimalFeasible)
{
sol._objVal = sol._primal * _rationalLP->maxObj();
if(intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MINIMIZE)
sol._objVal *= -1;
}
_solver.clearRowObjs();
_statistics->rationalTime->stop();
}
template <class R>
void SoPlexBase<R>::_performUnboundedIRStable(
SolRational& sol,
bool& hasUnboundedRay,
bool& stoppedTime,
bool& stoppedIter,
bool& error)
{
bool primalFeasible;
bool dualFeasible;
bool infeasible;
bool unbounded;
_transformUnbounded();
sol.invalidate();
int oldRefinements = _statistics->refinements;
_performOptIRStable(sol, false, false, 0, primalFeasible, dualFeasible, infeasible, unbounded,
stoppedTime, stoppedIter, error);
_statistics->unbdRefinements += _statistics->refinements - oldRefinements;
if(stoppedTime || stoppedIter)
{
sol.invalidate();
hasUnboundedRay = false;
error = false;
}
else if(error || unbounded || infeasible || !primalFeasible || !dualFeasible)
{
sol.invalidate();
hasUnboundedRay = false;
error = true;
}
else
{
const Rational& tau = sol._primal[numColsRational() - 1];
MSG_DEBUG(std::cout << "tau = " << tau << " (roughly " << tau.str() << ")\n");
assert(tau <= 1.0 + 2.0 * realParam(SoPlexBase<R>::FEASTOL));
assert(tau >= -realParam(SoPlexBase<R>::FEASTOL));
error = !(tau >= _rationalPosone || tau <= _rationalFeastol);
assert(!error);
hasUnboundedRay = (tau >= 1);
}
_untransformUnbounded(sol, hasUnboundedRay);
}
template <class R>
void SoPlexBase<R>::_performFeasIRStable(
SolRational& sol,
bool& withDualFarkas,
bool& stoppedTime,
bool& stoppedIter,
bool& error)
{
bool primalFeasible;
bool dualFeasible;
bool infeasible;
bool unbounded;
bool success = false;
error = false;
#if 0#endif
_transformFeasibility();
sol.invalidate();
do
{
int oldRefinements = _statistics->refinements;
_performOptIRStable(sol, false, false, 0, primalFeasible, dualFeasible, infeasible, unbounded,
stoppedTime, stoppedIter, error);
_statistics->feasRefinements += _statistics->refinements - oldRefinements;
if(stoppedTime || stoppedIter)
{
sol.invalidate();
withDualFarkas = false;
error = false;
}
else if(error || unbounded || infeasible || !primalFeasible || !dualFeasible)
{
sol.invalidate();
withDualFarkas = false;
error = true;
}
else
{
const Rational& tau = sol._primal[numColsRational() - 1];
MSG_DEBUG(std::cout << "tau = " << tau << " (roughly " << tau.str() << ")\n");
assert(tau >= -realParam(SoPlexBase<R>::FEASTOL));
assert(tau <= 1.0 + realParam(SoPlexBase<R>::FEASTOL));
error = (tau < -_rationalFeastol || tau > _rationalPosone + _rationalFeastol);
withDualFarkas = (tau < _rationalPosone);
if(withDualFarkas)
{
_solRational._hasDualFarkas = true;
_solRational._dualFarkas = _solRational._dual;
#if 0#endif
if(true) {
success = true;
sol._isPrimalFeasible = false;
}
}
else
{
sol._isDualFeasible = false;
success = true; }
}
}
while(!error && !success && !(stoppedTime || stoppedIter));
_untransformFeasibility(sol, withDualFarkas);
}
template <class R>
void SoPlexBase<R>::_lift()
{
MSG_DEBUG(std::cout << "Reducing matrix coefficients by lifting.\n");
_statistics->transformTime->start();
MSG_DEBUG(_realLP->writeFileLPBase("beforeLift.lp", 0, 0, 0));
_beforeLiftCols = numColsRational();
_beforeLiftRows = numRowsRational();
DSVectorRational colVector;
SVectorRational::Element liftingRowMem[2];
SVectorRational liftingRowVector(2, liftingRowMem);
const Rational maxValue = static_cast<Rational>(realParam(SoPlexBase<R>::LIFTMAXVAL));
for(int i = 0; i < numColsRational(); i++)
{
MSG_DEBUG(std::cout << "in lifting: examining column " << i << "\n");
colVector = colVectorRational(i);
bool addedLiftingRow = false;
int liftingColumnIndex = -1;
for(int k = colVector.size() - 1; k >= 0; k--)
{
const Rational& value = colVector.value(k);
if(spxAbs(value) > maxValue)
{
MSG_DEBUG(std::cout << " --> nonzero " << k << " has value " << value.str() << " in row " <<
colVector.index(k) << "\n");
if(!addedLiftingRow)
{
MSG_DEBUG(std::cout << " --> adding lifting row\n");
assert(liftingRowVector.size() == 0);
liftingColumnIndex = numColsRational();
liftingRowVector.add(i, maxValue);
liftingRowVector.add(liftingColumnIndex, -1);
_rationalLP->addRow(LPRowRational(0, liftingRowVector, 0));
_realLP->addRow(LPRowBase<R>(0.0, DSVectorBase<R>(liftingRowVector), 0.0));
assert(liftingColumnIndex == numColsRational() - 1);
assert(liftingColumnIndex == numCols() - 1);
_rationalLP->changeBounds(liftingColumnIndex, _rationalNegInfty, _rationalPosInfty);
_realLP->changeBounds(liftingColumnIndex, -realParam(SoPlexBase<R>::INFTY),
realParam(SoPlexBase<R>::INFTY));
liftingRowVector.clear();
addedLiftingRow = true;
}
int rowIndex = colVector.index(k);
assert(rowIndex >= 0);
assert(rowIndex < _beforeLiftRows);
assert(liftingColumnIndex == numColsRational() - 1);
MSG_DEBUG(std::cout << " --> changing matrix\n");
_rationalLP->changeElement(rowIndex, i, 0);
_realLP->changeElement(rowIndex, i, 0.0);
Rational newValue(value);
newValue /= maxValue;
_rationalLP->changeElement(rowIndex, liftingColumnIndex, newValue);
_realLP->changeElement(rowIndex, liftingColumnIndex, R(newValue));
}
}
}
const Rational minValue = Rational(realParam(SoPlexBase<R>::LIFTMINVAL));
for(int i = 0; i < numColsRational(); i++)
{
MSG_DEBUG(std::cout << "in lifting: examining column " << i << "\n");
colVector = colVectorRational(i);
bool addedLiftingRow = false;
int liftingColumnIndex = -1;
for(int k = colVector.size() - 1; k >= 0; k--)
{
const Rational& value = colVector.value(k);
if(spxAbs(value) < minValue)
{
MSG_DEBUG(std::cout << " --> nonzero " << k << " has value " << value.str() << " in row " <<
colVector.index(k) << "\n");
if(!addedLiftingRow)
{
MSG_DEBUG(std::cout << " --> adding lifting row\n");
assert(liftingRowVector.size() == 0);
liftingColumnIndex = numColsRational();
liftingRowVector.add(i, minValue);
liftingRowVector.add(liftingColumnIndex, -1);
_rationalLP->addRow(LPRowRational(0, liftingRowVector, 0));
_realLP->addRow(LPRowBase<R>(0.0, DSVectorBase<R>(liftingRowVector), 0.0));
assert(liftingColumnIndex == numColsRational() - 1);
assert(liftingColumnIndex == numCols() - 1);
_rationalLP->changeBounds(liftingColumnIndex, _rationalNegInfty, _rationalPosInfty);
_realLP->changeBounds(liftingColumnIndex, -realParam(SoPlexBase<R>::INFTY),
realParam(SoPlexBase<R>::INFTY));
liftingRowVector.clear();
addedLiftingRow = true;
}
int rowIndex = colVector.index(k);
assert(rowIndex >= 0);
assert(rowIndex < _beforeLiftRows);
assert(liftingColumnIndex == numColsRational() - 1);
MSG_DEBUG(std::cout << " --> changing matrix\n");
_rationalLP->changeElement(rowIndex, i, 0);
_realLP->changeElement(rowIndex, i, 0.0);
Rational newValue(value);
newValue /= minValue;
_rationalLP->changeElement(rowIndex, liftingColumnIndex, newValue);
_realLP->changeElement(rowIndex, liftingColumnIndex, R(newValue));
}
}
}
if(_hasBasis)
{
assert(numColsRational() >= _beforeLiftCols);
assert(numRowsRational() >= _beforeLiftRows);
_basisStatusCols.append(numColsRational() - _beforeLiftCols, SPxSolverBase<R>::BASIC);
_basisStatusRows.append(numRowsRational() - _beforeLiftRows, SPxSolverBase<R>::FIXED);
_rationalLUSolver.clear();
}
MSG_DEBUG(_realLP->writeFileLPBase("afterLift.lp", 0, 0, 0));
_statistics->transformTime->stop();
if(numColsRational() > _beforeLiftCols || numRowsRational() > _beforeLiftRows)
{
MSG_INFO1(spxout, spxout << "Added " << numColsRational() - _beforeLiftCols << " columns and "
<< numRowsRational() - _beforeLiftRows << " rows to reduce large matrix coefficients\n.");
}
}
template <class R>
void SoPlexBase<R>::_project(SolRational& sol)
{
_statistics->transformTime->start();
MSG_DEBUG(_realLP->writeFileLPBase("beforeProject.lp", 0, 0, 0));
assert(numColsRational() >= _beforeLiftCols);
assert(numRowsRational() >= _beforeLiftRows);
_rationalLP->removeColRange(_beforeLiftCols, numColsRational() - 1);
_rationalLP->removeRowRange(_beforeLiftRows, numRowsRational() - 1);
_realLP->removeColRange(_beforeLiftCols, numColsReal() - 1);
_realLP->removeRowRange(_beforeLiftRows, numRowsReal() - 1);
if(sol.isPrimalFeasible())
{
sol._primal.reDim(_beforeLiftCols);
sol._slacks.reDim(_beforeLiftRows);
}
if(sol.hasPrimalRay())
{
sol._primalRay.reDim(_beforeLiftCols);
}
const Rational maxValue = Rational(realParam(SoPlexBase<R>::LIFTMAXVAL));
for(int i = _beforeLiftCols; i < numColsRational() && sol._isDualFeasible; i++)
{
if(spxAbs(Rational(maxValue * sol._redCost[i])) > _rationalOpttol)
{
MSG_INFO1(spxout, spxout << "Warning: lost dual solution during project phase.\n");
sol._isDualFeasible = false;
}
}
if(sol.isDualFeasible())
{
sol._redCost.reDim(_beforeLiftCols);
sol._dual.reDim(_beforeLiftRows);
}
if(sol.hasDualFarkas())
{
sol._dualFarkas.reDim(_beforeLiftRows);
}
for(int i = _beforeLiftCols; i < numColsRational() && _hasBasis; i++)
{
if(_basisStatusCols[i] != SPxSolverBase<R>::BASIC)
{
MSG_INFO1(spxout, spxout <<
"Warning: lost basis during project phase because of nonbasic lifting column.\n");
_hasBasis = false;
_rationalLUSolver.clear();
}
}
for(int i = _beforeLiftRows; i < numRowsRational() && _hasBasis; i++)
{
if(_basisStatusRows[i] == SPxSolverBase<R>::BASIC)
{
MSG_INFO1(spxout, spxout <<
"Warning: lost basis during project phase because of basic lifting row.\n");
_hasBasis = false;
_rationalLUSolver.clear();
}
}
if(_hasBasis)
{
_basisStatusCols.reSize(_beforeLiftCols);
_basisStatusRows.reSize(_beforeLiftRows);
_rationalLUSolver.clear();
}
MSG_DEBUG(_realLP->writeFileLPBase("afterProject.lp", 0, 0, 0));
_statistics->transformTime->stop();
}
template <class R>
void SoPlexBase<R>::_storeLPReal()
{
#ifndef SOPLEX_MANUAL_ALT
if(intParam(SoPlexBase<R>::SYNCMODE) == SYNCMODE_MANUAL)
{
_manualRealLP = *_realLP;
return;
}
#endif
_manualLower = _realLP->lower();
_manualUpper = _realLP->upper();
_manualLhs = _realLP->lhs();
_manualRhs = _realLP->rhs();
_manualObj.reDim(_realLP->nCols());
_realLP->getObj(_manualObj);
}
template <class R>
void SoPlexBase<R>::_restoreLPReal()
{
if(intParam(SoPlexBase<R>::SYNCMODE) == SYNCMODE_MANUAL)
{
#ifndef SOPLEX_MANUAL_ALT
_solver.loadLP(_manualRealLP);
#else
_realLP->changeLower(_manualLower);
_realLP->changeUpper(_manualUpper);
_realLP->changeLhs(_manualLhs);
_realLP->changeRhs(_manualRhs);
_realLP->changeObj(_manualObj);
#endif
if(_hasBasis)
{
for(int i = 0; i < _solver.nRows(); i++)
{
if(_basisStatusRows[i] == SPxSolverBase<R>::FIXED && _solver.lhs(i) != _solver.rhs(i))
{
assert(_solver.rhs(i) == spxNextafter(_solver.lhs(i), R(infinity)));
if(_hasSolRational && _solRational.isDualFeasible()
&& ((intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MAXIMIZE
&& _solRational._dual[i] > 0)
|| (intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MINIMIZE
&& _solRational._dual[i] < 0)))
{
_basisStatusRows[i] = SPxSolverBase<R>::ON_UPPER;
}
else
{
_basisStatusRows[i] = SPxSolverBase<R>::ON_LOWER;
}
}
}
_solver.setBasis(_basisStatusRows.get_const_ptr(), _basisStatusCols.get_const_ptr());
_hasBasis = (_solver.basis().status() > SPxBasisBase<R>::NO_PROBLEM);
}
}
else
{
_realLP->changeLower(_manualLower);
_realLP->changeUpper(_manualUpper);
_realLP->changeLhs(_manualLhs);
_realLP->changeRhs(_manualRhs);
_realLP->changeObj(_manualObj);
}
}
template <class R>
void SoPlexBase<R>::_transformEquality()
{
MSG_DEBUG(std::cout << "Transforming rows to equation form.\n");
_statistics->transformTime->start();
MSG_DEBUG(_realLP->writeFileLPBase("beforeTransEqu.lp", 0, 0, 0));
_slackCols.clear();
for(int i = 0; i < numRowsRational(); i++)
{
assert((lhsRational(i) == rhsRational(i)) == (_rowTypes[i] == RANGETYPE_FIXED));
if(_rowTypes[i] != RANGETYPE_FIXED)
{
_slackCols.add(_rationalZero, -rhsRational(i), *_unitVectorRational(i), -lhsRational(i));
if(_rationalLP->lhs(i) != 0)
_rationalLP->changeLhs(i, _rationalZero);
if(_rationalLP->rhs(i) != 0)
_rationalLP->changeRhs(i, _rationalZero);
assert(_rationalLP->lhs(i) == 0);
assert(_rationalLP->rhs(i) == 0);
_realLP->changeRange(i, R(0.0), R(0.0));
_colTypes.append(_switchRangeType(_rowTypes[i]));
_rowTypes[i] = RANGETYPE_FIXED;
}
}
_rationalLP->addCols(_slackCols);
_realLP->addCols(_slackCols);
if(_hasBasis)
{
for(int i = 0; i < _slackCols.num(); i++)
{
int row = _slackCols.colVector(i).index(0);
assert(row >= 0);
assert(row < numRowsRational());
switch(_basisStatusRows[row])
{
case SPxSolverBase<R>::ON_LOWER:
_basisStatusCols.append(SPxSolverBase<R>::ON_UPPER);
break;
case SPxSolverBase<R>::ON_UPPER:
_basisStatusCols.append(SPxSolverBase<R>::ON_LOWER);
break;
case SPxSolverBase<R>::BASIC:
case SPxSolverBase<R>::FIXED:
default:
_basisStatusCols.append(_basisStatusRows[row]);
break;
}
_basisStatusRows[row] = SPxSolverBase<R>::FIXED;
}
_rationalLUSolver.clear();
}
MSG_DEBUG(_realLP->writeFileLPBase("afterTransEqu.lp", 0, 0, 0));
_statistics->transformTime->stop();
if(_slackCols.num() > 0)
{
MSG_INFO1(spxout, spxout << "Added " << _slackCols.num() <<
" slack columns to transform rows to equality form.\n");
}
}
template <class R>
void SoPlexBase<R>::_untransformEquality(SolRational& sol)
{
_statistics->transformTime->start();
MSG_DEBUG(_realLP->writeFileLPBase("beforeUntransEqu.lp", 0, 0, 0));
int numCols = numColsRational();
int numOrigCols = numColsRational() - _slackCols.num();
if(sol.isPrimalFeasible())
{
for(int i = 0; i < _slackCols.num(); i++)
{
int col = numOrigCols + i;
int row = _slackCols.colVector(i).index(0);
assert(row >= 0);
assert(row < numRowsRational());
sol._slacks[row] -= sol._primal[col];
}
sol._primal.reDim(numOrigCols);
}
if(sol.hasPrimalRay())
{
sol._primalRay.reDim(numOrigCols);
}
if(_hasBasis)
{
for(int i = 0; i < _slackCols.num(); i++)
{
int col = numOrigCols + i;
int row = _slackCols.colVector(i).index(0);
assert(row >= 0);
assert(row < numRowsRational());
assert(_basisStatusRows[row] != SPxSolverBase<R>::UNDEFINED);
assert(_basisStatusRows[row] != SPxSolverBase<R>::ZERO || lhsRational(row) == 0);
assert(_basisStatusRows[row] != SPxSolverBase<R>::ZERO || rhsRational(row) == 0);
assert(_basisStatusRows[row] != SPxSolverBase<R>::BASIC
|| _basisStatusCols[col] != SPxSolverBase<R>::BASIC);
MSG_DEBUG(std::cout << "slack column " << col << " for row " << row
<< ": col status=" << _basisStatusCols[col]
<< ", row status=" << _basisStatusRows[row]
<< ", redcost=" << sol._redCost[col].str()
<< ", dual=" << sol._dual[row].str() << "\n");
if(_basisStatusRows[row] != SPxSolverBase<R>::BASIC)
{
switch(_basisStatusCols[col])
{
case SPxSolverBase<R>::ON_LOWER:
_basisStatusRows[row] = SPxSolverBase<R>::ON_UPPER;
break;
case SPxSolverBase<R>::ON_UPPER:
_basisStatusRows[row] = SPxSolverBase<R>::ON_LOWER;
break;
case SPxSolverBase<R>::BASIC:
case SPxSolverBase<R>::FIXED:
default:
_basisStatusRows[row] = _basisStatusCols[col];
break;
}
}
}
_basisStatusCols.reSize(numOrigCols);
if(_slackCols.num() > 0)
_rationalLUSolver.clear();
}
if(sol.isDualFeasible())
{
sol._redCost.reDim(numOrigCols);
}
for(int i = 0; i < _slackCols.num(); i++)
{
int col = numOrigCols + i;
int row = _slackCols.colVector(i).index(0);
if(upperRational(col) != 0)
_rationalLP->changeLhs(row, -upperRational(col));
if(lowerRational(col) != 0)
_rationalLP->changeRhs(row, -lowerRational(col));
assert(_rationalLP->lhs(row) == -upperRational(col));
assert(_rationalLP->rhs(row) == -lowerRational(col));
_rowTypes[row] = _switchRangeType(_colTypes[col]);
}
_rationalLP->removeColRange(numOrigCols, numCols - 1);
_realLP->removeColRange(numOrigCols, numCols - 1);
_colTypes.reSize(numOrigCols);
MSG_DEBUG(_realLP->writeFileLPBase("afterUntransEqu.lp", 0, 0, 0));
_statistics->transformTime->stop();
}
template <class R>
void SoPlexBase<R>::_transformUnbounded()
{
MSG_INFO1(spxout, spxout << "Setting up LP to compute primal unbounded ray.\n");
_statistics->transformTime->start();
MSG_DEBUG(_realLP->writeFileLPBase("beforeTransUnbounded.lp", 0, 0, 0));
_unboundedLower.reDim(numColsRational());
_unboundedUpper.reDim(numColsRational());
for(int c = numColsRational() - 1; c >= 0; c--)
{
if(_lowerFinite(_colTypes[c]))
_unboundedLower[c] = lowerRational(c);
if(_upperFinite(_colTypes[c]))
_unboundedUpper[c] = upperRational(c);
}
_unboundedLhs.reDim(numRowsRational());
_unboundedRhs.reDim(numRowsRational());
for(int r = numRowsRational() - 1; r >= 0; r--)
{
if(_lowerFinite(_rowTypes[r]))
_unboundedLhs[r] = lhsRational(r);
if(_upperFinite(_rowTypes[r]))
_unboundedRhs[r] = rhsRational(r);
}
for(int r = numRowsRational() - 1; r >= 0; r--)
{
assert((lhsRational(r) > _rationalNegInfty) == _lowerFinite(_rowTypes[r]));
if(_lowerFinite(_rowTypes[r]))
{
_rationalLP->changeLhs(r, Rational(0));
_realLP->changeLhs(r, R(0.0));
}
else if(_realLP->lhs(r) > -realParam(SoPlexBase<R>::INFTY))
_realLP->changeLhs(r, -realParam(SoPlexBase<R>::INFTY));
assert((rhsRational(r) < _rationalPosInfty) == _upperFinite(_rowTypes[r]));
if(_upperFinite(_rowTypes[r]))
{
_rationalLP->changeRhs(r, Rational(0));
_realLP->changeRhs(r, R(0.0));
}
else if(_realLP->rhs(r) < realParam(SoPlexBase<R>::INFTY))
_realLP->changeRhs(r, realParam(SoPlexBase<R>::INFTY));
}
int numOrigCols = numColsRational();
DSVectorRational obj(numOrigCols + 1);
obj = _rationalLP->maxObj();
obj.add(numOrigCols, -1);
_rationalLP->addRow(LPRowRational(0, obj, 0));
_realLP->addRow(LPRowBase<R>(0, DSVectorBase<R>(obj), 0));
_rowTypes.append(RANGETYPE_FIXED);
assert(numColsRational() == numOrigCols + 1);
_rationalLP->changeMaxObj(numOrigCols, Rational(1));
_realLP->changeMaxObj(numOrigCols, R(1.0));
_rationalLP->changeBounds(numOrigCols, _rationalNegInfty, 1);
_realLP->changeBounds(numOrigCols, -realParam(SoPlexBase<R>::INFTY), 1.0);
_colTypes.append(RANGETYPE_UPPER);
for(int c = numColsRational() - 2; c >= 0; c--)
{
_rationalLP->changeObj(c, Rational(0));
_realLP->changeObj(c, R(0.0));
assert((lowerRational(c) > _rationalNegInfty) == _lowerFinite(_colTypes[c]));
if(_lowerFinite(_colTypes[c]))
{
_rationalLP->changeLower(c, Rational(0));
_realLP->changeLower(c, R(0.0));
}
else if(_realLP->lower(c) > -realParam(SoPlexBase<R>::INFTY))
_realLP->changeLower(c, -realParam(SoPlexBase<R>::INFTY));
assert((upperRational(c) < _rationalPosInfty) == _upperFinite(_colTypes[c]));
if(_upperFinite(_colTypes[c]))
{
_rationalLP->changeUpper(c, Rational(0));
_realLP->changeUpper(c, R(0.0));
}
else if(_realLP->upper(c) < realParam(SoPlexBase<R>::INFTY))
_realLP->changeUpper(c, realParam(SoPlexBase<R>::INFTY));
}
if(_hasBasis)
{
_basisStatusCols.append(SPxSolverBase<R>::ON_UPPER);
_basisStatusRows.append(SPxSolverBase<R>::BASIC);
_rationalLUSolver.clear();
}
MSG_DEBUG(_realLP->writeFileLPBase("afterTransUnbounded.lp", 0, 0, 0));
_statistics->transformTime->stop();
}
template <class R>
void SoPlexBase<R>::_untransformUnbounded(SolRational& sol, bool unbounded)
{
_statistics->transformTime->start();
MSG_DEBUG(_realLP->writeFileLPBase("beforeUntransUnbounded.lp", 0, 0, 0));
int numOrigCols = numColsRational() - 1;
int numOrigRows = numRowsRational() - 1;
const Rational& tau = sol._primal[numOrigCols];
if(unbounded)
{
assert(tau >= _rationalPosone);
sol._isPrimalFeasible = false;
sol._hasPrimalRay = true;
sol._isDualFeasible = false;
sol._hasDualFarkas = false;
if(tau != 1)
sol._primal /= tau;
sol._primalRay = sol._primal;
sol._primalRay.reDim(numOrigCols);
_hasBasis = (_basisStatusCols[numOrigCols] != SPxSolverBase<R>::BASIC
&& _basisStatusRows[numOrigRows] == SPxSolverBase<R>::BASIC);
_basisStatusCols.reSize(numOrigCols);
_basisStatusRows.reSize(numOrigRows);
}
else if(boolParam(SoPlexBase<R>::TESTDUALINF) && tau < _rationalFeastol)
{
const Rational& alpha = sol._dual[numOrigRows];
assert(sol._isDualFeasible);
assert(alpha <= _rationalFeastol - _rationalPosone);
sol._isPrimalFeasible = false;
sol._hasPrimalRay = false;
sol._hasDualFarkas = false;
if(alpha != -1)
{
sol._dual /= -alpha;
sol._redCost /= -alpha;
}
sol._dual.reDim(numOrigRows);
sol._redCost.reDim(numOrigCols);
}
else
{
sol.invalidate();
_hasBasis = false;
_basisStatusCols.reSize(numOrigCols);
_basisStatusCols.reSize(numOrigRows);
}
const SVectorRational& objRowVector = _rationalLP->rowVector(numOrigRows);
for(int i = objRowVector.size() - 1; i >= 0; i--)
{
_rationalLP->changeMaxObj(objRowVector.index(i), objRowVector.value(i));
_realLP->changeMaxObj(objRowVector.index(i), R(objRowVector.value(i)));
}
_rationalLP->removeRow(numOrigRows);
_realLP->removeRow(numOrigRows);
_rowTypes.reSize(numOrigRows);
_rationalLP->removeCol(numOrigCols);
_realLP->removeCol(numOrigCols);
_colTypes.reSize(numOrigCols);
for(int r = numRowsRational() - 1; r >= 0; r--)
{
if(_lowerFinite(_rowTypes[r]))
{
_rationalLP->changeLhs(r, _unboundedLhs[r]);
_realLP->changeLhs(r, R(_unboundedLhs[r]));
}
if(_upperFinite(_rowTypes[r]))
{
_rationalLP->changeRhs(r, _unboundedRhs[r]);
_realLP->changeRhs(r, R(_unboundedRhs[r]));
}
assert((lhsRational(r) > _rationalNegInfty) == _lowerFinite(_rowTypes[r]));
assert((rhsRational(r) < _rationalPosInfty) == _upperFinite(_rowTypes[r]));
assert((lhsReal(r) > -realParam(SoPlexBase<R>::INFTY)) == _lowerFinite(_rowTypes[r]));
assert((rhsReal(r) < realParam(SoPlexBase<R>::INFTY)) == _upperFinite(_rowTypes[r]));
}
for(int c = numColsRational() - 1; c >= 0; c--)
{
if(_lowerFinite(_colTypes[c]))
{
_rationalLP->changeLower(c, _unboundedLower[c]);
_realLP->changeLower(c, R(_unboundedLower[c]));
}
if(_upperFinite(_colTypes[c]))
{
_rationalLP->changeUpper(c, _unboundedUpper[c]);
_realLP->changeUpper(c, R(_unboundedUpper[c]));
}
assert((lowerRational(c) > _rationalNegInfty) == _lowerFinite(_colTypes[c]));
assert((upperRational(c) < _rationalPosInfty) == _upperFinite(_colTypes[c]));
assert((lowerReal(c) > -realParam(SoPlexBase<R>::INFTY)) == _lowerFinite(_colTypes[c]));
assert((upperReal(c) < realParam(SoPlexBase<R>::INFTY)) == _upperFinite(_colTypes[c]));
}
_rationalLUSolver.clear();
MSG_DEBUG(_realLP->writeFileLPBase("afterUntransUnbounded.lp", 0, 0, 0));
_statistics->transformTime->stop();
}
template <class R>
void SoPlexBase<R>::_storeBasis()
{
assert(!_storedBasis);
if(_hasBasis)
{
_storedBasis = true;
_storedBasisStatusCols = _basisStatusCols;
_storedBasisStatusRows = _basisStatusRows;
}
else
_storedBasis = false;
}
template <class R>
void SoPlexBase<R>::_restoreBasis()
{
if(_storedBasis)
{
_hasBasis = true;
_basisStatusCols = _storedBasisStatusCols;
_basisStatusRows = _storedBasisStatusRows;
_storedBasis = false;
}
}
template <class R>
void SoPlexBase<R>::_transformFeasibility()
{
MSG_INFO1(spxout, spxout << "Setting up LP to test for feasibility.\n");
_statistics->transformTime->start();
MSG_DEBUG(_realLP->writeFileLPBase("beforeTransFeas.lp", 0, 0, 0));
_feasObj.reDim(numColsRational());
for(int c = numColsRational() - 1; c >= 0; c--)
_feasObj[c] = _rationalLP->maxObj(c);
_feasLower.reDim(numColsRational());
_feasUpper.reDim(numColsRational());
for(int c = numColsRational() - 1; c >= 0; c--)
{
if(_lowerFinite(_colTypes[c]))
_feasLower[c] = lowerRational(c);
if(_upperFinite(_colTypes[c]))
_feasUpper[c] = upperRational(c);
}
_feasLhs.reDim(numRowsRational());
_feasRhs.reDim(numRowsRational());
for(int r = numRowsRational() - 1; r >= 0; r--)
{
if(_lowerFinite(_rowTypes[r]))
_feasLhs[r] = lhsRational(r);
if(_upperFinite(_rowTypes[r]))
_feasRhs[r] = rhsRational(r);
}
Rational shiftValue;
Rational shiftValue2;
for(int c = numColsRational() - 1; c >= 0; c--)
{
_rationalLP->changeMaxObj(c, Rational(0));
_realLP->changeMaxObj(c, R(0.0));
if(lowerRational(c) > 0)
{
const SVectorRational& colVector = colVectorRational(c);
for(int i = 0; i < colVector.size(); i++)
{
shiftValue = colVector.value(i);
shiftValue *= lowerRational(c);
int r = colVector.index(i);
assert((lhsRational(r) > _rationalNegInfty) == _lowerFinite(_rowTypes[r]));
assert((rhsRational(r) < _rationalPosInfty) == _upperFinite(_rowTypes[r]));
if(_lowerFinite(_rowTypes[r]) && _upperFinite(_rowTypes[r]))
{
shiftValue2 = lhsRational(r);
shiftValue2 -= shiftValue;
_rationalLP->changeLhs(r, shiftValue2);
_realLP->changeLhs(r, R(shiftValue2));
shiftValue -= rhsRational(r);
shiftValue *= -1;
_rationalLP->changeRhs(r, shiftValue);
_realLP->changeRhs(r, R(shiftValue));
}
else if(_lowerFinite(_rowTypes[r]))
{
shiftValue -= lhsRational(r);
shiftValue *= -1;
_rationalLP->changeLhs(r, shiftValue);
_realLP->changeLhs(r, R(shiftValue));
}
else if(_upperFinite(_rowTypes[r]))
{
shiftValue -= rhsRational(r);
shiftValue *= -1;
_rationalLP->changeRhs(r, shiftValue);
_realLP->changeRhs(r, R(shiftValue));
}
}
assert((upperRational(c) < _rationalPosInfty) == _upperFinite(_colTypes[c]));
if(_upperFinite(_colTypes[c]))
{
_rationalLP->changeBounds(c, 0, upperRational(c) - lowerRational(c));
_realLP->changeBounds(c, 0.0, R(upperRational(c)));
}
else if(_realLP->upper(c) < realParam(SoPlexBase<R>::INFTY))
{
_rationalLP->changeLower(c, Rational(0));
_realLP->changeBounds(c, 0.0, realParam(SoPlexBase<R>::INFTY));
}
else
{
_rationalLP->changeLower(c, Rational(0));
_realLP->changeLower(c, R(0.0));
}
}
else if(upperRational(c) < 0)
{
const SVectorRational& colVector = colVectorRational(c);
for(int i = 0; i < colVector.size(); i++)
{
shiftValue = colVector.value(i);
shiftValue *= upperRational(c);
int r = colVector.index(i);
assert((lhsRational(r) > _rationalNegInfty) == _lowerFinite(_rowTypes[r]));
assert((rhsRational(r) < _rationalPosInfty) == _upperFinite(_rowTypes[r]));
if(_lowerFinite(_rowTypes[r]) && _upperFinite(_rowTypes[r]))
{
shiftValue2 = lhsRational(r);
shiftValue2 -= shiftValue;
_rationalLP->changeLhs(r, shiftValue2);
_realLP->changeLhs(r, R(shiftValue2));
shiftValue -= rhsRational(r);
shiftValue *= -1;
_rationalLP->changeRhs(r, shiftValue);
_realLP->changeRhs(r, R(shiftValue));
}
else if(_lowerFinite(_rowTypes[r]))
{
shiftValue -= lhsRational(r);
shiftValue *= -1;
_rationalLP->changeLhs(r, shiftValue);
_realLP->changeLhs(r, R(shiftValue));
}
else if(_upperFinite(_rowTypes[r]))
{
shiftValue -= rhsRational(r);
shiftValue *= -1;
_rationalLP->changeRhs(r, shiftValue);
_realLP->changeRhs(r, R(shiftValue));
}
}
assert((lowerRational(c) > _rationalNegInfty) == _lowerFinite(_colTypes[c]));
if(_lowerFinite(_colTypes[c]))
{
_rationalLP->changeBounds(c, lowerRational(c) - upperRational(c), 0);
_realLP->changeBounds(c, R(lowerRational(c)), 0.0);
}
else if(_realLP->lower(c) > -realParam(SoPlexBase<R>::INFTY))
{
_rationalLP->changeUpper(c, Rational(0));
_realLP->changeBounds(c, -realParam(SoPlexBase<R>::INFTY), 0.0);
}
else
{
_rationalLP->changeUpper(c, Rational(0));
_realLP->changeUpper(c, R(0.0));
}
}
else
{
if(_lowerFinite(_colTypes[c]))
_realLP->changeLower(c, R(lowerRational(c)));
else if(_realLP->lower(c) > -realParam(SoPlexBase<R>::INFTY))
_realLP->changeLower(c, -realParam(SoPlexBase<R>::INFTY));
if(_upperFinite(_colTypes[c]))
_realLP->changeUpper(c, R(upperRational(c)));
else if(_realLP->upper(c) < realParam(SoPlexBase<R>::INFTY))
_realLP->changeUpper(c, realParam(SoPlexBase<R>::INFTY));
}
assert(lowerReal(c) <= upperReal(c));
}
_tauColVector.clear();
for(int r = numRowsRational() - 1; r >= 0; r--)
{
if(lhsRational(r) > 0)
{
_tauColVector.add(r, lhsRational(r));
assert((rhsRational(r) < _rationalPosInfty) == _upperFinite(_rowTypes[r]));
if(_upperFinite(_rowTypes[r]))
{
_rationalLP->changeRange(r, 0, rhsRational(r) - lhsRational(r));
_realLP->changeRange(r, 0.0, R(rhsRational(r)));
}
else
{
_rationalLP->changeLhs(r, Rational(0));
_realLP->changeLhs(r, R(0.0));
if(_realLP->rhs(r) < realParam(SoPlexBase<R>::INFTY))
_realLP->changeRhs(r, realParam(SoPlexBase<R>::INFTY));
}
}
else if(rhsRational(r) < 0)
{
_tauColVector.add(r, rhsRational(r));
assert((lhsRational(r) > _rationalNegInfty) == _lowerFinite(_rowTypes[r]));
if(_lowerFinite(_rowTypes[r]))
{
_rationalLP->changeRange(r, lhsRational(r) - rhsRational(r), 0);
_realLP->changeRange(r, R(lhsRational(r)), 0.0);
}
else
{
_rationalLP->changeRhs(r, Rational(0));
_realLP->changeRhs(r, R(0.0));
if(_realLP->lhs(r) > -realParam(SoPlexBase<R>::INFTY))
_realLP->changeLhs(r, -realParam(SoPlexBase<R>::INFTY));
}
}
else
{
if(_lowerFinite(_rowTypes[r]))
_realLP->changeLhs(r, R(lhsRational(r)));
else if(_realLP->lhs(r) > -realParam(SoPlexBase<R>::INFTY))
_realLP->changeLhs(r, -realParam(SoPlexBase<R>::INFTY));
if(_upperFinite(_rowTypes[r]))
_realLP->changeRhs(r, R(rhsRational(r)));
else if(_realLP->rhs(r) < realParam(SoPlexBase<R>::INFTY))
_realLP->changeRhs(r, realParam(SoPlexBase<R>::INFTY));
}
assert(rhsReal(r) <= rhsReal(r));
}
if(_tauColVector.size() == 0)
{
MSG_INFO3(spxout, spxout << "LP is trivially feasible.\n");
}
SPxColId id;
_tauColVector *= -1;
_rationalLP->addCol(id,
LPColRational((intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MAXIMIZE ?
_rationalPosone : _rationalNegone),
_tauColVector, 1, 0));
_realLP->addCol(id,
LPColBase<R>((intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MAXIMIZE ? 1.0 : -1.0),
DSVectorBase<R>(_tauColVector), 1.0, 0.0));
_colTypes.append(RANGETYPE_BOXED);
if(_hasBasis)
{
_basisStatusCols.append(SPxSolverBase<R>::ON_UPPER);
}
_rationalLUSolver.clear();
MSG_DEBUG(_realLP->writeFileLPBase("afterTransFeas.lp", 0, 0, 0));
_statistics->transformTime->stop();
}
template <class R>
void SoPlexBase<R>::_untransformFeasibility(SolRational& sol, bool infeasible)
{
_statistics->transformTime->start();
MSG_DEBUG(_realLP->writeFileLPBase("beforeUntransFeas.lp", 0, 0, 0));
int numOrigCols = numColsRational() - 1;
if(infeasible)
{
assert(sol._isDualFeasible);
assert(sol._primal[numOrigCols] < 1);
sol._isPrimalFeasible = false;
sol._hasPrimalRay = false;
sol._isDualFeasible = false;
sol._hasDualFarkas = true;
sol._dualFarkas = sol._dual;
_hasBasis = false;
_basisStatusCols.reSize(numOrigCols);
}
else if(sol._isPrimalFeasible)
{
assert(sol._primal[numOrigCols] >= 1);
sol._hasPrimalRay = false;
sol._isDualFeasible = false;
sol._hasDualFarkas = false;
if(sol._primal[numOrigCols] != 1)
{
sol._slacks /= sol._primal[numOrigCols];
for(int i = 0; i < numOrigCols; i++)
sol._primal[i] /= sol._primal[numOrigCols];
sol._primal[numOrigCols] = 1;
}
sol._primal.reDim(numOrigCols);
sol._slacks -= _rationalLP->colVector(numOrigCols);
_hasBasis = (_basisStatusCols[numOrigCols] != SPxSolverBase<R>::BASIC);
_basisStatusCols.reSize(numOrigCols);
}
else
{
_hasBasis = false;
_basisStatusCols.reSize(numOrigCols);
}
for(int r = numRowsRational() - 1; r >= 0; r--)
{
assert(rhsRational(r) >= _rationalPosInfty || lhsRational(r) <= _rationalNegInfty
|| _feasLhs[r] - lhsRational(r) == _feasRhs[r] - rhsRational(r));
if(_lowerFinite(_rowTypes[r]))
{
_rationalLP->changeLhs(r, _feasLhs[r]);
_realLP->changeLhs(r, R(_feasLhs[r]));
}
else if(_realLP->lhs(r) > -realParam(SoPlexBase<R>::INFTY))
_realLP->changeLhs(r, -realParam(SoPlexBase<R>::INFTY));
assert(_lowerFinite(_rowTypes[r]) == (lhsRational(r) > _rationalNegInfty));
assert(_lowerFinite(_rowTypes[r]) == (lhsReal(r) > -realParam(SoPlexBase<R>::INFTY)));
if(_upperFinite(_rowTypes[r]))
{
_rationalLP->changeRhs(r, _feasRhs[r]);
_realLP->changeRhs(r, R(_feasRhs[r]));
}
else if(_realLP->rhs(r) < realParam(SoPlexBase<R>::INFTY))
_realLP->changeRhs(r, realParam(SoPlexBase<R>::INFTY));
assert(_upperFinite(_rowTypes[r]) == (rhsRational(r) < _rationalPosInfty));
assert(_upperFinite(_rowTypes[r]) == (rhsReal(r) < realParam(SoPlexBase<R>::INFTY)));
assert(lhsReal(r) <= rhsReal(r));
}
Rational shiftValue;
for(int c = numOrigCols - 1; c >= 0; c--)
{
bool shifted = (_lowerFinite(_colTypes[c]) && _feasLower[c] > 0) || (_upperFinite(_colTypes[c])
&& _feasUpper[c] < 0);
assert(shifted || !_lowerFinite(_colTypes[c]) || _feasLower[c] == lowerRational(c));
assert(shifted || !_upperFinite(_colTypes[c]) || _feasUpper[c] == upperRational(c));
assert(upperRational(c) >= _rationalPosInfty || lowerRational(c) <= _rationalNegInfty
|| _feasLower[c] - lowerRational(c) == _feasUpper[c] - upperRational(c));
if(shifted)
{
if(_lowerFinite(_colTypes[c]))
{
shiftValue = _feasLower[c];
shiftValue -= lowerRational(c);
}
else if(_upperFinite(_colTypes[c]))
{
shiftValue = _feasUpper[c];
shiftValue -= upperRational(c);
}
if(sol._isPrimalFeasible)
{
sol._primal[c] += shiftValue;
sol._slacks.multAdd(shiftValue, _rationalLP->colVector(c));
}
}
if(_lowerFinite(_colTypes[c]))
{
if(shifted)
_rationalLP->changeLower(c, _feasLower[c]);
_realLP->changeLower(c, R(_feasLower[c]));
}
else if(_realLP->lower(c) > -realParam(SoPlexBase<R>::INFTY))
_realLP->changeLower(c, -realParam(SoPlexBase<R>::INFTY));
assert(_lowerFinite(_colTypes[c]) == (lowerRational(c) > -_rationalPosInfty));
assert(_lowerFinite(_colTypes[c]) == (lowerReal(c) > -realParam(SoPlexBase<R>::INFTY)));
if(_upperFinite(_colTypes[c]))
{
if(shifted)
_rationalLP->changeUpper(c, _feasUpper[c]);
_realLP->changeUpper(c, R(upperRational(c)));
}
else if(_realLP->upper(c) < realParam(SoPlexBase<R>::INFTY))
_realLP->changeUpper(c, realParam(SoPlexBase<R>::INFTY));
assert(_upperFinite(_colTypes[c]) == (upperRational(c) < _rationalPosInfty));
assert(_upperFinite(_colTypes[c]) == (upperReal(c) < realParam(SoPlexBase<R>::INFTY)));
_rationalLP->changeMaxObj(c, _feasObj[c]);
_realLP->changeMaxObj(c, R(_feasObj[c]));
assert(lowerReal(c) <= upperReal(c));
}
_rationalLP->removeCol(numOrigCols);
_realLP->removeCol(numOrigCols);
_colTypes.reSize(numOrigCols);
_rationalLUSolver.clear();
MSG_DEBUG(_realLP->writeFileLPBase("afterUntransFeas.lp", 0, 0, 0));
_statistics->transformTime->stop();
#ifndef NDEBUG
if(sol._isPrimalFeasible)
{
VectorRational activity(numRowsRational());
_rationalLP->computePrimalActivity(sol._primal, activity);
assert(sol._slacks == activity);
}
#endif
}
template <class R>
void SoPlexBase<R>::_computeInfeasBox(SolRational& sol, bool transformed)
{
assert(sol.hasDualFarkas());
const VectorRational& lower = transformed ? _feasLower : lowerRational();
const VectorRational& upper = transformed ? _feasUpper : upperRational();
const VectorRational& lhs = transformed ? _feasLhs : lhsRational();
const VectorRational& rhs = transformed ? _feasRhs : rhsRational();
const VectorRational& y = sol._dualFarkas;
const int numRows = numRowsRational();
const int numCols = transformed ? numColsRational() - 1 : numColsRational();
SSVectorRational ytransA(numColsRational());
Rational ytransb;
Rational temp;
ytransA.setEpsilon(0);
ytransA.clear();
ytransb = 0;
for(int r = 0; r < numRows; r++)
{
ytransA += y[r] * _rationalLP->rowVector(r);
ytransb += y[r] * (y[r] > 0 ? lhs[r] : rhs[r]);
}
if(transformed)
ytransA.reDim(numCols);
MSG_DEBUG(std::cout << "ytransb = " << ytransb.str() << "\n");
temp = 0;
bool isTempFinite = true;
for(int c = 0; c < numCols && isTempFinite; c++)
{
const Rational& minusRedCost = ytransA[c];
if(minusRedCost > 0)
{
assert((upper[c] < _rationalPosInfty) == _upperFinite(_colTypes[c]));
if(_upperFinite(_colTypes[c]))
temp += minusRedCost * upper[c];
else
isTempFinite = false;
}
else if(minusRedCost < 0)
{
assert((lower[c] > _rationalNegInfty) == _lowerFinite(_colTypes[c]));
if(_lowerFinite(_colTypes[c]))
temp += minusRedCost * lower[c];
else
isTempFinite = false;
}
}
MSG_DEBUG(std::cout << "max ytransA*[x_l,x_u] = " << (isTempFinite ? temp.str() : "infinite") <<
"\n");
if(isTempFinite && temp < ytransb)
{
MSG_INFO1(spxout, spxout << "Farkas infeasibility proof verified exactly. (1)\n");
return;
}
assert(ytransA.isSetup());
ytransA.setup();
if(ytransb < 0)
{
for(int c = 0; c < numCols; c++)
{
if(lower[c] > 0)
{
ytransA.setValue(c, ytransA[c] - ytransb / lower[c]);
ytransb = 0;
break;
}
else if(upper[c] < 0)
{
ytransA.setValue(c, ytransA[c] - ytransb / upper[c]);
ytransb = 0;
break;
}
}
}
if(ytransb < 0)
{
MSG_INFO1(spxout, spxout <<
"Approximate Farkas proof to weak. Could not compute Farkas box. (1)\n");
return;
}
temp = 0;
const int size = ytransA.size();
for(int n = 0; n < size; n++)
temp += spxAbs(ytransA.value(n));
assert(temp != 0);
Rational B = ytransb / temp;
bool success = false;
int n = 0;
MSG_DEBUG(std::cout << "B = " << B.str() << "\n");
assert(ytransb >= 0);
while(true)
{
if(n >= ytransA.size())
{
if(!success)
break;
success = false;
n = 0;
}
const Rational& minusRedCost = ytransA.value(n);
int colIdx = ytransA.index(n);
assert((upper[colIdx] < _rationalPosInfty) == _upperFinite(_colTypes[colIdx]));
assert((lower[colIdx] > _rationalNegInfty) == _lowerFinite(_colTypes[colIdx]));
if(minusRedCost < 0 && lower[colIdx] > -B && _lowerFinite(_colTypes[colIdx]))
{
ytransA.clearNum(n);
ytransb -= minusRedCost * lower[colIdx];
temp += minusRedCost;
assert(ytransb >= 0);
assert(temp >= 0);
assert(temp == 0 || ytransb / temp > B);
if(temp == 0 && ytransb == 0)
{
MSG_INFO1(spxout, spxout <<
"Approximate Farkas proof to weak. Could not compute Farkas box. (2)\n");
return;
}
else if(temp == 0)
{
assert(ytransb > 0);
MSG_INFO1(spxout, spxout << "Farkas infeasibility proof verified exactly. (2)\n");
return;
}
else
{
B = ytransb / temp;
MSG_DEBUG(std::cout << "B = " << B.str() << "\n");
}
success = true;
}
else if(minusRedCost > 0 && upper[colIdx] < B && _upperFinite(_colTypes[colIdx]))
{
ytransA.clearNum(n);
ytransb -= minusRedCost * upper[colIdx];
temp -= minusRedCost;
assert(ytransb >= 0);
assert(temp >= 0);
assert(temp == 0 || ytransb / temp > B);
if(temp == 0 && ytransb == 0)
{
MSG_INFO1(spxout, spxout <<
"Approximate Farkas proof to weak. Could not compute Farkas box. (2)\n");
return;
}
else if(temp == 0)
{
assert(ytransb > 0);
MSG_INFO1(spxout, spxout << "Farkas infeasibility proof verified exactly. (2)\n");
return;
}
else
{
B = ytransb / temp;
MSG_DEBUG(std::cout << "B = " << B.str() << "\n");
}
success = true;
}
else if(minusRedCost == 0)
ytransA.clearNum(n);
else
n++;
}
if(B > 0)
{
MSG_INFO1(spxout, spxout <<
"Computed Farkas box: provably no feasible solutions with components less than "
<< B.str() << " in absolute value.\n");
}
}
template <class R>
typename SPxSolverBase<R>::Status SoPlexBase<R>::_solveRealForRational(bool fromscratch,
VectorBase<R>& primal, VectorBase<R>& dual,
DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusRows,
DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusCols)
{
assert(_isConsistent());
assert(_solver.nRows() == numRowsRational());
assert(_solver.nCols() == numColsRational());
assert(primal.dim() == numColsRational());
assert(dual.dim() == numRowsRational());
typename SPxSolverBase<R>::Status result = SPxSolverBase<R>::UNKNOWN;
#ifndef SOPLEX_MANUAL_ALT
if(fromscratch || !_hasBasis)
_enableSimplifierAndScaler();
else
_disableSimplifierAndScaler();
#else
_disableSimplifierAndScaler();
#endif
if(fromscratch)
_solver.reLoad();
_statistics->syncTime->start();
SPxLPRational* rationalLP = 0;
if(_simplifier != 0 || _scaler != nullptr)
{
spx_alloc(rationalLP);
rationalLP = new(rationalLP) SPxLPRational(_solver);
}
if(_simplifier != nullptr || _scaler != nullptr || fromscratch)
_rationalLUSolver.clear();
_statistics->syncTime->stop();
try
{
typename SPxSimplifier<R>::Result simplificationStatus = SPxSimplifier<R>::OKAY;
if(_simplifier != 0)
{
bool keepbounds = intParam(SoPlexBase<R>::RATIOTESTER) == SoPlexBase<R>::RATIOTESTER_BOUNDFLIPPING;
Real remainingTime = _solver.getMaxTime() - _solver.time();
simplificationStatus = _simplifier->simplify(_solver, realParam(SoPlexBase<R>::EPSILON_ZERO),
realParam(SoPlexBase<R>::FPFEASTOL), realParam(SoPlexBase<R>::FPOPTTOL), remainingTime, keepbounds,
_solver.random.getSeed());
}
if(_scaler != nullptr && simplificationStatus == SPxSimplifier<R>::OKAY)
_scaler->scale(_solver, false);
if(simplificationStatus == SPxSimplifier<R>::OKAY)
{
MSG_INFO1(spxout, spxout << std::endl);
_solveRealLPAndRecordStatistics();
MSG_INFO1(spxout, spxout << std::endl);
}
if(simplificationStatus == SPxSimplifier<R>::INFEASIBLE)
result = SPxSolverBase<R>::INFEASIBLE;
else if(simplificationStatus == SPxSimplifier<R>::DUAL_INFEASIBLE)
result = SPxSolverBase<R>::INForUNBD;
else if(simplificationStatus == SPxSimplifier<R>::UNBOUNDED)
result = SPxSolverBase<R>::UNBOUNDED;
else if(simplificationStatus == SPxSimplifier<R>::VANISHED
|| simplificationStatus == SPxSimplifier<R>::OKAY)
{
result = simplificationStatus == SPxSimplifier<R>::VANISHED ? SPxSolverBase<R>::OPTIMAL :
_solver.status();
switch(result)
{
case SPxSolverBase<R>::OPTIMAL:
if(_simplifier != 0)
{
assert(!_simplifier->isUnsimplified());
assert(simplificationStatus == SPxSimplifier<R>::VANISHED
|| simplificationStatus == SPxSimplifier<R>::OKAY);
bool vanished = simplificationStatus == SPxSimplifier<R>::VANISHED;
VectorBase<R> tmpPrimal(vanished ? 0 : _solver.nCols());
VectorBase<R> tmpSlacks(vanished ? 0 : _solver.nRows());
VectorBase<R> tmpDual(vanished ? 0 : _solver.nRows());
VectorBase<R> tmpRedCost(vanished ? 0 : _solver.nCols());
if(!vanished)
{
assert(_solver.status() == SPxSolverBase<R>::OPTIMAL);
_solver.getPrimalSol(tmpPrimal);
_solver.getSlacks(tmpSlacks);
_solver.getDualSol(tmpDual);
_solver.getRedCostSol(tmpRedCost);
if(_scaler != nullptr)
{
_scaler->unscalePrimal(_solver, tmpPrimal);
_scaler->unscaleSlacks(_solver, tmpSlacks);
_scaler->unscaleDual(_solver, tmpDual);
_scaler->unscaleRedCost(_solver, tmpRedCost);
}
basisStatusRows.reSize(_solver.nRows());
basisStatusCols.reSize(_solver.nCols());
_solver.getBasis(basisStatusRows.get_ptr(), basisStatusCols.get_ptr(), basisStatusRows.size(),
basisStatusCols.size());
}
_simplifier->unsimplify(tmpPrimal, tmpDual, tmpSlacks, tmpRedCost, basisStatusRows.get_ptr(),
basisStatusCols.get_ptr());
basisStatusRows.reSize(numRowsRational());
basisStatusCols.reSize(numColsRational());
_simplifier->getBasis(basisStatusRows.get_ptr(), basisStatusCols.get_ptr(), basisStatusRows.size(),
basisStatusCols.size());
_hasBasis = true;
primal = _simplifier->unsimplifiedPrimal();
dual = _simplifier->unsimplifiedDual();
}
else
{
_solver.getPrimalSol(primal);
_solver.getDualSol(dual);
if(_scaler != nullptr)
{
_scaler->unscalePrimal(_solver, primal);
_scaler->unscaleDual(_solver, dual);
}
basisStatusRows.reSize(_solver.nRows());
basisStatusCols.reSize(_solver.nCols());
_solver.getBasis(basisStatusRows.get_ptr(), basisStatusCols.get_ptr(), basisStatusRows.size(),
basisStatusCols.size());
_hasBasis = true;
}
break;
case SPxSolverBase<R>::ABORT_CYCLING:
if(_simplifier == 0 && boolParam(SoPlexBase<R>::ACCEPTCYCLING))
{
_solver.getPrimalSol(primal);
_solver.getDualSol(dual);
if(_scaler != nullptr)
{
_scaler->unscalePrimal(_solver, primal);
_scaler->unscaleDual(_solver, dual);
}
}
case SPxSolverBase<R>::ABORT_TIME:
case SPxSolverBase<R>::ABORT_ITER:
case SPxSolverBase<R>::ABORT_VALUE:
case SPxSolverBase<R>::REGULAR:
case SPxSolverBase<R>::RUNNING:
case SPxSolverBase<R>::UNBOUNDED:
_hasBasis = (_solver.basis().status() > SPxBasisBase<R>::NO_PROBLEM);
if(_hasBasis && _simplifier == 0)
{
basisStatusRows.reSize(_solver.nRows());
basisStatusCols.reSize(_solver.nCols());
_solver.getBasis(basisStatusRows.get_ptr(), basisStatusCols.get_ptr(), basisStatusRows.size(),
basisStatusCols.size());
}
else
{
_hasBasis = false;
_rationalLUSolver.clear();
}
break;
case SPxSolverBase<R>::INFEASIBLE:
if(_simplifier != 0)
{
_hasBasis = false;
_rationalLUSolver.clear();
break;
}
_solver.getDualfarkas(dual);
if(_scaler != nullptr)
_scaler->unscaleDual(_solver, dual);
basisStatusRows.reSize(_solver.nRows());
basisStatusCols.reSize(_solver.nCols());
_solver.getBasis(basisStatusRows.get_ptr(), basisStatusCols.get_ptr(), basisStatusRows.size(),
basisStatusCols.size());
_hasBasis = true;
break;
case SPxSolverBase<R>::INForUNBD:
case SPxSolverBase<R>::SINGULAR:
default:
_hasBasis = false;
_rationalLUSolver.clear();
break;
}
}
}
catch(...)
{
MSG_INFO1(spxout, spxout << "Exception thrown during floating-point solve.\n");
result = SPxSolverBase<R>::ERROR;
_hasBasis = false;
_rationalLUSolver.clear();
}
if(_simplifier != 0 || _scaler != nullptr)
{
assert(rationalLP != 0);
_solver.loadLP((SPxLPBase<R>)(*rationalLP));
rationalLP->~SPxLPRational();
spx_free(rationalLP);
if(_hasBasis)
_solver.setBasis(basisStatusRows.get_ptr(), basisStatusCols.get_ptr());
}
return result;
}
template <class R>
typename SPxSolverBase<R>::Status SoPlexBase<R>::_solveRealStable(bool acceptUnbounded,
bool acceptInfeasible, VectorBase<R>& primal, VectorBase<R>& dual,
DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusRows,
DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusCols,
const bool forceNoSimplifier)
{
typename SPxSolverBase<R>::Status result = SPxSolverBase<R>::UNKNOWN;
bool fromScratch = false;
bool solved = false;
bool solvedFromScratch = false;
bool initialSolve = true;
bool increasedMarkowitz = false;
bool relaxedTolerances = false;
bool tightenedTolerances = false;
bool switchedScaler = false;
bool switchedSimplifier = false;
bool switchedRatiotester = false;
bool switchedPricer = false;
bool turnedoffPre = false;
R markowitz = _slufactor.markowitz();
int ratiotester = intParam(SoPlexBase<R>::RATIOTESTER);
int pricer = intParam(SoPlexBase<R>::PRICER);
int simplifier = intParam(SoPlexBase<R>::SIMPLIFIER);
int scaler = intParam(SoPlexBase<R>::SCALER);
int type = intParam(SoPlexBase<R>::ALGORITHM);
if(forceNoSimplifier)
setIntParam(SoPlexBase<R>::SIMPLIFIER, SoPlexBase<R>::SIMPLIFIER_OFF);
while(true)
{
assert(!increasedMarkowitz || GE(_slufactor.markowitz(), R(0.9)));
result = _solveRealForRational(fromScratch, primal, dual, basisStatusRows, basisStatusCols);
solved = (result == SPxSolverBase<R>::OPTIMAL)
|| (result == SPxSolverBase<R>::INFEASIBLE && acceptInfeasible)
|| (result == SPxSolverBase<R>::UNBOUNDED && acceptUnbounded);
if(solved || result == SPxSolverBase<R>::ABORT_TIME || result == SPxSolverBase<R>::ABORT_ITER)
break;
if(initialSolve)
{
MSG_INFO1(spxout, spxout << "Numerical troubles during floating-point solve." << std::endl);
initialSolve = false;
}
if(!turnedoffPre
&& (intParam(SoPlexBase<R>::SIMPLIFIER) != SoPlexBase<R>::SIMPLIFIER_OFF
|| intParam(SoPlexBase<R>::SCALER) != SoPlexBase<R>::SCALER_OFF))
{
MSG_INFO1(spxout, spxout << "Turning off preprocessing." << std::endl);
turnedoffPre = true;
setIntParam(SoPlexBase<R>::SCALER, SoPlexBase<R>::SCALER_OFF);
setIntParam(SoPlexBase<R>::SIMPLIFIER, SoPlexBase<R>::SIMPLIFIER_OFF);
fromScratch = true;
solvedFromScratch = true;
continue;
}
setIntParam(SoPlexBase<R>::SCALER, scaler);
setIntParam(SoPlexBase<R>::SIMPLIFIER, simplifier);
if(!increasedMarkowitz)
{
MSG_INFO1(spxout, spxout << "Increasing Markowitz threshold." << std::endl);
_slufactor.setMarkowitz(0.9);
increasedMarkowitz = true;
try
{
_solver.factorize();
continue;
}
catch(...)
{
MSG_DEBUG(std::cout << std::endl << "Factorization failed." << std::endl);
}
}
if(!solvedFromScratch)
{
MSG_INFO1(spxout, spxout << "Solving from scratch." << std::endl);
fromScratch = true;
solvedFromScratch = true;
continue;
}
setIntParam(SoPlexBase<R>::RATIOTESTER, ratiotester);
setIntParam(SoPlexBase<R>::PRICER, pricer);
if(!switchedScaler)
{
MSG_INFO1(spxout, spxout << "Switching scaling." << std::endl);
if(scaler == int(SoPlexBase<R>::SCALER_OFF))
setIntParam(SoPlexBase<R>::SCALER, SoPlexBase<R>::SCALER_BIEQUI);
else
setIntParam(SoPlexBase<R>::SCALER, SoPlexBase<R>::SCALER_OFF);
fromScratch = true;
solvedFromScratch = true;
switchedScaler = true;
continue;
}
if(!switchedSimplifier && !forceNoSimplifier)
{
MSG_INFO1(spxout, spxout << "Switching simplification." << std::endl);
if(simplifier == int(SoPlexBase<R>::SIMPLIFIER_OFF))
setIntParam(SoPlexBase<R>::SIMPLIFIER, SoPlexBase<R>::SIMPLIFIER_INTERNAL);
else
setIntParam(SoPlexBase<R>::SIMPLIFIER, SoPlexBase<R>::SIMPLIFIER_OFF);
fromScratch = true;
solvedFromScratch = true;
switchedSimplifier = true;
continue;
}
setIntParam(SoPlexBase<R>::SIMPLIFIER, SoPlexBase<R>::SIMPLIFIER_OFF);
if(!relaxedTolerances)
{
MSG_INFO1(spxout, spxout << "Relaxing tolerances." << std::endl);
setIntParam(SoPlexBase<R>::ALGORITHM, SoPlexBase<R>::ALGORITHM_PRIMAL);
_solver.setDelta((_solver.feastol() * 1e3 > 1e-3) ? 1e-3 : (_solver.feastol() * 1e3));
relaxedTolerances = _solver.feastol() >= 1e-3;
solvedFromScratch = false;
continue;
}
if(!tightenedTolerances && result != SPxSolverBase<R>::INFEASIBLE)
{
MSG_INFO1(spxout, spxout << "Tightening tolerances." << std::endl);
setIntParam(SoPlexBase<R>::ALGORITHM, SoPlexBase<R>::ALGORITHM_DUAL);
_solver.setDelta(_solver.feastol() * 1e-3 < 1e-9 ? 1e-9 : _solver.feastol() * 1e-3);
tightenedTolerances = _solver.feastol() <= 1e-9;
solvedFromScratch = false;
continue;
}
setIntParam(SoPlexBase<R>::ALGORITHM, type);
if(!switchedRatiotester)
{
MSG_INFO1(spxout, spxout << "Switching ratio test." << std::endl);
_solver.setType(_solver.type() == SPxSolverBase<R>::LEAVE ? SPxSolverBase<R>::ENTER :
SPxSolverBase<R>::LEAVE);
if(_solver.ratiotester() != (SPxRatioTester<R>*)&_ratiotesterTextbook)
setIntParam(SoPlexBase<R>::RATIOTESTER, RATIOTESTER_TEXTBOOK);
else
setIntParam(SoPlexBase<R>::RATIOTESTER, RATIOTESTER_FAST);
switchedRatiotester = true;
solvedFromScratch = false;
continue;
}
if(!switchedPricer)
{
MSG_INFO1(spxout, spxout << "Switching pricer." << std::endl);
_solver.setType(_solver.type() == SPxSolverBase<R>::LEAVE ? SPxSolverBase<R>::ENTER :
SPxSolverBase<R>::LEAVE);
if(_solver.pricer() != (SPxPricer<R>*)&_pricerDevex)
setIntParam(SoPlexBase<R>::PRICER, PRICER_DEVEX);
else
setIntParam(SoPlexBase<R>::PRICER, PRICER_STEEP);
switchedPricer = true;
solvedFromScratch = false;
continue;
}
MSG_INFO1(spxout, spxout << "Giving up." << std::endl);
break;
}
_solver.setFeastol(realParam(SoPlexBase<R>::FPFEASTOL));
_solver.setOpttol(realParam(SoPlexBase<R>::FPOPTTOL));
_slufactor.setMarkowitz(markowitz);
setIntParam(SoPlexBase<R>::RATIOTESTER, ratiotester);
setIntParam(SoPlexBase<R>::PRICER, pricer);
setIntParam(SoPlexBase<R>::SIMPLIFIER, simplifier);
setIntParam(SoPlexBase<R>::SCALER, scaler);
setIntParam(SoPlexBase<R>::ALGORITHM, type);
return result;
}
template <class R>
void SoPlexBase<R>::_computeBasisInverseRational()
{
assert(_rationalLUSolver.status() == SLinSolverRational::UNLOADED
|| _rationalLUSolver.status() == SLinSolverRational::TIME);
const int matrixdim = numRowsRational();
assert(_rationalLUSolverBind.size() == matrixdim);
Array< const SVectorRational* > matrix(matrixdim);
_rationalLUSolverBind.reSize(matrixdim);
for(int i = 0; i < matrixdim; i++)
{
if(_rationalLUSolverBind[i] >= 0)
{
assert(_rationalLUSolverBind[i] < numColsRational());
matrix[i] = &colVectorRational(_rationalLUSolverBind[i]);
}
else
{
assert(-1 - _rationalLUSolverBind[i] >= 0);
assert(-1 - _rationalLUSolverBind[i] < numRowsRational());
matrix[i] = _unitVectorRational(-1 - _rationalLUSolverBind[i]);
}
}
if(realParam(SoPlexBase<R>::TIMELIMIT) < realParam(SoPlexBase<R>::INFTY))
_rationalLUSolver.setTimeLimit((double)realParam(SoPlexBase<R>::TIMELIMIT) -
_statistics->solvingTime->time());
else
_rationalLUSolver.setTimeLimit(-1.0);
_rationalLUSolver.load(matrix.get_ptr(), matrixdim);
_statistics->luFactorizationTimeRational += _rationalLUSolver.getFactorTime();
_statistics->luFactorizationsRational += _rationalLUSolver.getFactorCount();
_rationalLUSolver.resetCounters();
if(_rationalLUSolver.status() == SLinSolverRational::TIME)
{
MSG_INFO2(spxout, spxout << "Rational factorization hit time limit.\n");
}
else if(_rationalLUSolver.status() != SLinSolverRational::OK)
{
MSG_INFO1(spxout, spxout << "Error performing rational LU factorization.\n");
}
return;
}
template <class R>
void SoPlexBase<R>::_factorizeColumnRational(SolRational& sol,
DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusRows,
DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusCols, bool& stoppedTime,
bool& stoppedIter, bool& error, bool& optimal)
{
_statistics->rationalTime->start();
stoppedTime = false;
stoppedIter = false;
error = false;
optimal = false;
const bool maximizing = (intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MAXIMIZE);
const int matrixdim = numRowsRational();
bool loadMatrix = (_rationalLUSolver.status() == SLinSolverRational::UNLOADED
|| _rationalLUSolver.status() == SLinSolverRational::TIME);
int numBasicRows;
assert(loadMatrix || matrixdim == _rationalLUSolver.dim());
assert(loadMatrix || matrixdim == _rationalLUSolverBind.size());
if(!loadMatrix && (matrixdim != _rationalLUSolver.dim()
|| matrixdim != _rationalLUSolverBind.size()))
{
MSG_WARNING(spxout, spxout <<
"Warning: dimensioning error in rational matrix factorization (recovered).\n");
loadMatrix = true;
}
_workSol._primal.reDim(matrixdim);
_workSol._slacks.reDim(matrixdim);
_workSol._dual.reDim(matrixdim);
_workSol._redCost.reDim(numColsRational() > matrixdim ? numColsRational() : matrixdim);
if(loadMatrix)
_rationalLUSolverBind.reSize(matrixdim);
VectorRational& basicPrimalRhs = _workSol._slacks;
VectorRational& basicDualRhs = _workSol._redCost;
VectorRational& basicPrimal = _workSol._primal;
VectorRational& basicDual = _workSol._dual;
Rational violation;
Rational primalViolation;
Rational dualViolation;
bool primalFeasible = false;
bool dualFeasible = false;
assert(basisStatusCols.size() == numColsRational());
assert(basisStatusRows.size() == numRowsRational());
int j = 0;
for(int i = 0; i < basisStatusRows.size(); i++)
{
if(basisStatusRows[i] == SPxSolverBase<R>::BASIC && j < matrixdim)
{
basicPrimalRhs[i] = 0;
basicDualRhs[j] = 0;
if(loadMatrix)
_rationalLUSolverBind[j] = -1 - i;
j++;
}
else if(basisStatusRows[i] == SPxSolverBase<R>::ON_LOWER)
basicPrimalRhs[i] = lhsRational(i);
else if(basisStatusRows[i] == SPxSolverBase<R>::ON_UPPER)
basicPrimalRhs[i] = rhsRational(i);
else if(basisStatusRows[i] == SPxSolverBase<R>::ZERO)
basicPrimalRhs[i] = 0;
else if(basisStatusRows[i] == SPxSolverBase<R>::FIXED)
{
assert(lhsRational(i) == rhsRational(i));
basicPrimalRhs[i] = lhsRational(i);
}
else if(basisStatusRows[i] == SPxSolverBase<R>::UNDEFINED)
{
MSG_INFO1(spxout, spxout << "Undefined basis status of row in rational factorization.\n");
error = true;
goto TERMINATE;
}
else
{
assert(basisStatusRows[i] == SPxSolverBase<R>::BASIC);
MSG_INFO1(spxout, spxout << "Too many basic rows in rational factorization.\n");
error = true;
goto TERMINATE;
}
}
numBasicRows = j;
for(int i = 0; i < basisStatusCols.size(); i++)
{
if(basisStatusCols[i] == SPxSolverBase<R>::BASIC && j < matrixdim)
{
basicDualRhs[j] = objRational(i);
if(loadMatrix)
_rationalLUSolverBind[j] = i;
j++;
}
else if(basisStatusCols[i] == SPxSolverBase<R>::ON_LOWER)
basicPrimalRhs.multAdd(-lowerRational(i), colVectorRational(i));
else if(basisStatusCols[i] == SPxSolverBase<R>::ON_UPPER)
basicPrimalRhs.multAdd(-upperRational(i), colVectorRational(i));
else if(basisStatusCols[i] == SPxSolverBase<R>::ZERO)
{}
else if(basisStatusCols[i] == SPxSolverBase<R>::FIXED)
{
assert(lowerRational(i) == upperRational(i));
basicPrimalRhs.multAdd(-lowerRational(i), colVectorRational(i));
}
else if(basisStatusCols[i] == SPxSolverBase<R>::UNDEFINED)
{
MSG_INFO1(spxout, spxout << "Undefined basis status of column in rational factorization.\n");
error = true;
goto TERMINATE;
}
else
{
assert(basisStatusCols[i] == SPxSolverBase<R>::BASIC);
MSG_INFO1(spxout, spxout << "Too many basic columns in rational factorization.\n");
error = true;
goto TERMINATE;
}
}
if(j != matrixdim)
{
MSG_INFO1(spxout, spxout << "Too few basic entries in rational factorization.\n");
error = true;
goto TERMINATE;
}
if(loadMatrix)
_computeBasisInverseRational();
if(_rationalLUSolver.status() == SLinSolverRational::TIME)
{
stoppedTime = true;
return;
}
else if(_rationalLUSolver.status() != SLinSolverRational::OK)
{
error = true;
return;
}
assert(_rationalLUSolver.status() == SLinSolverRational::OK);
if(realParam(SoPlexBase<R>::TIMELIMIT) < realParam(SoPlexBase<R>::INFTY))
_rationalLUSolver.setTimeLimit(Real(realParam(SoPlexBase<R>::TIMELIMIT)) -
_statistics->solvingTime->time());
else
_rationalLUSolver.setTimeLimit(-1.0);
_rationalLUSolver.solveRight(basicPrimal, basicPrimalRhs);
_statistics->luSolveTimeRational += _rationalLUSolver.getSolveTime();
_rationalLUSolver.resetCounters();
if(_isSolveStopped(stoppedTime, stoppedIter))
{
MSG_INFO2(spxout, spxout << "Rational factorization hit time limit while solving for primal.\n");
return;
}
j = 0;
primalViolation = 0;
primalFeasible = true;
for(int i = 0; i < basisStatusRows.size(); i++)
{
if(basisStatusRows[i] == SPxSolverBase<R>::BASIC)
{
assert(j < matrixdim);
assert(_rationalLUSolverBind[j] == -1 - i);
violation = lhsRational(i);
violation += basicPrimal[j];
if(violation > primalViolation)
{
primalFeasible = false;
primalViolation = violation;
}
violation = rhsRational(i);
violation += basicPrimal[j];
violation *= -1;
if(violation > primalViolation)
{
primalFeasible = false;
primalViolation = violation;
}
j++;
}
}
for(int i = 0; i < basisStatusCols.size(); i++)
{
if(basisStatusCols[i] == SPxSolverBase<R>::BASIC)
{
assert(j < matrixdim);
assert(_rationalLUSolverBind[j] == i);
if(basicPrimal[j] < lowerRational(i))
{
violation = lowerRational(i);
violation -= basicPrimal[j];
if(violation > primalViolation)
{
primalFeasible = false;
primalViolation = violation;
}
}
if(basicPrimal[j] > upperRational(i))
{
violation = basicPrimal[j];
violation -= upperRational(i);
if(violation > primalViolation)
{
primalFeasible = false;
primalViolation = violation;
}
}
j++;
}
}
if(!primalFeasible)
{
MSG_INFO1(spxout, spxout << "Rational solution primal infeasible.\n");
}
if(realParam(SoPlexBase<R>::TIMELIMIT) < realParam(SoPlexBase<R>::INFTY))
_rationalLUSolver.setTimeLimit(Real(realParam(SoPlexBase<R>::TIMELIMIT)) -
_statistics->solvingTime->time());
else
_rationalLUSolver.setTimeLimit(-1.0);
_rationalLUSolver.solveLeft(basicDual, basicDualRhs);
_statistics->luSolveTimeRational += _rationalLUSolver.getSolveTime();
_rationalLUSolver.resetCounters();
if(_isSolveStopped(stoppedTime, stoppedIter))
{
MSG_INFO2(spxout, spxout << "Rational factorization hit time limit while solving for dual.\n");
return;
}
dualViolation = 0;
dualFeasible = true;
for(int i = 0; i < basisStatusRows.size(); i++)
{
if(_rowTypes[i] == RANGETYPE_FIXED
&& (basisStatusRows[i] == SPxSolverBase<R>::ON_LOWER
|| basisStatusRows[i] == SPxSolverBase<R>::ON_UPPER))
{
assert(lhsRational(i) == rhsRational(i));
basisStatusRows[i] = SPxSolverBase<R>::FIXED;
}
assert(basisStatusRows[i] != SPxSolverBase<R>::BASIC || basicDual[i] == 0);
if(basisStatusRows[i] == SPxSolverBase<R>::BASIC || basisStatusRows[i] == SPxSolverBase<R>::FIXED)
continue;
else if(basicDual[i] < 0)
{
if(((maximizing && basisStatusRows[i] != SPxSolverBase<R>::ON_LOWER) || (!maximizing
&& basisStatusRows[i] != SPxSolverBase<R>::ON_UPPER))
&& (basisStatusRows[i] != SPxSolverBase<R>::ZERO || rhsRational(i) != 0))
{
dualFeasible = false;
violation = -basicDual[i];
if(violation > dualViolation)
dualViolation = violation;
MSG_DEBUG(spxout << "negative dual multliplier for row " << i
<< " with dual " << basicDual[i].str()
<< " and status " << basisStatusRows[i]
<< " and [lhs,rhs] = [" << lhsRational(i).str() << "," << rhsRational(i).str() << "]"
<< "\n");
}
}
else if(basicDual[i] > 0)
{
if(((maximizing && basisStatusRows[i] != SPxSolverBase<R>::ON_UPPER) || (!maximizing
&& basisStatusRows[i] != SPxSolverBase<R>::ON_LOWER))
&& (basisStatusRows[i] != SPxSolverBase<R>::ZERO || lhsRational(i) == 0))
{
dualFeasible = false;
if(basicDual[i] > dualViolation)
dualViolation = basicDual[i];
MSG_DEBUG(spxout << "positive dual multliplier for row " << i
<< " with dual " << basicDual[i].str()
<< " and status " << basisStatusRows[i]
<< " and [lhs,rhs] = [" << lhsRational(i).str() << "," << rhsRational(i).str() << "]"
<< "\n");
}
}
}
for(int i = 0; i < basisStatusCols.size(); i++)
{
if(_colTypes[i] == RANGETYPE_FIXED
&& (basisStatusCols[i] == SPxSolverBase<R>::ON_LOWER
|| basisStatusCols[i] == SPxSolverBase<R>::ON_UPPER))
{
assert(lowerRational(i) == upperRational(i));
basisStatusCols[i] = SPxSolverBase<R>::FIXED;
}
assert(basisStatusCols[i] != SPxSolverBase<R>::BASIC
|| basicDual * colVectorRational(i) == objRational(i));
if(basisStatusCols[i] == SPxSolverBase<R>::BASIC || basisStatusCols[i] == SPxSolverBase<R>::FIXED)
continue;
else
{
_workSol._redCost[i] = basicDual * colVectorRational(i);
_workSol._redCost[i] -= objRational(i);
if(_workSol._redCost[i] > 0)
{
if(((maximizing && basisStatusCols[i] != SPxSolverBase<R>::ON_LOWER) || (!maximizing
&& basisStatusCols[i] != SPxSolverBase<R>::ON_UPPER))
&& (basisStatusCols[i] != SPxSolverBase<R>::ZERO || upperRational(i) != 0))
{
dualFeasible = false;
if(_workSol._redCost[i] > dualViolation)
dualViolation = _workSol._redCost[i];
}
_workSol._redCost[i] *= -1;
}
else if(_workSol._redCost[i] < 0)
{
_workSol._redCost[i] *= -1;
if(((maximizing && basisStatusCols[i] != SPxSolverBase<R>::ON_UPPER) || (!maximizing
&& basisStatusCols[i] != SPxSolverBase<R>::ON_LOWER))
&& (basisStatusCols[i] != SPxSolverBase<R>::ZERO || lowerRational(i) != 0))
{
dualFeasible = false;
if(_workSol._redCost[i] > dualViolation)
dualViolation = _workSol._redCost[i];
}
}
else
_workSol._redCost[i] *= -1;
}
}
if(!dualFeasible)
{
MSG_INFO1(spxout, spxout << "Rational solution dual infeasible.\n");
}
optimal = primalFeasible && dualFeasible;
if(optimal || boolParam(SoPlexBase<R>::RATFACJUMP))
{
_hasBasis = true;
if(&basisStatusRows != &_basisStatusRows)
_basisStatusRows = basisStatusRows;
if(&basisStatusCols != &_basisStatusCols)
_basisStatusCols = basisStatusCols;
sol._primal.reDim(numColsRational());
j = numBasicRows;
for(int i = 0; i < basisStatusCols.size(); i++)
{
if(basisStatusCols[i] == SPxSolverBase<R>::BASIC)
{
assert(j < matrixdim);
assert(_rationalLUSolverBind[j] == i);
sol._primal[i] = basicPrimal[j];
j++;
}
else if(basisStatusCols[i] == SPxSolverBase<R>::ON_LOWER)
sol._primal[i] = lowerRational(i);
else if(basisStatusCols[i] == SPxSolverBase<R>::ON_UPPER)
sol._primal[i] = upperRational(i);
else if(basisStatusCols[i] == SPxSolverBase<R>::ZERO)
sol._primal[i] = 0;
else if(basisStatusCols[i] == SPxSolverBase<R>::FIXED)
{
assert(lowerRational(i) == upperRational(i));
sol._primal[i] = lowerRational(i);
}
else
{
assert(basisStatusCols[i] == SPxSolverBase<R>::UNDEFINED);
MSG_INFO1(spxout, spxout << "Undefined basis status of column in rational factorization.\n");
error = true;
goto TERMINATE;
}
}
sol._slacks.reDim(numRowsRational());
_rationalLP->computePrimalActivity(sol._primal, sol._slacks);
sol._isPrimalFeasible = true;
sol._dual = basicDual;
for(int i = 0; i < numColsRational(); i++)
{
if(basisStatusCols[i] == SPxSolverBase<R>::BASIC)
sol._redCost[i] = 0;
else if(basisStatusCols[i] == SPxSolverBase<R>::FIXED)
{
sol._redCost[i] = basicDual * colVectorRational(i);
sol._redCost[i] -= objRational(i);
sol._redCost[i] *= -1;
}
else
sol._redCost[i] = _workSol._redCost[i];
}
sol._isDualFeasible = true;
}
else
{
_rationalLUSolver.clear();
}
TERMINATE:
_statistics->rationalTime->stop();
return;
}
template <class R>
bool SoPlexBase<R>::_reconstructSolutionRational(SolRational& sol,
DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusRows,
DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusCols,
const Rational& denomBoundSquared)
{
bool success;
bool isSolBasic;
DIdxSet basicIndices(numColsRational());
success = false;
isSolBasic = true;
if(!sol.isPrimalFeasible() || !sol.isDualFeasible())
return success;
_statistics->reconstructionTime->start();
_statistics->rationalReconstructions++;
_workSol._primal = sol._primal;
for(int j = 0; j < numColsRational(); ++j)
{
if(basisStatusCols[j] == SPxSolverBase<R>::BASIC)
basicIndices.addIdx(j);
}
success = reconstructVector(_workSol._primal, denomBoundSquared, &basicIndices);
if(!success)
{
MSG_INFO1(spxout, spxout << "Rational reconstruction of primal solution failed.\n");
_statistics->reconstructionTime->stop();
return success;
}
MSG_DEBUG(spxout << "Rational reconstruction of primal solution successful.\n");
for(int c = numColsRational() - 1; c >= 0; c--)
{
typename SPxSolverBase<R>::VarStatus& basisStatusCol = _basisStatusCols[c];
if((basisStatusCol == SPxSolverBase<R>::FIXED && _workSol._primal[c] != lowerRational(c))
|| (basisStatusCol == SPxSolverBase<R>::ON_LOWER && _workSol._primal[c] != lowerRational(c))
|| (basisStatusCol == SPxSolverBase<R>::ON_UPPER && _workSol._primal[c] != upperRational(c))
|| (basisStatusCol == SPxSolverBase<R>::ZERO && _workSol._primal[c] != 0)
|| (basisStatusCol == SPxSolverBase<R>::UNDEFINED))
{
isSolBasic = false;
}
if(_lowerFinite(_colTypes[c]) && _workSol._primal[c] < lowerRational(c))
{
MSG_DEBUG(std::cout << "Lower bound of variable " << c << " violated by " <<
(lowerRational(c) - _workSol._primal[c]).str() << "\n");
MSG_INFO1(spxout, spxout << "Reconstructed solution primal infeasible (1).\n");
_statistics->reconstructionTime->stop();
return false;
}
if(_upperFinite(_colTypes[c]) && _workSol._primal[c] > upperRational(c))
{
MSG_DEBUG(std::cout << "Upper bound of variable " << c << " violated by " <<
(_workSol._primal[c] - upperRational(c)).str() << "\n");
MSG_INFO1(spxout, spxout << "Reconstructed solution primal infeasible (2).\n");
_statistics->reconstructionTime->stop();
return false;
}
}
_workSol._slacks.reDim(numRowsRational());
_rationalLP->computePrimalActivity(_workSol._primal, _workSol._slacks);
for(int r = numRowsRational() - 1; r >= 0; r--)
{
typename SPxSolverBase<R>::VarStatus& basisStatusRow = _basisStatusRows[r];
if((basisStatusRow == SPxSolverBase<R>::FIXED && _workSol._slacks[r] != lhsRational(r))
|| (basisStatusRow == SPxSolverBase<R>::ON_LOWER && _workSol._slacks[r] != lhsRational(r))
|| (basisStatusRow == SPxSolverBase<R>::ON_UPPER && _workSol._slacks[r] != rhsRational(r))
|| (basisStatusRow == SPxSolverBase<R>::ZERO && _workSol._slacks[r] != 0)
|| (basisStatusRow == SPxSolverBase<R>::UNDEFINED))
{
isSolBasic = false;
}
if(_lowerFinite(_rowTypes[r]) && _workSol._slacks[r] < lhsRational(r))
{
MSG_DEBUG(std::cout << "Lhs of row " << r << " violated by " <<
(lhsRational(r) - _workSol._slacks[r]).str() << "\n");
MSG_INFO1(spxout, spxout << "Reconstructed solution primal infeasible (3).\n");
_statistics->reconstructionTime->stop();
return false;
}
if(_upperFinite(_rowTypes[r]) && _workSol._slacks[r] > rhsRational(r))
{
MSG_DEBUG(std::cout << "Rhs of row " << r << " violated by " <<
(_workSol._slacks[r] - rhsRational(r)) << "\n");
MSG_INFO1(spxout, spxout << "Reconstructed solution primal infeasible (4).\n");
_statistics->reconstructionTime->stop();
return false;
}
}
_workSol._dual = sol._dual;
success = reconstructVector(_workSol._dual, denomBoundSquared);
if(!success)
{
MSG_INFO1(spxout, spxout << "Rational reconstruction of dual solution failed.\n");
_statistics->reconstructionTime->stop();
return success;
}
MSG_DEBUG(spxout << "Rational reconstruction of dual vector successful.\n");
const bool maximizing = (intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MAXIMIZE);
for(int r = numRowsRational() - 1; r >= 0; r--)
{
int sig = sign(_workSol._dual[r]);
if((!maximizing && sig > 0) || (maximizing && sig < 0))
{
if(!_lowerFinite(_rowTypes[r]) || _workSol._slacks[r] > lhsRational(r))
{
MSG_DEBUG(std::cout << "complementary slackness violated by row " << r
<< " with dual " << _workSol._dual[r].str()
<< " and slack " << _workSol._slacks[r].str()
<< " not at lhs " << lhsRational(r).str()
<< "\n");
MSG_INFO1(spxout, spxout << "Reconstructed solution dual infeasible (1).\n");
_statistics->reconstructionTime->stop();
return false;
}
if(_basisStatusRows[r] != SPxSolverBase<R>::ON_LOWER
&& _basisStatusRows[r] != SPxSolverBase<R>::FIXED)
{
if(_basisStatusRows[r] == SPxSolverBase<R>::BASIC
|| _basisStatusRows[r] == SPxSolverBase<R>::UNDEFINED)
isSolBasic = false;
else
_basisStatusRows[r] = SPxSolverBase<R>::ON_LOWER;
}
}
else if((!maximizing && sig < 0) || (maximizing && sig > 0))
{
if(!_upperFinite(_rowTypes[r]) || _workSol._slacks[r] < rhsRational(r))
{
MSG_DEBUG(std::cout << "complementary slackness violated by row " << r
<< " with dual " << _workSol._dual[r].str()
<< " and slack " << _workSol._slacks[r].str()
<< " not at rhs " << rhsRational(r).str()
<< "\n");
MSG_INFO1(spxout, spxout << "Reconstructed solution dual infeasible (2).\n");
_statistics->reconstructionTime->stop();
return false;
}
if(_basisStatusRows[r] != SPxSolverBase<R>::ON_UPPER
&& _basisStatusRows[r] != SPxSolverBase<R>::FIXED)
{
if(_basisStatusRows[r] == SPxSolverBase<R>::BASIC
|| _basisStatusRows[r] == SPxSolverBase<R>::UNDEFINED)
isSolBasic = false;
else
_basisStatusRows[r] = SPxSolverBase<R>::ON_UPPER;
}
}
}
_workSol._redCost.reDim(numColsRational());
_rationalLP->getObj(_workSol._redCost);
_rationalLP->subDualActivity(_workSol._dual, _workSol._redCost);
for(int c = numColsRational() - 1; c >= 0; c--)
{
int sig = sign(_workSol._redCost[c]);
if((!maximizing && sig > 0) || (maximizing && sig < 0))
{
if(!_lowerFinite(_colTypes[c]) || _workSol._primal[c] > lowerRational(c))
{
MSG_DEBUG(std::cout << "complementary slackness violated by column " << c
<< " with reduced cost " << _workSol._redCost[c].str()
<< " and value " << _workSol._primal[c].str()
<< " not at lower bound " << lowerRational(c).str()
<< "\n");
MSG_INFO1(spxout, spxout << "Reconstructed solution dual infeasible (3).\n");
_statistics->reconstructionTime->stop();
return false;
}
if(_basisStatusCols[c] != SPxSolverBase<R>::ON_LOWER
&& _basisStatusCols[c] != SPxSolverBase<R>::FIXED)
{
if(_basisStatusCols[c] == SPxSolverBase<R>::BASIC
|| _basisStatusCols[c] == SPxSolverBase<R>::UNDEFINED)
isSolBasic = false;
else
_basisStatusCols[c] = SPxSolverBase<R>::ON_LOWER;
}
}
else if((!maximizing && sig < 0) || (maximizing && sig > 0))
{
if(!_upperFinite(_colTypes[c]) || _workSol._primal[c] < upperRational(c))
{
MSG_DEBUG(std::cout << "complementary slackness violated by column " << c
<< " with reduced cost " << _workSol._redCost[c].str()
<< " and value " << _workSol._primal[c].str()
<< " not at upper bound " << upperRational(c).str()
<< "\n");
MSG_INFO1(spxout, spxout << "Reconstructed solution dual infeasible (4).\n");
_statistics->reconstructionTime->stop();
return false;
}
if(_basisStatusCols[c] != SPxSolverBase<R>::ON_UPPER
&& _basisStatusCols[c] != SPxSolverBase<R>::FIXED)
{
if(_basisStatusCols[c] == SPxSolverBase<R>::BASIC
|| _basisStatusCols[c] == SPxSolverBase<R>::UNDEFINED)
isSolBasic = false;
else
_basisStatusCols[c] = SPxSolverBase<R>::ON_UPPER;
}
}
}
sol._primal = _workSol._primal;
sol._slacks = _workSol._slacks;
sol._dual = _workSol._dual;
sol._redCost = _workSol._redCost;
if(!isSolBasic)
{
MSG_WARNING(spxout, spxout << "Warning: Reconstructed solution not basic.\n");
_hasBasis = false;
}
_statistics->reconstructionTime->stop();
return success;
}
}