13#include <com/sun/star/frame/XModel.hpp>
14#include <com/sun/star/container/XIndexAccess.hpp>
15#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
16#include <com/sun/star/sheet/XSpreadsheet.hpp>
17#include <com/sun/star/sheet/XSolver.hpp>
18#include <com/sun/star/sheet/XSolverDescription.hpp>
19#include <com/sun/star/table/CellAddress.hpp>
20#include <com/sun/star/table/CellContentType.hpp>
21#include <com/sun/star/table/XCell.hpp>
22#include <com/sun/star/lang/XServiceInfo.hpp>
24#include <rtl/math.hxx>
47class XComponentContext;
62 : lower(
std::numeric_limits<float>::lowest())
63 , upper(
std::numeric_limits<float>::
max())
67 void updateBound(sheet::SolverConstraintOperator eOp,
double fValue)
69 if (eOp == sheet::SolverConstraintOperator_LESS_EQUAL)
76 else if (eOp == sheet::SolverConstraintOperator_GREATER_EQUAL)
81 else if (eOp == sheet::SolverConstraintOperator_EQUAL)
99typedef cppu::WeakImplHelper<sheet::XSolver, sheet::XSolverDescription, lang::XServiceInfo>
110 uno::Reference<sheet::XSpreadsheetDocument> mxDocument;
111 table::CellAddress maObjective;
112 uno::Sequence<table::CellAddress> maVariables;
113 uno::Sequence<sheet::SolverConstraint> maConstraints;
120 sal_Int32 mnAlgorithm;
124 double mfResultValue;
126 uno::Sequence<double> maSolution;
130 std::vector<sheet::SolverConstraint> maNonBoundedConstraints;
133 static OUString getResourceString(
TranslateId aId);
135 uno::Reference<table::XCell> getCell(
const table::CellAddress& rPosition);
136 void setValue(
const table::CellAddress& rPosition,
double fValue);
137 double getValue(
const table::CellAddress& rPosition);
143 , mbNonNegative(
false)
163 virtual uno::Reference<beans::XPropertySetInfo> SAL_CALL getPropertySetInfo()
override
165 return createPropertySetInfo(getInfoHelper());
181 virtual uno::Reference<sheet::XSpreadsheetDocument> SAL_CALL getDocument()
override
185 virtual void SAL_CALL
186 setDocument(
const uno::Reference<sheet::XSpreadsheetDocument>& rDocument)
override
188 mxDocument = rDocument;
191 virtual table::CellAddress SAL_CALL getObjective()
override {
return maObjective; }
192 virtual void SAL_CALL setObjective(
const table::CellAddress& rObjective)
override
194 maObjective = rObjective;
197 virtual uno::Sequence<table::CellAddress> SAL_CALL getVariables()
override
201 virtual void SAL_CALL setVariables(
const uno::Sequence<table::CellAddress>& rVariables)
override
203 maVariables = rVariables;
206 virtual uno::Sequence<sheet::SolverConstraint> SAL_CALL getConstraints()
override
208 return maConstraints;
210 virtual void SAL_CALL
211 setConstraints(
const uno::Sequence<sheet::SolverConstraint>& rConstraints)
override
213 maConstraints = rConstraints;
216 virtual sal_Bool SAL_CALL getMaximize()
override {
return mbMaximize; }
217 virtual void SAL_CALL setMaximize(
sal_Bool bMaximize)
override { mbMaximize = bMaximize; }
220 virtual double SAL_CALL getResultValue()
override {
return mfResultValue; }
222 virtual uno::Sequence<double> SAL_CALL getSolution()
override {
return maSolution; }
224 virtual void SAL_CALL
solve()
override;
227 virtual OUString SAL_CALL getComponentDescription()
override
229 return SwarmSolver::getResourceString(RID_SWARM_SOLVER_COMPONENT);
232 virtual OUString SAL_CALL getStatusDescription()
override {
return maStatus; }
237 switch (getInfoHelper().getHandleByName(rPropertyName))
239 case PROP_NONNEGATIVE:
240 pResId = RID_PROPERTY_NONNEGATIVE;
243 pResId = RID_PROPERTY_INTEGER;
246 pResId = RID_PROPERTY_TIMEOUT;
249 pResId = RID_PROPERTY_ALGORITHM;
254 return SwarmSolver::getResourceString(pResId);
260 return "com.sun.star.comp.Calc.SwarmSolver";
270 return {
"com.sun.star.sheet.Solver" };
274 void applyVariables(std::vector<double>
const& rVariables);
275 bool doesViolateConstraints();
278 double calculateFitness(std::vector<double>
const& rVariables);
279 size_t getDimensionality()
const;
280 void initializeVariables(std::vector<double>& rVariables, std::mt19937& rGenerator);
281 double clampVariable(
size_t nVarIndex,
double fValue);
282 double boundVariable(
size_t nVarIndex,
double fValue);
286OUString SwarmSolver::getResourceString(
TranslateId aId)
294uno::Reference<table::XCell> SwarmSolver::getCell(
const table::CellAddress& rPosition)
296 uno::Reference<container::XIndexAccess> xSheets(mxDocument->getSheets(), uno::UNO_QUERY);
297 uno::Reference<sheet::XSpreadsheet> xSheet(xSheets->getByIndex(rPosition.Sheet),
299 return xSheet->getCellByPosition(rPosition.Column, rPosition.Row);
302void SwarmSolver::setValue(
const table::CellAddress& rPosition,
double fValue)
304 getCell(rPosition)->setValue(fValue);
307double SwarmSolver::getValue(
const table::CellAddress& rPosition)
309 return getCell(rPosition)->getValue();
315void SwarmSolver::applyVariables(std::vector<double>
const& rVariables)
317 for (sal_Int32 i = 0;
i < maVariables.getLength(); ++
i)
319 setValue(maVariables[i], rVariables[i]);
323double SwarmSolver::calculateFitness(std::vector<double>
const& rVariables)
325 applyVariables(rVariables);
327 if (doesViolateConstraints())
328 return std::numeric_limits<float>::lowest();
338void SwarmSolver::initializeVariables(std::vector<double>& rVariables, std::mt19937& rGenerator)
341 bool bConstraintsOK =
false;
343 while (!bConstraintsOK && nTry < 10)
345 size_t noVariables(maVariables.getLength());
347 rVariables.resize(noVariables);
349 for (
size_t i = 0;
i < noVariables; ++
i)
354 sal_Int64 intLower(rBound.lower);
355 sal_Int64 intUpper(rBound.upper);
356 std::uniform_int_distribution<sal_Int64> random(intLower, intUpper);
357 rVariables[
i] = double(random(rGenerator));
361 std::uniform_real_distribution<double> random(rBound.lower, rBound.upper);
362 rVariables[
i] = random(rGenerator);
366 applyVariables(rVariables);
368 bConstraintsOK = !doesViolateConstraints();
373double SwarmSolver::clampVariable(
size_t nVarIndex,
double fValue)
375 Bound
const& rBound =
maBounds[nVarIndex];
376 double fResult = std::clamp(fValue, rBound.lower, rBound.upper);
379 return std::trunc(fResult);
384double SwarmSolver::boundVariable(
size_t nVarIndex,
double fValue)
386 Bound
const& rBound =
maBounds[nVarIndex];
388 double fResult = fValue;
389 while (fResult < rBound.lower || fResult > rBound.upper)
391 if (fResult < rBound.lower)
392 fResult = rBound.upper - (rBound.lower - fResult);
393 if (fResult > rBound.upper)
394 fResult = (fResult - rBound.upper) + rBound.lower;
398 return std::trunc(fResult);
403size_t SwarmSolver::getDimensionality()
const {
return maVariables.getLength(); }
405bool SwarmSolver::doesViolateConstraints()
407 for (
const sheet::SolverConstraint& rConstraint : maNonBoundedConstraints)
409 double fLeftValue =
getValue(rConstraint.Left);
410 double fRightValue = 0.0;
412 table::CellAddress aCellAddress;
414 if (rConstraint.Right >>= aCellAddress)
416 fRightValue =
getValue(aCellAddress);
418 else if (rConstraint.Right >>= fRightValue)
427 sheet::SolverConstraintOperator eOp = rConstraint.Operator;
430 case sheet::SolverConstraintOperator_LESS_EQUAL:
432 if (fLeftValue > fRightValue)
436 case sheet::SolverConstraintOperator_GREATER_EQUAL:
438 if (fLeftValue < fRightValue)
442 case sheet::SolverConstraintOperator_EQUAL:
444 if (!rtl::math::approxEqual(fLeftValue, fRightValue))
457template <
typename SwarmAlgorithm>
class SwarmRunner
460 SwarmAlgorithm& mrAlgorithm;
463 static constexpr size_t mnPopulationSize = 40;
464 static constexpr int constNumberOfGenerationsWithoutChange = 50;
466 std::chrono::high_resolution_clock::time_point
maStart;
467 std::chrono::high_resolution_clock::time_point
maEnd;
470 SwarmRunner(SwarmAlgorithm& rAlgorithm)
471 : mrAlgorithm(rAlgorithm)
476 void setTimeout(
double fTimeout) { mfTimeout = fTimeout; }
478 std::vector<double>
const&
solve()
480 using std::chrono::duration_cast;
481 using std::chrono::high_resolution_clock;
482 using std::chrono::milliseconds;
484 mrAlgorithm.initialize();
490 while ((mrAlgorithm.getGeneration() - nLastChange) < constNumberOfGenerationsWithoutChange
491 && duration_cast<milliseconds>(maEnd - maStart).count() < mfTimeout)
493 bool bChange = mrAlgorithm.next();
496 nLastChange = mrAlgorithm.getGeneration();
498 maEnd = high_resolution_clock::now();
500 return mrAlgorithm.getResult();
505void SAL_CALL SwarmSolver::solve()
507 uno::Reference<frame::XModel>
xModel(mxDocument, uno::UNO_QUERY_THROW);
511 if (!maVariables.getLength())
514 maBounds.resize(maVariables.getLength());
516 xModel->lockControllers();
520 for (Bound& rBound : maBounds)
525 for (sheet::SolverConstraint
const& rConstraint : std::as_const(maConstraints))
527 table::CellAddress aLeftCellAddress = rConstraint.Left;
528 sheet::SolverConstraintOperator eOp = rConstraint.Operator;
531 bool bFoundVariable =
false;
532 for (
const table::CellAddress& rVariableCell : std::as_const(maVariables))
534 if (aLeftCellAddress == rVariableCell)
536 bFoundVariable =
true;
537 table::CellAddress aCellAddress;
540 if (rConstraint.Right >>= aCellAddress)
542 uno::Reference<table::XCell> xCell = getCell(aCellAddress);
543 if (xCell->getType() == table::CellContentType_VALUE)
549 maNonBoundedConstraints.push_back(rConstraint);
552 else if (rConstraint.Right >>= fValue)
560 maNonBoundedConstraints.push_back(rConstraint);
563 std::vector<double> aSolution;
565 if (mnAlgorithm == 0)
568 SwarmRunner<DifferentialEvolutionAlgorithm<SwarmSolver>> aEvolution(aDE);
569 aEvolution.setTimeout(mnTimeout);
570 aSolution = aEvolution.solve();
575 SwarmRunner<ParticleSwarmOptimizationAlgorithm<SwarmSolver>> aSwarmSolver(aPSO);
576 aSwarmSolver.setTimeout(mnTimeout);
577 aSolution = aSwarmSolver.solve();
580 xModel->unlockControllers();
584 maSolution.realloc(aSolution.size());
585 std::copy(aSolution.begin(), aSolution.end(), maSolution.getArray());
588extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
590 uno::Sequence<uno::Any>
const&)
592 return cppu::acquire(
new SwarmSolver());
SAL_DLLPUBLIC_EXPORT uno::XInterface * com_sun_star_comp_Calc_SwarmSolver_get_implementation(uno::XComponentContext *, uno::Sequence< uno::Any > const &)
cppu::WeakImplHelper< sheet::XSolver, sheet::XSolverDescription, lang::XServiceInfo > SwarmSolver_Base
PropertiesInfo aProperties
::basegfx::B2DRectangle maBounds
::cppu::OBroadcastHelper & GetBroadcastHelper()
virtual ::cppu::IPropertyArrayHelper * createArrayHelper() const=0
::cppu::IPropertyArrayHelper * getArrayHelper()
void describeProperties(css::uno::Sequence< css::beans::Property > &_rProps) const
void registerProperty(const OUString &_rName, sal_Int32 _nHandle, sal_Int32 _nAttributes, void *_pPointerToMember, const css::uno::Type &_rMemberType)
OPropertyContainer(::cppu::OBroadcastHelper &_rBHelper)
bool solve(Matrix &matrix, int rows, int cols, Vector &result, BaseType minPivot)
std::locale Create(std::string_view aPrefixName, const LanguageTag &rLocale)
OUString get(TranslateId sContextAndId, const std::locale &loc)
css::uno::Sequence< OUString > getSupportedServiceNames()
OUString getImplementationName()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
css::beans::Optional< css::uno::Any > getValue(std::u16string_view id)
IMPLEMENT_FORWARD_XTYPEPROVIDER2(ChildWindowPane, ChildWindowPaneInterfaceBase, Pane)
IMPLEMENT_FORWARD_XINTERFACE2(ChildWindowPane, ChildWindowPaneInterfaceBase, Pane)
RegError REGISTRY_CALLTYPE setValue(RegKeyHandle hKey, rtl_uString *keyName, RegValueType valueType, RegValue pData, sal_uInt32 valueSize)
Reference< XModel > xModel
#define DECLARE_XTYPEPROVIDER()
#define DECLARE_XINTERFACE()