Kaydet (Commit) 6d492447 authored tarafından Andre Fischer's avatar Andre Fischer

118160: Use CoinMP as replacement for lp_solve.

Original author: Niklas Nebel
üst 47dfa3a7
...@@ -52,7 +52,7 @@ SHL1STDLIBS= $(COMPHELPERLIB) \ ...@@ -52,7 +52,7 @@ SHL1STDLIBS= $(COMPHELPERLIB) \
$(CPPULIB) \ $(CPPULIB) \
$(SALLIB) \ $(SALLIB) \
$(TOOLSLIB) \ $(TOOLSLIB) \
$(LPSOLVELIB) CoinMP.lib
SHL1DEPN= makefile.mk SHL1DEPN= makefile.mk
SHL1DEF= $(MISC)$/$(SHL1TARGET).def SHL1DEF= $(MISC)$/$(SHL1TARGET).def
......
...@@ -21,12 +21,7 @@ ...@@ -21,12 +21,7 @@
#undef LANGUAGE_NONE #include <coinmp/CoinMP.h>
#define WINAPI __stdcall
#define LoadInverseLib FALSE
#define LoadLanguageLib FALSE
#include <lpsolve/lp_lib.h>
#undef LANGUAGE_NONE
#include "solver.hxx" #include "solver.hxx"
#include "solver.hrc" #include "solver.hrc"
...@@ -310,12 +305,6 @@ void SAL_CALL SolverComponent::solve() throw(uno::RuntimeException) ...@@ -310,12 +305,6 @@ void SAL_CALL SolverComponent::solve() throw(uno::RuntimeException)
maStatus = OUString(); maStatus = OUString();
mbSuccess = false; mbSuccess = false;
if ( mnEpsilonLevel < EPS_TIGHT || mnEpsilonLevel > EPS_BAGGY )
{
maStatus = lcl_GetResourceString( RID_ERROR_EPSILONLEVEL );
return;
}
xModel->lockControllers(); xModel->lockControllers();
// collect variables in vector (?) // collect variables in vector (?)
...@@ -394,29 +383,32 @@ void SAL_CALL SolverComponent::solve() throw(uno::RuntimeException) ...@@ -394,29 +383,32 @@ void SAL_CALL SolverComponent::solve() throw(uno::RuntimeException)
return; return;
// //
// build lp_solve model // build parameter arrays for CoinMP
// //
lprec* lp = make_lp( 0, nVariables );
if ( !lp )
return;
set_outputfile( lp, const_cast<char*>( "" ) ); // no output
// set objective function // set objective function
const std::vector<double>& rObjCoeff = aCellsHash[maObjective]; const std::vector<double>& rObjCoeff = aCellsHash[maObjective];
REAL* pObjVal = new REAL[nVariables+1]; double* pObjectCoeffs = new double[nVariables];
pObjVal[0] = 0.0; // ignored
for (nVar=0; nVar<nVariables; nVar++) for (nVar=0; nVar<nVariables; nVar++)
pObjVal[nVar+1] = rObjCoeff[nVar+1]; pObjectCoeffs[nVar] = rObjCoeff[nVar+1];
set_obj_fn( lp, pObjVal ); double nObjectConst = rObjCoeff[0]; // constant term of objective
delete[] pObjVal;
set_rh( lp, 0, rObjCoeff[0] ); // constant term of objective
// add rows // add rows
set_add_rowmode(lp, TRUE); size_t nRows = maConstraints.getLength();
size_t nCompSize = nVariables * nRows;
double* pCompMatrix = new double[nCompSize]; // first collect all coefficients, row-wise
for (size_t i=0; i<nCompSize; i++)
pCompMatrix[i] = 0.0;
double* pRHS = new double[nRows];
char* pRowType = new char[nRows];
for (size_t i=0; i<nRows; i++)
{
pRHS[i] = 0.0;
pRowType[i] = 'N';
}
for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos) for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos)
{ {
...@@ -438,10 +430,9 @@ void SAL_CALL SolverComponent::solve() throw(uno::RuntimeException) ...@@ -438,10 +430,9 @@ void SAL_CALL SolverComponent::solve() throw(uno::RuntimeException)
table::CellAddress aLeftAddr = maConstraints[nConstrPos].Left; table::CellAddress aLeftAddr = maConstraints[nConstrPos].Left;
const std::vector<double>& rLeftCoeff = aCellsHash[aLeftAddr]; const std::vector<double>& rLeftCoeff = aCellsHash[aLeftAddr];
REAL* pValues = new REAL[nVariables+1]; double* pValues = &pCompMatrix[nConstrPos * nVariables];
pValues[0] = 0.0; // ignored?
for (nVar=0; nVar<nVariables; nVar++) for (nVar=0; nVar<nVariables; nVar++)
pValues[nVar+1] = rLeftCoeff[nVar+1]; pValues[nVar] = rLeftCoeff[nVar+1];
// if left hand cell has a constant term, put into rhs value // if left hand cell has a constant term, put into rhs value
double fRightValue = -rLeftCoeff[0]; double fRightValue = -rLeftCoeff[0];
...@@ -451,41 +442,68 @@ void SAL_CALL SolverComponent::solve() throw(uno::RuntimeException) ...@@ -451,41 +442,68 @@ void SAL_CALL SolverComponent::solve() throw(uno::RuntimeException)
const std::vector<double>& rRightCoeff = aCellsHash[aRightAddr]; const std::vector<double>& rRightCoeff = aCellsHash[aRightAddr];
// modify pValues with rhs coefficients // modify pValues with rhs coefficients
for (nVar=0; nVar<nVariables; nVar++) for (nVar=0; nVar<nVariables; nVar++)
pValues[nVar+1] -= rRightCoeff[nVar+1]; pValues[nVar] -= rRightCoeff[nVar+1];
fRightValue += rRightCoeff[0]; // constant term fRightValue += rRightCoeff[0]; // constant term
} }
else else
fRightValue += fDirectValue; fRightValue += fDirectValue;
int nConstrType = LE;
switch ( eOp ) switch ( eOp )
{ {
case sheet::SolverConstraintOperator_LESS_EQUAL: nConstrType = LE; break; case sheet::SolverConstraintOperator_LESS_EQUAL: pRowType[nConstrPos] = 'L'; break;
case sheet::SolverConstraintOperator_GREATER_EQUAL: nConstrType = GE; break; case sheet::SolverConstraintOperator_GREATER_EQUAL: pRowType[nConstrPos] = 'G'; break;
case sheet::SolverConstraintOperator_EQUAL: nConstrType = EQ; break; case sheet::SolverConstraintOperator_EQUAL: pRowType[nConstrPos] = 'E'; break;
default: default:
OSL_ENSURE( false, "unexpected enum type" ); OSL_ENSURE( false, "unexpected enum type" );
} }
add_constraint( lp, pValues, nConstrType, fRightValue ); pRHS[nConstrPos] = fRightValue;
delete[] pValues;
} }
} }
set_add_rowmode(lp, FALSE); // Find non-zero coefficients, column-wise
int* pMatrixBegin = new int[nVariables+1];
int* pMatrixCount = new int[nVariables];
double* pMatrix = new double[nCompSize]; // not always completely used
int* pMatrixIndex = new int[nCompSize];
int nMatrixPos = 0;
for (nVar=0; nVar<nVariables; nVar++)
{
int nBegin = nMatrixPos;
for (size_t nRow=0; nRow<nRows; nRow++)
{
double fCoeff = pCompMatrix[ nRow * nVariables + nVar ]; // row-wise
if ( fCoeff != 0.0 )
{
pMatrix[nMatrixPos] = fCoeff;
pMatrixIndex[nMatrixPos] = nRow;
++nMatrixPos;
}
}
pMatrixBegin[nVar] = nBegin;
pMatrixCount[nVar] = nMatrixPos - nBegin;
}
pMatrixBegin[nVariables] = nMatrixPos;
delete[] pCompMatrix;
pCompMatrix = NULL;
// apply settings to all variables // apply settings to all variables
double* pLowerBounds = new double[nVariables];
double* pUpperBounds = new double[nVariables];
for (nVar=0; nVar<nVariables; nVar++) for (nVar=0; nVar<nVariables; nVar++)
{ {
if ( !mbNonNegative ) pLowerBounds[nVar] = mbNonNegative ? 0.0 : -DBL_MAX;
set_unbounded(lp, nVar+1); // allow negative (default is non-negative) pUpperBounds[nVar] = DBL_MAX;
//! collect bounds from constraints?
if ( mbInteger ) // bounds could possibly be further restricted from single-cell constraints
set_int(lp, nVar+1, TRUE);
} }
char* pColType = new char[nVariables];
for (nVar=0; nVar<nVariables; nVar++)
pColType[nVar] = mbInteger ? 'I' : 'C';
// apply single-var integer constraints // apply single-var integer constraints
for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos) for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos)
...@@ -500,51 +518,69 @@ void SAL_CALL SolverComponent::solve() throw(uno::RuntimeException) ...@@ -500,51 +518,69 @@ void SAL_CALL SolverComponent::solve() throw(uno::RuntimeException)
if ( AddressEqual( aVariableCells[nVar], aLeftAddr ) ) if ( AddressEqual( aVariableCells[nVar], aLeftAddr ) )
{ {
if ( eOp == sheet::SolverConstraintOperator_INTEGER ) if ( eOp == sheet::SolverConstraintOperator_INTEGER )
set_int(lp, nVar+1, TRUE); pColType[nVar] = 'I';
else else
set_binary(lp, nVar+1, TRUE); {
pColType[nVar] = 'B';
pLowerBounds[nVar] = 0.0;
pUpperBounds[nVar] = 1.0;
}
} }
} }
} }
if ( mbMaximize ) int nObjectSense = mbMaximize ? SOLV_OBJSENS_MAX : SOLV_OBJSENS_MIN;
set_maxim(lp);
else HPROB hProb = CoinCreateProblem("");
set_minim(lp); int nResult = CoinLoadProblem( hProb, nVariables, nRows, nMatrixPos, 0,
nObjectSense, nObjectConst, pObjectCoeffs,
pLowerBounds, pUpperBounds, pRowType, pRHS, NULL,
pMatrixBegin, pMatrixCount, pMatrixIndex, pMatrix,
NULL, NULL, NULL );
nResult = CoinLoadInteger( hProb, pColType );
if ( !mbLimitBBDepth ) delete[] pColType;
set_bb_depthlimit( lp, 0 ); delete[] pMatrixIndex;
delete[] pMatrix;
delete[] pMatrixCount;
delete[] pMatrixBegin;
delete[] pUpperBounds;
delete[] pLowerBounds;
delete[] pRowType;
delete[] pRHS;
delete[] pObjectCoeffs;
set_epslevel( lp, mnEpsilonLevel ); CoinSetRealOption( hProb, COIN_REAL_MAXSECONDS, mnTimeout );
set_timeout( lp, mnTimeout ); CoinSetRealOption( hProb, COIN_REAL_MIPMAXSEC, mnTimeout );
// TODO: handle (or remove) settings: epsilon, B&B depth
// solve model // solve model
int nResult = ::solve( lp ); nResult = CoinCheckProblem( hProb );
nResult = CoinOptimizeProblem( hProb, 0 );
mbSuccess = ( nResult == OPTIMAL ); mbSuccess = ( nResult == SOLV_CALL_SUCCESS );
if ( mbSuccess ) if ( mbSuccess )
{ {
// get solution // get solution
maSolution.realloc( nVariables ); maSolution.realloc( nVariables );
CoinGetSolutionValues( hProb, maSolution.getArray(), NULL, NULL, NULL );
REAL* pResultVar = NULL; mfResultValue = CoinGetObjectValue( hProb );
get_ptr_variables( lp, &pResultVar );
for (nVar=0; nVar<nVariables; nVar++)
maSolution[nVar] = pResultVar[nVar];
mfResultValue = get_objective( lp );
} }
else if ( nResult == INFEASIBLE ) else
maStatus = lcl_GetResourceString( RID_ERROR_INFEASIBLE ); {
else if ( nResult == UNBOUNDED ) int nSolutionStatus = CoinGetSolutionStatus( hProb );
maStatus = lcl_GetResourceString( RID_ERROR_UNBOUNDED ); if ( nSolutionStatus == 1 )
else if ( nResult == TIMEOUT || nResult == SUBOPTIMAL ) maStatus = lcl_GetResourceString( RID_ERROR_INFEASIBLE );
maStatus = lcl_GetResourceString( RID_ERROR_TIMEOUT ); else if ( nSolutionStatus == 2 )
// SUBOPTIMAL is assumed to be caused by a timeout, and reported as an error maStatus = lcl_GetResourceString( RID_ERROR_UNBOUNDED );
// TODO: detect timeout condition and report as RID_ERROR_TIMEOUT
delete_lp( lp ); // (currently reported as infeasible)
}
CoinUnloadProblem( hProb );
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment