21#include <CoinError.hpp>
26#include <com/sun/star/frame/XModel.hpp>
27#include <com/sun/star/table/CellAddress.hpp>
29#include <rtl/math.hxx>
46 virtual void SAL_CALL
solve()
override;
49 return "com.sun.star.comp.Calc.CoinMPSolver";
51 virtual OUString SAL_CALL getComponentDescription()
override
59void SAL_CALL CoinMPSolver::solve()
61 uno::Reference<frame::XModel>
xModel( mxDoc, uno::UNO_QUERY_THROW );
70 const auto & aVariableCells = maVariables;
71 size_t nVariables = aVariableCells.size();
77 aCellsHash[maObjective].reserve( nVariables + 1 );
79 for (
const auto& rConstr : std::as_const(maConstraints))
81 table::CellAddress aCellAddr = rConstr.Left;
82 aCellsHash[aCellAddr].reserve( nVariables + 1 );
84 if ( rConstr.Right >>= aCellAddr )
85 aCellsHash[aCellAddr].reserve( nVariables + 1 );
91 for (
const auto& rVarCell : aVariableCells )
97 for (
auto& rEntry : aCellsHash )
100 rEntry.second.push_back( fValue );
104 for (
const auto& rVarCell : aVariableCells )
109 for (
auto& rEntry : aCellsHash )
112 double fInitial = rEntry.second.front();
113 rEntry.second.push_back( fChanged - fInitial );
118 for (
const auto& rEntry : aCellsHash )
120 double fInitial = rEntry.second.front();
121 double fCoeff = rEntry.second.back();
124 bool bLinear = rtl::math::approxEqual( fTwo, fInitial + 2.0 * fCoeff ) ||
125 rtl::math::approxEqual( fInitial, fTwo - 2.0 * fCoeff );
134 xModel->unlockControllers();
136 if ( !maStatus.isEmpty() )
145 const std::vector<double>& rObjCoeff = aCellsHash[maObjective];
146 std::unique_ptr<double[]> pObjectCoeffs(
new double[nVariables]);
147 for (nVar=0; nVar<nVariables; nVar++)
148 pObjectCoeffs[nVar] = rObjCoeff[nVar+1];
149 double nObjectConst = rObjCoeff[0];
153 size_t nRows = maConstraints.getLength();
154 size_t nCompSize = nVariables * nRows;
155 std::unique_ptr<double[]> pCompMatrix(
new double[nCompSize]);
156 for (
size_t i=0;
i<nCompSize;
i++)
157 pCompMatrix[i] = 0.0;
159 std::unique_ptr<double[]> pRHS(
new double[nRows]);
160 std::unique_ptr<char[]> pRowType(
new char[nRows]);
161 for (
size_t i=0;
i<nRows;
i++)
167 for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos)
170 sheet::SolverConstraintOperator eOp = maConstraints[nConstrPos].Operator;
171 if ( eOp == sheet::SolverConstraintOperator_LESS_EQUAL ||
172 eOp == sheet::SolverConstraintOperator_GREATER_EQUAL ||
173 eOp == sheet::SolverConstraintOperator_EQUAL )
175 double fDirectValue = 0.0;
176 bool bRightCell =
false;
177 table::CellAddress aRightAddr;
178 const uno::Any& rRightAny = maConstraints[nConstrPos].Right;
179 if ( rRightAny >>= aRightAddr )
182 rRightAny >>= fDirectValue;
184 table::CellAddress aLeftAddr = maConstraints[nConstrPos].Left;
186 const std::vector<double>& rLeftCoeff = aCellsHash[aLeftAddr];
187 double*
pValues = &pCompMatrix[nConstrPos * nVariables];
188 for (nVar=0; nVar<nVariables; nVar++)
189 pValues[nVar] = rLeftCoeff[nVar+1];
192 double fRightValue = -rLeftCoeff[0];
196 const std::vector<double>& rRightCoeff = aCellsHash[aRightAddr];
198 for (nVar=0; nVar<nVariables; nVar++)
199 pValues[nVar] -= rRightCoeff[nVar+1];
201 fRightValue += rRightCoeff[0];
204 fRightValue += fDirectValue;
208 case sheet::SolverConstraintOperator_LESS_EQUAL: pRowType[nConstrPos] =
'L';
break;
209 case sheet::SolverConstraintOperator_GREATER_EQUAL: pRowType[nConstrPos] =
'G';
break;
210 case sheet::SolverConstraintOperator_EQUAL: pRowType[nConstrPos] =
'E';
break;
212 OSL_ENSURE(
false,
"unexpected enum type" );
214 pRHS[nConstrPos] = fRightValue;
220 std::unique_ptr<int[]> pMatrixBegin(
new int[nVariables+1]);
221 std::unique_ptr<int[]> pMatrixCount(
new int[nVariables]);
222 std::unique_ptr<double[]> pMatrix(
new double[nCompSize]);
223 std::unique_ptr<int[]> pMatrixIndex(
new int[nCompSize]);
225 for (nVar=0; nVar<nVariables; nVar++)
227 int nBegin = nMatrixPos;
228 for (
size_t nRow=0; nRow<nRows; nRow++)
230 double fCoeff = pCompMatrix[ nRow * nVariables + nVar ];
233 pMatrix[nMatrixPos] = fCoeff;
234 pMatrixIndex[nMatrixPos] = nRow;
238 pMatrixBegin[nVar] = nBegin;
239 pMatrixCount[nVar] = nMatrixPos - nBegin;
241 pMatrixBegin[nVariables] = nMatrixPos;
246 std::unique_ptr<double[]> pLowerBounds(
new double[nVariables]);
247 std::unique_ptr<double[]> pUpperBounds(
new double[nVariables]);
248 for (nVar=0; nVar<nVariables; nVar++)
250 pLowerBounds[nVar] = mbNonNegative ? 0.0 : -DBL_MAX;
251 pUpperBounds[nVar] = DBL_MAX;
256 std::unique_ptr<char[]> pColType(
new char[nVariables]);
257 for (nVar=0; nVar<nVariables; nVar++)
258 pColType[nVar] = mbInteger ?
'I' :
'C';
262 for (
const auto& rConstr : std::as_const(maConstraints))
264 sheet::SolverConstraintOperator eOp = rConstr.Operator;
265 if ( eOp == sheet::SolverConstraintOperator_INTEGER ||
266 eOp == sheet::SolverConstraintOperator_BINARY )
268 table::CellAddress aLeftAddr = rConstr.Left;
270 for (nVar=0; nVar<nVariables; nVar++)
273 if ( eOp == sheet::SolverConstraintOperator_INTEGER )
274 pColType[nVar] =
'I';
277 pColType[nVar] =
'B';
278 pLowerBounds[nVar] = 0.0;
279 pUpperBounds[nVar] = 1.0;
285 int nObjectSense = mbMaximize ? SOLV_OBJSENS_MAX : SOLV_OBJSENS_MIN;
287 HPROB hProb = CoinCreateProblem(
"");
288 int nResult = CoinLoadProblem( hProb, nVariables, nRows, nMatrixPos, 0,
289 nObjectSense, nObjectConst, pObjectCoeffs.get(),
290 pLowerBounds.get(), pUpperBounds.get(), pRowType.get(), pRHS.get(),
nullptr,
291 pMatrixBegin.get(), pMatrixCount.get(), pMatrixIndex.get(), pMatrix.get(),
292 nullptr,
nullptr,
nullptr );
293 if (nResult == SOLV_CALL_SUCCESS)
295 nResult = CoinLoadInteger( hProb, pColType.get() );
299 pMatrixIndex.reset();
301 pMatrixCount.reset();
302 pMatrixBegin.reset();
303 pUpperBounds.reset();
304 pLowerBounds.reset();
307 pObjectCoeffs.reset();
309 CoinSetRealOption( hProb, COIN_REAL_MAXSECONDS, mnTimeout );
310 CoinSetRealOption( hProb, COIN_REAL_MIPMAXSEC, mnTimeout );
316 if (nResult == SOLV_CALL_SUCCESS)
318 nResult = CoinCheckProblem( hProb );
321 if (nResult == SOLV_CALL_SUCCESS)
325 nResult = CoinOptimizeProblem( hProb, 0 );
327 catch (
const CoinError& e)
329 CoinUnloadProblem(hProb);
330 throw std::runtime_error(e.message());
334 mbSuccess = ( nResult == SOLV_CALL_SUCCESS );
339 maSolution.realloc( nVariables );
340 CoinGetSolutionValues( hProb, maSolution.getArray(),
nullptr,
nullptr,
nullptr );
341 mfResultValue = CoinGetObjectValue( hProb );
345 int nSolutionStatus = CoinGetSolutionStatus( hProb );
346 if ( nSolutionStatus == 1 )
348 else if ( nSolutionStatus == 2 )
354 CoinUnloadProblem( hProb );
357extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
359 css::uno::XComponentContext *,
360 css::uno::Sequence<css::uno::Any>
const &)
362 return cppu::acquire(
new CoinMPSolver());
const PropertyValue * pValues
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_Calc_CoinMPSolver_get_implementation(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
std::unordered_map< css::table::CellAddress, std::vector< double >, ScSolverCellHash, ScSolverCellEqual > ScSolverCellHashMap
bool AddressEqual(const css::table::CellAddress &rAddr1, const css::table::CellAddress &rAddr2)
static double GetValue(const css::uno::Reference< css::sheet::XSpreadsheetDocument > &xDoc, const css::table::CellAddress &rPos)
static void SetValue(const css::uno::Reference< css::sheet::XSpreadsheetDocument > &xDoc, const css::table::CellAddress &rPos, double fValue)
static OUString GetResourceString(TranslateId aId)
bool solve(Matrix &matrix, int rows, int cols, Vector &result, BaseType minPivot)
OUString getImplementationName()
Reference< XModel > xModel