43#define WINAPI __stdcall
45#define LoadInverseLib FALSE
46#define LoadLanguageLib FALSE
48#include <lpsolve/lp_lib.h>
57#include <com/sun/star/frame/XModel.hpp>
58#include <com/sun/star/table/CellAddress.hpp>
59#include <rtl/math.hxx>
76 virtual void SAL_CALL
solve()
override;
79 return "com.sun.star.comp.Calc.LpsolveSolver";
81 virtual OUString SAL_CALL getComponentDescription()
override
89void SAL_CALL LpsolveSolver::solve()
91 uno::Reference<frame::XModel>
xModel( mxDoc, uno::UNO_QUERY_THROW );
96 if ( mnEpsilonLevel < EPS_TIGHT || mnEpsilonLevel > EPS_BAGGY )
102 xModel->lockControllers();
106 const auto & aVariableCells = maVariables;
107 size_t nVariables = aVariableCells.size();
113 aCellsHash[maObjective].reserve( nVariables + 1 );
115 for (
const auto& rConstr : std::as_const(maConstraints))
117 table::CellAddress aCellAddr = rConstr.Left;
118 aCellsHash[aCellAddr].reserve( nVariables + 1 );
120 if ( rConstr.Right >>= aCellAddr )
121 aCellsHash[aCellAddr].reserve( nVariables + 1 );
127 for (
const auto& rVarCell : aVariableCells )
133 for (
auto& rEntry : aCellsHash )
136 rEntry.second.push_back( fValue );
140 for (
const auto& rVarCell : aVariableCells )
145 for (
auto& rEntry : aCellsHash )
148 double fInitial = rEntry.second.front();
149 rEntry.second.push_back( fChanged - fInitial );
154 for (
const auto& rEntry : aCellsHash )
156 double fInitial = rEntry.second.front();
157 double fCoeff = rEntry.second.back();
160 bool bLinear = rtl::math::approxEqual( fTwo, fInitial + 2.0 * fCoeff ) ||
161 rtl::math::approxEqual( fInitial, fTwo - 2.0 * fCoeff );
170 xModel->unlockControllers();
172 if ( !maStatus.isEmpty() )
179 lprec* lp = make_lp( 0, nVariables );
183 set_outputfile( lp,
const_cast<char*
>(
"" ) );
187 const std::vector<double>& rObjCoeff = aCellsHash[maObjective];
188 std::unique_ptr<REAL[]> pObjVal(
new REAL[nVariables+1]);
190 for (nVar=0; nVar<nVariables; nVar++)
191 pObjVal[nVar+1] = rObjCoeff[nVar+1];
192 set_obj_fn( lp, pObjVal.get() );
194 set_rh( lp, 0, rObjCoeff[0] );
198 set_add_rowmode(lp, TRUE);
200 for (
const auto& rConstr : std::as_const(maConstraints))
203 sheet::SolverConstraintOperator eOp = rConstr.Operator;
204 if ( eOp == sheet::SolverConstraintOperator_LESS_EQUAL ||
205 eOp == sheet::SolverConstraintOperator_GREATER_EQUAL ||
206 eOp == sheet::SolverConstraintOperator_EQUAL )
208 double fDirectValue = 0.0;
209 bool bRightCell =
false;
210 table::CellAddress aRightAddr;
211 const uno::Any& rRightAny = rConstr.Right;
212 if ( rRightAny >>= aRightAddr )
215 rRightAny >>= fDirectValue;
217 table::CellAddress aLeftAddr = rConstr.Left;
219 const std::vector<double>& rLeftCoeff = aCellsHash[aLeftAddr];
220 std::unique_ptr<REAL[]>
pValues(
new REAL[nVariables+1] );
222 for (nVar=0; nVar<nVariables; nVar++)
223 pValues[nVar+1] = rLeftCoeff[nVar+1];
226 double fRightValue = -rLeftCoeff[0];
230 const std::vector<double>& rRightCoeff = aCellsHash[aRightAddr];
232 for (nVar=0; nVar<nVariables; nVar++)
233 pValues[nVar+1] -= rRightCoeff[nVar+1];
235 fRightValue += rRightCoeff[0];
238 fRightValue += fDirectValue;
240 int nConstrType =
LE;
243 case sheet::SolverConstraintOperator_LESS_EQUAL: nConstrType =
LE;
break;
244 case sheet::SolverConstraintOperator_GREATER_EQUAL: nConstrType =
GE;
break;
245 case sheet::SolverConstraintOperator_EQUAL: nConstrType =
EQ;
break;
247 OSL_FAIL(
"unexpected enum type" );
249 add_constraint( lp,
pValues.get(), nConstrType, fRightValue );
253 set_add_rowmode(lp, FALSE);
257 for (nVar=0; nVar<nVariables; nVar++)
259 if ( !mbNonNegative )
260 set_unbounded(lp, nVar+1);
263 set_int(lp, nVar+1, TRUE);
268 for (
const auto& rConstr : std::as_const(maConstraints))
270 sheet::SolverConstraintOperator eOp = rConstr.Operator;
271 if ( eOp == sheet::SolverConstraintOperator_INTEGER ||
272 eOp == sheet::SolverConstraintOperator_BINARY )
274 table::CellAddress aLeftAddr = rConstr.Left;
276 for (nVar=0; nVar<nVariables; nVar++)
279 if ( eOp == sheet::SolverConstraintOperator_INTEGER )
280 set_int(lp, nVar+1, TRUE);
282 set_binary(lp, nVar+1, TRUE);
292 if ( !mbLimitBBDepth )
293 set_bb_depthlimit( lp, 0 );
295 set_epslevel( lp, mnEpsilonLevel );
296 set_timeout( lp, mnTimeout );
300 int nResult = ::solve( lp );
307 maSolution.realloc( nVariables );
309 REAL* pResultVar =
nullptr;
310 get_ptr_variables( lp, &pResultVar );
311 std::copy_n(pResultVar, nVariables, maSolution.getArray());
313 mfResultValue = get_objective( lp );
315 else if ( nResult == INFEASIBLE )
317 else if ( nResult == UNBOUNDED )
319 else if ( nResult == TIMEOUT || nResult == SUBOPTIMAL )
326extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
328 css::uno::XComponentContext *,
329 css::uno::Sequence<css::uno::Any>
const &)
331 return cppu::acquire(
new LpsolveSolver());
const PropertyValue * pValues
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_Calc_LpsolveSolver_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