Swarm based (uses PSO or DE) experimental non-linear solver

This is a new, simple non-linear solver that uses a swarm
(population) to do global optimization. It uses two algoritms -
Particle Swarm Optimization (PSO) or Differential Evolution (DE)
to find a (non-optimal) solution.

It is experimental as not all functions are implemented and it
needs a lot more testing so that it performs well.

Change-Id: If55dad7eda17394851a9d178ad892de771eca7c9
Reviewed-on: https://gerrit.libreoffice.org/44382
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
This commit is contained in:
Tomaž Vajngerl
2017-11-06 00:54:25 +01:00
committed by Tomaž Vajngerl
parent 257f62bb18
commit 08404bbb90
13 changed files with 1425 additions and 0 deletions

View File

@@ -118,6 +118,7 @@ $(eval $(call gb_Rdb_add_components,services,\
$(if $(ENABLE_LPSOLVE), \
sccomp/source/solver/lpsolvesolver \
) \
sccomp/source/solver/swarmsolver \
writerfilter/util/writerfilter \
writerperfect/source/draw/wpftdraw \
writerperfect/source/impress/wpftimpress \

View File

@@ -0,0 +1,71 @@
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
$(eval $(call gb_CppunitTest_CppunitTest,swarm_solver_test))
$(eval $(call gb_CppunitTest_add_exception_objects,swarm_solver_test,\
sccomp/qa/unit/SwarmSolverTest \
))
$(eval $(call gb_CppunitTest_use_externals,swarm_solver_test,\
boost_headers \
))
$(eval $(call gb_CppunitTest_use_libraries,swarm_solver_test,\
basegfx \
comphelper \
cppu \
cppuhelper \
drawinglayer \
editeng \
for \
forui \
i18nlangtag \
msfilter \
oox \
sal \
salhelper \
sax \
sb \
sc \
scqahelper \
sfx \
sot \
subsequenttest \
svl \
svt \
svx \
svxcore \
test \
tk \
tl \
ucbhelper \
unotest \
utl \
vbahelper \
vcl \
xo \
$(gb_UWINAPI) \
))
$(eval $(call gb_CppunitTest_set_include,swarm_solver_test,\
-I$(SRCDIR)/sc/inc \
$$(INCLUDE) \
))
$(eval $(call gb_CppunitTest_use_sdk_api,swarm_solver_test))
$(eval $(call gb_CppunitTest_use_ure,swarm_solver_test))
$(eval $(call gb_CppunitTest_use_vcl,swarm_solver_test))
$(eval $(call gb_CppunitTest_use_rdb,swarm_solver_test,services))
$(eval $(call gb_CppunitTest_use_configuration,swarm_solver_test))
# vim: set noet sw=4 ts=4:

View File

@@ -22,6 +22,8 @@ $(eval $(call gb_Library_Library,solver))
$(if $(ENABLE_COINMP),$(eval $(call gb_Library_set_componentfile,solver,sccomp/source/solver/coinmpsolver)))
$(if $(ENABLE_LPSOLVE),$(eval $(call gb_Library_set_componentfile,solver,sccomp/source/solver/lpsolvesolver)))
$(eval $(call gb_Library_set_componentfile,solver,sccomp/source/solver/swarmsolver))
$(eval $(call gb_Library_use_sdk_api,solver))
$(eval $(call gb_Library_set_include,solver,\
@@ -45,6 +47,7 @@ $(eval $(call gb_Library_use_externals,solver,\
))
$(eval $(call gb_Library_add_exception_objects,solver,\
sccomp/source/solver/SwarmSolver \
sccomp/source/solver/SolverComponent \
$(if $(ENABLE_COINMP), sccomp/source/solver/CoinMPSolver) \
$(if $(ENABLE_LPSOLVE), sccomp/source/solver/LpsolveSolver) \

View File

@@ -29,6 +29,7 @@ $(eval $(call gb_Module_add_l10n_targets,sccomp,\
$(eval $(call gb_Module_add_check_targets,sccomp,\
CppunitTest_sccomp_solver \
CppunitTest_sccomp_swarmsolvertest \
))
# vim: set noet sw=4 ts=4:

View File

@@ -24,11 +24,13 @@
#define RID_SOLVER_COMPONENT NC_("RID_SOLVER_COMPONENT", "%PRODUCTNAME Linear Solver")
#define RID_COINMP_SOLVER_COMPONENT NC_("RID_COINMP_SOLVER_COMPONENT", "%PRODUCTNAME CoinMP Linear Solver")
#define RID_SWARM_SOLVER_COMPONENT NC_("RID_SWARM_SOLVER_COMPONENT", "%PRODUCTNAME Swarm Non-Linear Solver (experimental)")
#define RID_PROPERTY_NONNEGATIVE NC_("RID_PROPERTY_NONNEGATIVE", "Assume variables as non-negative")
#define RID_PROPERTY_INTEGER NC_("RID_PROPERTY_INTEGER", "Assume variables as integer")
#define RID_PROPERTY_TIMEOUT NC_("RID_PROPERTY_TIMEOUT", "Solving time limit (seconds)")
#define RID_PROPERTY_EPSILONLEVEL NC_("RID_PROPERTY_EPSILONLEVEL", "Epsilon level (0-3)")
#define RID_PROPERTY_LIMITBBDEPTH NC_("RID_PROPERTY_LIMITBBDEPTH", "Limit branch-and-bound depth")
#define RID_PROPERTY_ALGORITHM NC_("RID_PROPERTY_ALGORITHM", "Swarm algorithm (0 - Differential Evolution, 1 - Particle Swarm Optimization)")
#define RID_ERROR_NONLINEAR NC_("RID_ERROR_NONLINEAR", "The model is not linear.")
#define RID_ERROR_EPSILONLEVEL NC_("RID_ERROR_EPSILONLEVEL", "The epsilon level is invalid.")
#define RID_ERROR_INFEASIBLE NC_("RID_ERROR_INFEASIBLE", "The model is infeasible. Check limiting conditions.")

View File

@@ -0,0 +1,399 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <sal/config.h>
#include <com/sun/star/container/XContentEnumerationAccess.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/sheet/XSolver.hpp>
#include <com/sun/star/sheet/XSolverDescription.hpp>
#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
#include <com/sun/star/sheet/XSpreadsheet.hpp>
#include <com/sun/star/text/XTextRange.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <test/calc_unoapi_test.hxx>
#include <address.hxx>
using namespace css;
namespace
{
class SwarmSolverTest : public CalcUnoApiTest
{
uno::Reference<lang::XComponent> mxComponent;
void testUnconstrained();
void testVariableBounded();
void testVariableConstrained();
void testTwoVariables();
void testMultipleVariables();
public:
SwarmSolverTest()
: CalcUnoApiTest("sccomp/qa/unit/data")
{
}
virtual void tearDown() override;
CPPUNIT_TEST_SUITE(SwarmSolverTest);
CPPUNIT_TEST(testUnconstrained);
CPPUNIT_TEST(testVariableBounded);
CPPUNIT_TEST(testVariableConstrained);
CPPUNIT_TEST(testMultipleVariables);
CPPUNIT_TEST(testTwoVariables);
CPPUNIT_TEST_SUITE_END();
};
void SwarmSolverTest::tearDown()
{
if (mxComponent.is())
closeDocument(mxComponent);
}
void SwarmSolverTest::testUnconstrained()
{
CPPUNIT_ASSERT(!mxComponent.is());
OUString aFileURL;
createFileURL("Simple.ods", aFileURL);
mxComponent = loadFromDesktop(aFileURL);
CPPUNIT_ASSERT_MESSAGE("Component not loaded", mxComponent.is());
uno::Reference<sheet::XSpreadsheetDocument> xDocument(mxComponent, uno::UNO_QUERY_THROW);
uno::Reference<container::XIndexAccess> xIndex(xDocument->getSheets(), uno::UNO_QUERY_THROW);
uno::Reference<sheet::XSpreadsheet> xSheet(xIndex->getByIndex(0), uno::UNO_QUERY_THROW);
uno::Reference<table::XCell> xCell;
uno::Reference<sheet::XSolver> xSolver;
OUString sSolverName("com.sun.star.comp.Calc.SwarmSolver");
xSolver.set(m_xContext->getServiceManager()->createInstanceWithContext(sSolverName, m_xContext),
uno::UNO_QUERY_THROW);
table::CellAddress aObjective(0, 1, 1);
// "changing cells" - unknown variables
uno::Sequence<table::CellAddress> aVariables(1);
aVariables[0] = table::CellAddress(0, 1, 0);
// constraints
uno::Sequence<sheet::SolverConstraint> aConstraints;
// initialize solver
xSolver->setDocument(xDocument);
xSolver->setObjective(aObjective);
xSolver->setVariables(aVariables);
xSolver->setConstraints(aConstraints);
xSolver->setMaximize(false);
// test results
xSolver->solve();
CPPUNIT_ASSERT(xSolver->getSuccess());
uno::Sequence<double> aSolution = xSolver->getSolution();
CPPUNIT_ASSERT_EQUAL(aSolution.getLength(), aVariables.getLength());
CPPUNIT_ASSERT_DOUBLES_EQUAL(3.0, aSolution[0], 1E-5);
}
void SwarmSolverTest::testVariableBounded()
{
CPPUNIT_ASSERT(!mxComponent.is());
OUString aFileURL;
createFileURL("Simple.ods", aFileURL);
mxComponent = loadFromDesktop(aFileURL);
CPPUNIT_ASSERT_MESSAGE("Component not loaded", mxComponent.is());
uno::Reference<sheet::XSpreadsheetDocument> xDocument(mxComponent, uno::UNO_QUERY_THROW);
uno::Reference<container::XIndexAccess> xIndex(xDocument->getSheets(), uno::UNO_QUERY_THROW);
uno::Reference<sheet::XSpreadsheet> xSheet(xIndex->getByIndex(0), uno::UNO_QUERY_THROW);
uno::Reference<table::XCell> xCell;
uno::Reference<sheet::XSolver> xSolver;
OUString sSolverName("com.sun.star.comp.Calc.SwarmSolver");
xSolver.set(m_xContext->getServiceManager()->createInstanceWithContext(sSolverName, m_xContext),
uno::UNO_QUERY_THROW);
table::CellAddress aObjective(0, 1, 1);
// "changing cells" - unknown variables
uno::Sequence<table::CellAddress> aVariables(1);
aVariables[0] = table::CellAddress(0, 1, 0);
// constraints
uno::Sequence<sheet::SolverConstraint> aConstraints(2);
aConstraints[0].Left = table::CellAddress(0, 1, 0);
aConstraints[0].Operator = sheet::SolverConstraintOperator_LESS_EQUAL;
aConstraints[0].Right <<= 100.0;
aConstraints[1].Left = table::CellAddress(0, 1, 0);
aConstraints[1].Operator = sheet::SolverConstraintOperator_GREATER_EQUAL;
aConstraints[1].Right <<= -100.0;
// initialize solver
xSolver->setDocument(xDocument);
xSolver->setObjective(aObjective);
xSolver->setVariables(aVariables);
xSolver->setConstraints(aConstraints);
xSolver->setMaximize(false);
// test results
xSolver->solve();
CPPUNIT_ASSERT(xSolver->getSuccess());
uno::Sequence<double> aSolution = xSolver->getSolution();
CPPUNIT_ASSERT_EQUAL(aSolution.getLength(), aVariables.getLength());
CPPUNIT_ASSERT_DOUBLES_EQUAL(3.0, aSolution[0], 1E-5);
}
void SwarmSolverTest::testVariableConstrained()
{
CPPUNIT_ASSERT(!mxComponent.is());
OUString aFileURL;
createFileURL("Simple.ods", aFileURL);
mxComponent = loadFromDesktop(aFileURL);
CPPUNIT_ASSERT_MESSAGE("Component not loaded", mxComponent.is());
uno::Reference<sheet::XSpreadsheetDocument> xDocument(mxComponent, uno::UNO_QUERY_THROW);
uno::Reference<container::XIndexAccess> xIndex(xDocument->getSheets(), uno::UNO_QUERY_THROW);
uno::Reference<sheet::XSpreadsheet> xSheet(xIndex->getByIndex(0), uno::UNO_QUERY_THROW);
uno::Reference<table::XCell> xCell;
uno::Reference<sheet::XSolver> xSolver;
OUString sSolverName("com.sun.star.comp.Calc.SwarmSolver");
xSolver.set(m_xContext->getServiceManager()->createInstanceWithContext(sSolverName, m_xContext),
uno::UNO_QUERY_THROW);
table::CellAddress aObjective(0, 1, 1);
// "changing cells" - unknown variables
uno::Sequence<table::CellAddress> aVariables(1);
aVariables[0] = table::CellAddress(0, 1, 0);
// constraints
uno::Sequence<sheet::SolverConstraint> aConstraints(3);
aConstraints[0].Left = table::CellAddress(0, 1, 0);
aConstraints[0].Operator = sheet::SolverConstraintOperator_GREATER_EQUAL;
aConstraints[0].Right <<= -50000.0;
aConstraints[1].Left = table::CellAddress(0, 1, 0);
aConstraints[1].Operator = sheet::SolverConstraintOperator_LESS_EQUAL;
aConstraints[1].Right <<= 0.0;
aConstraints[2].Left = table::CellAddress(0, 1, 1);
aConstraints[2].Operator = sheet::SolverConstraintOperator_GREATER_EQUAL;
aConstraints[2].Right <<= 10.0;
// initialize solver
xSolver->setDocument(xDocument);
xSolver->setObjective(aObjective);
xSolver->setVariables(aVariables);
xSolver->setConstraints(aConstraints);
xSolver->setMaximize(false);
// test results
xSolver->solve();
CPPUNIT_ASSERT(xSolver->getSuccess());
uno::Sequence<double> aSolution = xSolver->getSolution();
CPPUNIT_ASSERT_EQUAL(aSolution.getLength(), aVariables.getLength());
CPPUNIT_ASSERT_DOUBLES_EQUAL(-0.741657, aSolution[0], 1E-5);
}
void SwarmSolverTest::testTwoVariables()
{
CPPUNIT_ASSERT(!mxComponent.is());
OUString aFileURL;
createFileURL("TwoVariables.ods", aFileURL);
mxComponent = loadFromDesktop(aFileURL);
CPPUNIT_ASSERT_MESSAGE("Component not loaded", mxComponent.is());
uno::Reference<sheet::XSpreadsheetDocument> xDocument(mxComponent, uno::UNO_QUERY_THROW);
uno::Reference<container::XIndexAccess> xIndex(xDocument->getSheets(), uno::UNO_QUERY_THROW);
uno::Reference<sheet::XSpreadsheet> xSheet(xIndex->getByIndex(0), uno::UNO_QUERY_THROW);
uno::Reference<table::XCell> xCell;
uno::Reference<sheet::XSolver> xSolver;
OUString sSolverName("com.sun.star.comp.Calc.SwarmSolver");
xSolver.set(m_xContext->getServiceManager()->createInstanceWithContext(sSolverName, m_xContext),
uno::UNO_QUERY_THROW);
table::CellAddress aObjective(0, 1, 5);
// "changing cells" - unknown variables
uno::Sequence<table::CellAddress> aVariables(2);
aVariables[0] = table::CellAddress(0, 1, 2);
aVariables[1] = table::CellAddress(0, 1, 3);
// constraints
uno::Sequence<sheet::SolverConstraint> aConstraints(4);
aConstraints[0].Left = table::CellAddress(0, 1, 2);
aConstraints[0].Operator = sheet::SolverConstraintOperator_GREATER_EQUAL;
aConstraints[0].Right <<= -100.0;
aConstraints[1].Left = table::CellAddress(0, 1, 3);
aConstraints[1].Operator = sheet::SolverConstraintOperator_GREATER_EQUAL;
aConstraints[1].Right <<= -100.0;
aConstraints[2].Left = table::CellAddress(0, 1, 2);
aConstraints[2].Operator = sheet::SolverConstraintOperator_LESS_EQUAL;
aConstraints[2].Right <<= 100.0;
aConstraints[3].Left = table::CellAddress(0, 1, 3);
aConstraints[3].Operator = sheet::SolverConstraintOperator_LESS_EQUAL;
aConstraints[3].Right <<= 100.0;
// initialize solver
xSolver->setDocument(xDocument);
xSolver->setObjective(aObjective);
xSolver->setVariables(aVariables);
xSolver->setConstraints(aConstraints);
xSolver->setMaximize(true);
// test results
xSolver->solve();
CPPUNIT_ASSERT(xSolver->getSuccess());
uno::Sequence<double> aSolution = xSolver->getSolution();
CPPUNIT_ASSERT_EQUAL(aVariables.getLength(), aSolution.getLength());
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.666667, aSolution[0], 1E-5);
CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.666667, aSolution[1], 1E-5);
}
void SwarmSolverTest::testMultipleVariables()
{
CPPUNIT_ASSERT(!mxComponent.is());
OUString aFileURL;
createFileURL("MultiVariable.ods", aFileURL);
mxComponent = loadFromDesktop(aFileURL);
CPPUNIT_ASSERT_MESSAGE("Component not loaded", mxComponent.is());
uno::Reference<sheet::XSpreadsheetDocument> xDocument(mxComponent, uno::UNO_QUERY_THROW);
uno::Reference<container::XIndexAccess> xIndex(xDocument->getSheets(), uno::UNO_QUERY_THROW);
uno::Reference<sheet::XSpreadsheet> xSheet(xIndex->getByIndex(0), uno::UNO_QUERY_THROW);
uno::Reference<table::XCell> xCell;
uno::Reference<sheet::XSolver> xSolver;
OUString sSolverName("com.sun.star.comp.Calc.SwarmSolver");
xSolver.set(m_xContext->getServiceManager()->createInstanceWithContext(sSolverName, m_xContext),
uno::UNO_QUERY_THROW);
uno::Reference<beans::XPropertySet> xPropSet(xSolver, uno::UNO_QUERY_THROW);
xPropSet->setPropertyValue("Integer", uno::makeAny(true));
table::CellAddress aObjective(0, 5, 7);
// "changing cells" - unknown variables
uno::Sequence<table::CellAddress> aVariables(4);
aVariables[0] = table::CellAddress(0, 6, 1);
aVariables[1] = table::CellAddress(0, 6, 2);
aVariables[2] = table::CellAddress(0, 6, 3);
aVariables[3] = table::CellAddress(0, 6, 4);
// constraints
uno::Sequence<sheet::SolverConstraint> aConstraints(12);
aConstraints[0].Left = table::CellAddress(0, 1, 5);
aConstraints[0].Operator = sheet::SolverConstraintOperator_GREATER_EQUAL;
aConstraints[0].Right <<= table::CellAddress(0, 1, 6);
aConstraints[1].Left = table::CellAddress(0, 2, 5);
aConstraints[1].Operator = sheet::SolverConstraintOperator_GREATER_EQUAL;
aConstraints[1].Right <<= table::CellAddress(0, 2, 6);
aConstraints[2].Left = table::CellAddress(0, 3, 5);
aConstraints[2].Operator = sheet::SolverConstraintOperator_GREATER_EQUAL;
aConstraints[2].Right <<= table::CellAddress(0, 3, 6);
aConstraints[3].Left = table::CellAddress(0, 4, 5);
aConstraints[3].Operator = sheet::SolverConstraintOperator_GREATER_EQUAL;
aConstraints[3].Right <<= table::CellAddress(0, 4, 6);
aConstraints[4].Left = table::CellAddress(0, 6, 1);
aConstraints[4].Operator = sheet::SolverConstraintOperator_GREATER_EQUAL;
aConstraints[4].Right <<= 0.0;
aConstraints[5].Left = table::CellAddress(0, 6, 2);
aConstraints[5].Operator = sheet::SolverConstraintOperator_GREATER_EQUAL;
aConstraints[5].Right <<= 0.0;
aConstraints[6].Left = table::CellAddress(0, 6, 3);
aConstraints[6].Operator = sheet::SolverConstraintOperator_GREATER_EQUAL;
aConstraints[6].Right <<= 0.0;
aConstraints[7].Left = table::CellAddress(0, 6, 4);
aConstraints[7].Operator = sheet::SolverConstraintOperator_GREATER_EQUAL;
aConstraints[7].Right <<= 0.0;
aConstraints[8].Left = table::CellAddress(0, 6, 1);
aConstraints[8].Operator = sheet::SolverConstraintOperator_LESS_EQUAL;
aConstraints[8].Right <<= 10000.0;
aConstraints[9].Left = table::CellAddress(0, 6, 2);
aConstraints[9].Operator = sheet::SolverConstraintOperator_LESS_EQUAL;
aConstraints[9].Right <<= 10000.0;
aConstraints[10].Left = table::CellAddress(0, 6, 3);
aConstraints[10].Operator = sheet::SolverConstraintOperator_LESS_EQUAL;
aConstraints[10].Right <<= 10000.0;
aConstraints[11].Left = table::CellAddress(0, 6, 4);
aConstraints[11].Operator = sheet::SolverConstraintOperator_LESS_EQUAL;
aConstraints[11].Right <<= 10000.0;
// initialize solver
xSolver->setDocument(xDocument);
xSolver->setObjective(aObjective);
xSolver->setVariables(aVariables);
xSolver->setConstraints(aConstraints);
xSolver->setMaximize(false);
// test results
xSolver->solve();
CPPUNIT_ASSERT(xSolver->getSuccess());
uno::Sequence<double> aSolution = xSolver->getSolution();
CPPUNIT_ASSERT_EQUAL(aVariables.getLength(), aSolution.getLength());
#ifndef _WIN32
// Disable on windows for now, needs algorithm stability improvements
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, aSolution[0], 1E-5);
CPPUNIT_ASSERT_DOUBLES_EQUAL(3.0, aSolution[1], 1E-5);
CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, aSolution[2], 1E-5);
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, aSolution[3], 1E-5);
#endif
}
CPPUNIT_TEST_SUITE_REGISTRATION(SwarmSolverTest);
}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,164 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
*/
#ifndef INCLUDED_SCCOMP_SOURCE_DIFFERENTIALEVOLUTION_HXX
#define INCLUDED_SCCOMP_SOURCE_DIFFERENTIALEVOLUTION_HXX
#include <vector>
#include <random>
#include <limits>
struct Individual
{
std::vector<double> mVariables;
};
template <typename DataProvider> class DifferentialEvolutionAlgorithm
{
static constexpr double mnDifferentialWeight = 0.5; // [0, 2]
static constexpr double mnCrossoverProbability = 0.9; // [0, 1]
static constexpr double constAcceptedPrecision = 0.000000001;
DataProvider& mrDataProvider;
size_t mnPopulationSize;
std::vector<Individual> maPopulation;
std::random_device maRandomDevice;
std::mt19937 maGenerator;
size_t mnDimensionality;
std::uniform_int_distribution<> maRandomPopulation;
std::uniform_int_distribution<> maRandomDimensionality;
std::uniform_real_distribution<> maRandom01;
Individual maBestCandidate;
double mfBestFitness;
int mnGeneration;
int mnLastChange;
public:
DifferentialEvolutionAlgorithm(DataProvider& rDataProvider, size_t nPopulationSize)
: mrDataProvider(rDataProvider)
, mnPopulationSize(nPopulationSize)
, maGenerator(maRandomDevice())
, mnDimensionality(mrDataProvider.getDimensionality())
, maRandomPopulation(0, mnPopulationSize - 1)
, maRandomDimensionality(0, mnDimensionality - 1)
, maRandom01(0.0, 1.0)
, mfBestFitness(std::numeric_limits<double>::lowest())
, mnGeneration(0)
, mnLastChange(0)
{
}
std::vector<double> const& getResult() { return maBestCandidate.mVariables; }
int getGeneration() { return mnGeneration; }
int getLastChange() { return mnLastChange; }
void initialize()
{
mnGeneration = 0;
mnLastChange = 0;
maPopulation.clear();
maBestCandidate.mVariables.clear();
// Initialize population with individuals that have been initialized with uniform random
// noise
// uniform noise means random value inside your search space
for (size_t i = 0; i < mnPopulationSize; ++i)
{
maPopulation.emplace_back();
Individual& rIndividual = maPopulation.back();
mrDataProvider.initializeVariables(rIndividual.mVariables, maGenerator);
}
}
// Calculate one generation
bool next()
{
bool bBestChanged = false;
for (size_t agentIndex = 0; agentIndex < mnPopulationSize; ++agentIndex)
{
// calculate new candidate solution
// pick random point from population
size_t x = agentIndex; // randomPopulation(generator);
size_t a, b, c;
// create a copy of choosen random agent in population
Individual& rOriginal = maPopulation[x];
Individual aCandidate(rOriginal);
// pick three different random points from population
do
{
a = maRandomPopulation(maGenerator);
} while (a == x);
do
{
b = maRandomPopulation(maGenerator);
} while (b == x || b == a);
do
{
c = maRandomPopulation(maGenerator);
} while (c == x || c == a || c == b);
size_t randomIndex = maRandomDimensionality(maGenerator);
for (size_t index = 0; index < mnDimensionality; ++index)
{
double randomCrossoverProbability = maRandom01(maGenerator);
if (index == randomIndex || randomCrossoverProbability < mnCrossoverProbability)
{
double fVarA = maPopulation[a].mVariables[index];
double fVarB = maPopulation[b].mVariables[index];
double fVarC = maPopulation[c].mVariables[index];
double fNewValue = fVarA + mnDifferentialWeight * (fVarB - fVarC);
fNewValue = mrDataProvider.boundVariable(index, fNewValue);
aCandidate.mVariables[index] = fNewValue;
}
}
double fCandidateFitness = mrDataProvider.calculateFitness(aCandidate.mVariables);
// see if is better than original, if so replace
if (fCandidateFitness > mrDataProvider.calculateFitness(rOriginal.mVariables))
{
maPopulation[x] = aCandidate;
if (fCandidateFitness > mfBestFitness)
{
if (std::abs(fCandidateFitness - mfBestFitness) > constAcceptedPrecision)
{
bBestChanged = true;
mnLastChange = mnGeneration;
}
mfBestFitness = fCandidateFitness;
maBestCandidate = maPopulation[x];
}
}
}
mnGeneration++;
return bBestChanged;
}
};
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@@ -0,0 +1,178 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
*/
#ifndef INCLUDED_SCCOMP_SOURCE_PARTICLESWARM_HXX
#define INCLUDED_SCCOMP_SOURCE_PARTICLESWARM_HXX
#include <vector>
#include <random>
#include <limits>
struct Particle
{
Particle(size_t nDimensionality)
: mVelocity(nDimensionality)
, mPosition(nDimensionality)
, mCurrentFitness(std::numeric_limits<float>::lowest())
, mBestPosition(nDimensionality)
, mBestFitness(std::numeric_limits<float>::lowest())
{
}
std::vector<double> mVelocity;
std::vector<double> mPosition;
double mCurrentFitness;
std::vector<double> mBestPosition;
double mBestFitness;
};
template <typename DataProvider> class ParticleSwarmOptimizationAlgorithm
{
private:
// inertia
static constexpr double constWeight = 0.729;
// cognitive coefficient
static constexpr double c1 = 1.49445;
// social coefficient
static constexpr double c2 = 1.49445;
static constexpr double constAcceptedPrecision = 0.000000001;
DataProvider& mrDataProvider;
size_t mnNumOfParticles;
std::vector<Particle> maSwarm;
std::random_device maRandomDevice;
std::mt19937 maGenerator;
size_t mnDimensionality;
std::uniform_real_distribution<> maRandom01;
std::vector<double> maBestPosition;
double mfBestFitness;
int mnGeneration;
int mnLastChange;
public:
ParticleSwarmOptimizationAlgorithm(DataProvider& rDataProvider, size_t nNumOfParticles)
: mrDataProvider(rDataProvider)
, mnNumOfParticles(nNumOfParticles)
, maGenerator(maRandomDevice())
, mnDimensionality(mrDataProvider.getDimensionality())
, maRandom01(0.0, 1.0)
, maBestPosition(mnDimensionality)
, mfBestFitness(std::numeric_limits<float>::lowest())
, mnGeneration(0)
, mnLastChange(0)
{
}
std::vector<double> const& getResult() { return maBestPosition; }
int getGeneration() { return mnGeneration; }
int getLastChange() { return mnLastChange; }
void initialize()
{
mnGeneration = 0;
mnLastChange = 0;
maSwarm.clear();
mfBestFitness = std::numeric_limits<float>::lowest();
for (size_t i = 0; i < mnNumOfParticles; i++)
{
maSwarm.emplace_back(mnDimensionality);
Particle& rParticle = maSwarm.back();
mrDataProvider.initializeVariables(rParticle.mPosition, maGenerator);
mrDataProvider.initializeVariables(rParticle.mVelocity, maGenerator);
for (size_t k = 0; k < mnDimensionality; k++)
{
rParticle.mPosition[k] = mrDataProvider.clampVariable(k, rParticle.mPosition[k]);
}
rParticle.mCurrentFitness = mrDataProvider.calculateFitness(rParticle.mPosition);
for (size_t k = 0; k < mnDimensionality; k++)
{
rParticle.mPosition[k] = mrDataProvider.clampVariable(k, rParticle.mPosition[k]);
}
std::copy(rParticle.mPosition.begin(), rParticle.mPosition.end(),
rParticle.mBestPosition.begin());
rParticle.mBestFitness = rParticle.mCurrentFitness;
if (rParticle.mCurrentFitness > mfBestFitness)
{
mfBestFitness = rParticle.mCurrentFitness;
std::copy(rParticle.mPosition.begin(), rParticle.mPosition.end(),
maBestPosition.begin());
}
}
}
bool next()
{
bool bBestChanged = false;
for (Particle& rParticle : maSwarm)
{
double fRandom1 = maRandom01(maGenerator);
double fRandom2 = maRandom01(maGenerator);
for (size_t k = 0; k < mnDimensionality; k++)
{
rParticle.mVelocity[k]
= (constWeight * rParticle.mVelocity[k])
+ (c1 * fRandom1 * (rParticle.mBestPosition[k] - rParticle.mPosition[k]))
+ (c2 * fRandom2 * (maBestPosition[k] - rParticle.mPosition[k]));
mrDataProvider.clampVariable(k, rParticle.mVelocity[k]);
rParticle.mPosition[k] += rParticle.mVelocity[k];
rParticle.mPosition[k] = mrDataProvider.clampVariable(k, rParticle.mPosition[k]);
}
rParticle.mCurrentFitness = mrDataProvider.calculateFitness(rParticle.mPosition);
if (rParticle.mCurrentFitness > rParticle.mBestFitness)
{
rParticle.mBestFitness = rParticle.mCurrentFitness;
std::copy(rParticle.mPosition.begin(), rParticle.mPosition.end(),
rParticle.mBestPosition.begin());
}
if (rParticle.mCurrentFitness > mfBestFitness)
{
if (std::abs(rParticle.mCurrentFitness - mfBestFitness) > constAcceptedPrecision)
{
bBestChanged = true;
mnLastChange = mnGeneration;
}
std::copy(rParticle.mPosition.begin(), rParticle.mPosition.end(),
maBestPosition.begin());
mfBestFitness = rParticle.mCurrentFitness;
}
}
mnGeneration++;
return bBestChanged;
}
};
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@@ -0,0 +1,591 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
*/
#include <sal/config.h>
#include <config_lgpl.h>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/uno/XComponentContext.hpp>
#include <com/sun/star/container/XIndexAccess.hpp>
#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
#include <com/sun/star/sheet/XSpreadsheet.hpp>
#include <com/sun/star/sheet/XSolver.hpp>
#include <com/sun/star/sheet/XSolverDescription.hpp>
#include <com/sun/star/table/CellAddress.hpp>
#include <com/sun/star/table/CellContentType.hpp>
#include <com/sun/star/table/XCell.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <rtl/math.hxx>
#include <cppuhelper/implbase.hxx>
#include <cppuhelper/supportsservice.hxx>
#include <comphelper/broadcasthelper.hxx>
#include <comphelper/propertycontainer.hxx>
#include <comphelper/proparrhlp.hxx>
#include <vector>
#include <limits>
#include <chrono>
#include <random>
#include <o3tl/make_unique.hxx>
#include <unotools/resmgr.hxx>
#include "DifferentialEvolution.hxx"
#include "ParticelSwarmOptimization.hxx"
#include <strings.hrc>
using namespace css;
namespace
{
struct Bound
{
double lower;
double upper;
Bound()
// float bounds should be low/high enough for all practical uses
// otherwise we are too far away from the solution
: lower(std::numeric_limits<float>::lowest())
, upper(std::numeric_limits<float>::max())
{
}
void updateBound(sheet::SolverConstraintOperator eOp, double fValue)
{
if (eOp == sheet::SolverConstraintOperator_LESS_EQUAL)
{
// if we set the bound multiple times use the one which includes both values
// for example bound values 100, 120, 150 -> use 100 -> the lowest one
if (fValue < upper)
upper = fValue;
}
else if (eOp == sheet::SolverConstraintOperator_GREATER_EQUAL)
{
if (fValue > lower)
lower = fValue;
}
else if (eOp == sheet::SolverConstraintOperator_EQUAL)
{
lower = fValue;
upper = fValue;
}
}
};
enum
{
PROP_NONNEGATIVE,
PROP_INTEGER,
PROP_TIMEOUT,
PROP_ALGORITHM,
};
} // end anonymous namespace
typedef cppu::WeakImplHelper<sheet::XSolver, sheet::XSolverDescription, lang::XServiceInfo>
SwarmSolver_Base;
class SwarmSolver : public comphelper::OMutexAndBroadcastHelper,
public comphelper::OPropertyContainer,
public comphelper::OPropertyArrayUsageHelper<SwarmSolver>,
public SwarmSolver_Base
{
private:
uno::Reference<sheet::XSpreadsheetDocument> mxDocument;
table::CellAddress maObjective;
uno::Sequence<table::CellAddress> maVariables;
uno::Sequence<sheet::SolverConstraint> maConstraints;
bool mbMaximize;
// set via XPropertySet
bool mbNonNegative;
bool mbInteger;
sal_Int32 mnTimeout;
sal_Int32 mnAlgorithm;
// results
bool mbSuccess;
double mfResultValue;
uno::Sequence<double> maSolution;
OUString maStatus;
std::vector<Bound> maBounds;
std::vector<sheet::SolverConstraint> maNonBoundedConstraints;
private:
static OUString getResourceString(const char* pId);
uno::Reference<table::XCell> getCell(const table::CellAddress& rPosition);
void setValue(const table::CellAddress& rPosition, double fValue);
double getValue(const table::CellAddress& rPosition);
public:
SwarmSolver()
: OPropertyContainer(GetBroadcastHelper())
, mbMaximize(true)
, mbNonNegative(false)
, mbInteger(false)
, mnTimeout(60000)
, mnAlgorithm(0)
, mbSuccess(false)
, mfResultValue(0.0)
{
registerProperty("NonNegative", PROP_NONNEGATIVE, 0, &mbNonNegative,
cppu::UnoType<decltype(mbNonNegative)>::get());
registerProperty("Integer", PROP_INTEGER, 0, &mbInteger,
cppu::UnoType<decltype(mbInteger)>::get());
registerProperty("Timeout", PROP_TIMEOUT, 0, &mnTimeout,
cppu::UnoType<decltype(mnTimeout)>::get());
registerProperty("Algorithm", PROP_ALGORITHM, 0, &mnAlgorithm,
cppu::UnoType<decltype(mnAlgorithm)>::get());
}
DECLARE_XINTERFACE()
DECLARE_XTYPEPROVIDER()
virtual uno::Reference<beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override
{
return createPropertySetInfo(getInfoHelper());
}
// OPropertySetHelper
virtual cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override
{
return *getArrayHelper();
}
// OPropertyArrayUsageHelper
virtual cppu::IPropertyArrayHelper* createArrayHelper() const override
{
uno::Sequence<beans::Property> aProperties;
describeProperties(aProperties);
return new cppu::OPropertyArrayHelper(aProperties);
}
// XSolver
virtual uno::Reference<sheet::XSpreadsheetDocument> SAL_CALL getDocument() override
{
return mxDocument;
}
virtual void SAL_CALL
setDocument(const uno::Reference<sheet::XSpreadsheetDocument>& rDocument) override
{
mxDocument = rDocument;
}
virtual table::CellAddress SAL_CALL getObjective() override { return maObjective; }
virtual void SAL_CALL setObjective(const table::CellAddress& rObjective) override
{
maObjective = rObjective;
}
virtual uno::Sequence<table::CellAddress> SAL_CALL getVariables() override
{
return maVariables;
}
virtual void SAL_CALL setVariables(const uno::Sequence<table::CellAddress>& rVariables) override
{
maVariables = rVariables;
}
virtual uno::Sequence<sheet::SolverConstraint> SAL_CALL getConstraints() override
{
return maConstraints;
}
virtual void SAL_CALL
setConstraints(const uno::Sequence<sheet::SolverConstraint>& rConstraints) override
{
maConstraints = rConstraints;
}
virtual sal_Bool SAL_CALL getMaximize() override { return mbMaximize; }
virtual void SAL_CALL setMaximize(sal_Bool bMaximize) override { mbMaximize = bMaximize; }
virtual sal_Bool SAL_CALL getSuccess() override { return mbSuccess; }
virtual double SAL_CALL getResultValue() override { return mfResultValue; }
virtual uno::Sequence<double> SAL_CALL getSolution() override { return maSolution; }
virtual void SAL_CALL solve() override;
// XSolverDescription
virtual OUString SAL_CALL getComponentDescription() override
{
return SwarmSolver::getResourceString(RID_SWARM_SOLVER_COMPONENT);
}
virtual OUString SAL_CALL getStatusDescription() override { return maStatus; }
virtual OUString SAL_CALL getPropertyDescription(const OUString& rPropertyName) override
{
const char* pResId = nullptr;
switch (getInfoHelper().getHandleByName(rPropertyName))
{
case PROP_NONNEGATIVE:
pResId = RID_PROPERTY_NONNEGATIVE;
break;
case PROP_INTEGER:
pResId = RID_PROPERTY_INTEGER;
break;
case PROP_TIMEOUT:
pResId = RID_PROPERTY_TIMEOUT;
break;
case PROP_ALGORITHM:
pResId = RID_PROPERTY_ALGORITHM;
break;
default:
break;
}
return SwarmSolver::getResourceString(pResId);
}
// XServiceInfo
virtual OUString SAL_CALL getImplementationName() override
{
return OUString("com.sun.star.comp.Calc.SwarmSolver");
}
sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override
{
return cppu::supportsService(this, rServiceName);
}
uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
{
uno::Sequence<OUString> aServiceNames{ "com.sun.star.sheet.Solver" };
return aServiceNames;
}
private:
void applyVariables(std::vector<double> const& rVariables);
bool doesViolateConstraints();
public:
double calculateFitness(std::vector<double> const& rVariables);
size_t getDimensionality();
void initializeVariables(std::vector<double>& rVariables, std::mt19937& rGenerator);
double clampVariable(size_t nVarIndex, double fValue);
double boundVariable(size_t nVarIndex, double fValue);
};
OUString SwarmSolver::getResourceString(const char* pId)
{
OUString sString;
if (!pId)
return sString;
static std::locale aLocale = Translate::Create("scc");
return Translate::get(pId, aLocale);
}
uno::Reference<table::XCell> SwarmSolver::getCell(const table::CellAddress& rPosition)
{
uno::Reference<container::XIndexAccess> xSheets(mxDocument->getSheets(), uno::UNO_QUERY);
uno::Reference<sheet::XSpreadsheet> xSheet(xSheets->getByIndex(rPosition.Sheet),
uno::UNO_QUERY);
return xSheet->getCellByPosition(rPosition.Column, rPosition.Row);
}
void SwarmSolver::setValue(const table::CellAddress& rPosition, double fValue)
{
getCell(rPosition)->setValue(fValue);
}
double SwarmSolver::getValue(const table::CellAddress& rPosition)
{
return getCell(rPosition)->getValue();
}
IMPLEMENT_FORWARD_XINTERFACE2(SwarmSolver, SwarmSolver_Base, OPropertyContainer)
IMPLEMENT_FORWARD_XTYPEPROVIDER2(SwarmSolver, SwarmSolver_Base, OPropertyContainer)
void SwarmSolver::applyVariables(std::vector<double> const& rVariables)
{
for (sal_Int32 i = 0; i < maVariables.getLength(); ++i)
{
setValue(maVariables[i], rVariables[i]);
}
}
double SwarmSolver::calculateFitness(std::vector<double> const& rVariables)
{
applyVariables(rVariables);
if (doesViolateConstraints())
return std::numeric_limits<float>::lowest();
double x = getValue(maObjective);
if (mbMaximize)
return x;
else
return -x;
}
void SwarmSolver::initializeVariables(std::vector<double>& rVariables, std::mt19937& rGenerator)
{
int nTry = 1;
bool bConstraintsOK = false;
while (!bConstraintsOK && nTry < 10)
{
size_t noVariables(maVariables.getLength());
rVariables.resize(noVariables);
for (size_t i = 0; i < noVariables; ++i)
{
Bound const& rBound = maBounds[i];
if (mbInteger)
{
sal_Int64 intLower(rBound.lower);
sal_Int64 intUpper(rBound.upper);
std::uniform_int_distribution<sal_Int64> random(intLower, intUpper);
rVariables[i] = double(random(rGenerator));
}
else
{
std::uniform_real_distribution<double> random(rBound.lower, rBound.upper);
rVariables[i] = random(rGenerator);
}
}
applyVariables(rVariables);
bConstraintsOK = !doesViolateConstraints();
nTry++;
}
}
double SwarmSolver::clampVariable(size_t nVarIndex, double fValue)
{
Bound const& rBound = maBounds[nVarIndex];
double fResult = std::max(std::min(fValue, rBound.upper), rBound.lower);
if (mbInteger)
return sal_Int64(fResult);
return fResult;
}
double SwarmSolver::boundVariable(size_t nVarIndex, double fValue)
{
Bound const& rBound = maBounds[nVarIndex];
// double fResult = std::max(std::min(fValue, rBound.upper), rBound.lower);
double fResult = fValue;
while (fResult < rBound.lower || fResult > rBound.upper)
{
if (fResult < rBound.lower)
fResult = rBound.upper - (rBound.lower - fResult);
if (fResult > rBound.upper)
fResult = (fResult - rBound.upper) + rBound.lower;
}
if (mbInteger)
return sal_Int64(fResult);
return fResult;
}
size_t SwarmSolver::getDimensionality() { return maVariables.getLength(); }
bool SwarmSolver::doesViolateConstraints()
{
for (sheet::SolverConstraint& rConstraint : maNonBoundedConstraints)
{
double fLeftValue = getValue(rConstraint.Left);
double fRightValue = 0.0;
table::CellAddress aCellAddress;
if (rConstraint.Right >>= aCellAddress)
{
fRightValue = getValue(aCellAddress);
}
else if (rConstraint.Right >>= fRightValue)
{
// empty
}
else
{
return false;
}
sheet::SolverConstraintOperator eOp = rConstraint.Operator;
switch (eOp)
{
case sheet::SolverConstraintOperator_LESS_EQUAL:
{
if (fLeftValue > fRightValue)
return true;
}
break;
case sheet::SolverConstraintOperator_GREATER_EQUAL:
{
if (fLeftValue < fRightValue)
return true;
}
break;
case sheet::SolverConstraintOperator_EQUAL:
{
if (!rtl::math::approxEqual(fLeftValue, fRightValue))
return true;
}
break;
default:
break;
}
}
return false;
}
template <typename SwarmAlgorithm> class SwarmRunner
{
private:
SwarmAlgorithm& mrAlgorithm;
double mfTimeout;
static constexpr size_t mnPopulationSize = 40;
static constexpr int constNumberOfGenerationsWithoutChange = 50;
std::chrono::high_resolution_clock::time_point maStart;
std::chrono::high_resolution_clock::time_point maEnd;
public:
SwarmRunner(SwarmAlgorithm& rAlgorithm)
: mrAlgorithm(rAlgorithm)
, mfTimeout(5000)
{
}
void setTimeout(double fTimeout)
{
mfTimeout = fTimeout;
}
std::vector<double> const& solve()
{
using std::chrono::duration_cast;
using std::chrono::milliseconds;
using std::chrono::high_resolution_clock;
mrAlgorithm.initialize();
maEnd = maStart = high_resolution_clock::now();
int nLastChange = 0;
while ((mrAlgorithm.getGeneration() - nLastChange) < constNumberOfGenerationsWithoutChange
&& duration_cast<milliseconds>(maEnd - maStart).count() < mfTimeout)
{
bool bChange = mrAlgorithm.next();
if (bChange)
nLastChange = mrAlgorithm.getGeneration();
maEnd = high_resolution_clock::now();
}
return mrAlgorithm.getResult();
}
};
void SAL_CALL SwarmSolver::solve()
{
uno::Reference<frame::XModel> xModel(mxDocument, uno::UNO_QUERY_THROW);
maStatus.clear();
mbSuccess = false;
maBounds.resize(maVariables.getLength());
xModel->lockControllers();
if (mbNonNegative)
{
for (Bound& rBound : maBounds)
rBound.lower = 0;
}
// Determine variable bounds
for (sheet::SolverConstraint const& rConstraint : maConstraints)
{
table::CellAddress aLeftCellAddress = rConstraint.Left;
sheet::SolverConstraintOperator eOp = rConstraint.Operator;
size_t index = 0;
bool bFoundVariable = false;
for (table::CellAddress& rVariableCell : maVariables)
{
if (aLeftCellAddress == rVariableCell)
{
bFoundVariable = true;
table::CellAddress aCellAddress;
double fValue;
if (rConstraint.Right >>= aCellAddress)
{
uno::Reference<table::XCell> xCell = getCell(aCellAddress);
if (xCell->getType() == table::CellContentType_VALUE)
{
maBounds[index].updateBound(eOp, xCell->getValue());
}
else
{
maNonBoundedConstraints.push_back(rConstraint);
}
}
else if (rConstraint.Right >>= fValue)
{
maBounds[index].updateBound(eOp, fValue);
}
}
index++;
}
if (!bFoundVariable)
maNonBoundedConstraints.push_back(rConstraint);
}
std::vector<double> aSolution;
if (mnAlgorithm == 0)
{
DifferentialEvolutionAlgorithm<SwarmSolver> aDE(*this, 50);
SwarmRunner<DifferentialEvolutionAlgorithm<SwarmSolver>> aEvolution(aDE);
aEvolution.setTimeout(mnTimeout);
aSolution = aEvolution.solve();
}
else
{
ParticleSwarmOptimizationAlgorithm<SwarmSolver> aPSO(*this, 100);
SwarmRunner<ParticleSwarmOptimizationAlgorithm<SwarmSolver>> aSwarmSolver(aPSO);
aSwarmSolver.setTimeout(mnTimeout);
aSolution = aSwarmSolver.solve();
}
xModel->unlockControllers();
mbSuccess = true;
maSolution.realloc(aSolution.size());
std::copy(aSolution.begin(), aSolution.end(), maSolution.begin());
}
extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* SAL_CALL
com_sun_star_comp_Calc_SwarmSolver_get_implementation(uno::XComponentContext*,
uno::Sequence<uno::Any> const&)
{
return cppu::acquire(new SwarmSolver());
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
-->
<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
xmlns="http://openoffice.org/2010/uno-components">
<implementation name="com.sun.star.comp.Calc.SwarmSolver" constructor="com_sun_star_comp_Calc_SwarmSolver_get_implementation">
<service name="com.sun.star.sheet.Solver"/>
</implementation>
</component>