SwarmSolver: add a constrained linear program test
The existing tests are single variable or bound only. Add a small two variable linear program with real inequality constraints on formula cells: maximize 2x + 4y subject to x + y <= 4 and x + 3y <= 6, with both variables in [0, 10]. The two constraints meet at x = 3, y = 1, where the objective reaches its maximum of 10, and the solver finds that point. The model is written in a small FODF spreadsheet so the formulas are easy to read in the diff. Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> Change-Id: Ie9bd269a92da0db07927a6b7500e2580801369b6 Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/4056 Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com> Reviewed-by: Miklos Vajna <vmiklos@collabora.com> (cherry picked from commit 3befd66155132064c8543c0688eadd8ba2010192) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/208441 Tested-by: Xisco Fauli <xiscofauli@libreoffice.org> Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
committed by
Xisco Fauli
parent
0209dc2476
commit
f4c5255cd6
@@ -80,6 +80,7 @@ class SwarmSolverTest : public UnoApiTest
|
||||
void testUnboundedIntegerVariable();
|
||||
void testRepeatedSolveResetsState();
|
||||
void testControllersUnlockedAfterError();
|
||||
void testConstrainedLinearProgram();
|
||||
|
||||
public:
|
||||
SwarmSolverTest()
|
||||
@@ -104,6 +105,7 @@ public:
|
||||
CPPUNIT_TEST(testUnboundedIntegerVariable);
|
||||
CPPUNIT_TEST(testRepeatedSolveResetsState);
|
||||
CPPUNIT_TEST(testControllersUnlockedAfterError);
|
||||
CPPUNIT_TEST(testConstrainedLinearProgram);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
};
|
||||
|
||||
@@ -841,6 +843,57 @@ void SwarmSolverTest::testControllersUnlockedAfterError()
|
||||
!xModel->hasControllersLocked());
|
||||
}
|
||||
|
||||
void SwarmSolverTest::testConstrainedLinearProgram()
|
||||
{
|
||||
// A small linear program with two binding inequality constraints on formula
|
||||
// cells. Maximize 2x + 4y subject to x + y <= 4 and x + 3y <= 6, with both
|
||||
// variables in [0, 10]. The two constraints meet at x = 3, y = 1, where the
|
||||
// objective reaches its maximum of 10.
|
||||
|
||||
loadFromFile(u"ConstrainedLinear.fods");
|
||||
|
||||
uno::Reference<sheet::XSpreadsheetDocument> xDocument(mxComponent, uno::UNO_QUERY_THROW);
|
||||
|
||||
uno::Reference<sheet::XSolver> xSolver;
|
||||
xSolver.set(m_xContext->getServiceManager()->createInstanceWithContext(
|
||||
u"com.sun.star.comp.Calc.SwarmSolver"_ustr, m_xContext),
|
||||
uno::UNO_QUERY_THROW);
|
||||
|
||||
// objective 2x + 4y is in B3
|
||||
table::CellAddress aObjective(0, 1, 2);
|
||||
// x is A1, y is A2
|
||||
uno::Sequence<table::CellAddress> aVariables{ { 0, 0, 0 }, { 0, 0, 1 } };
|
||||
|
||||
uno::Sequence<sheet::SolverConstraint> aConstraints{
|
||||
// box bounds on the two variables
|
||||
{ table::CellAddress(0, 0, 0), sheet::SolverConstraintOperator_GREATER_EQUAL,
|
||||
uno::Any(0.0) },
|
||||
{ table::CellAddress(0, 0, 0), sheet::SolverConstraintOperator_LESS_EQUAL, uno::Any(10.0) },
|
||||
{ table::CellAddress(0, 0, 1), sheet::SolverConstraintOperator_GREATER_EQUAL,
|
||||
uno::Any(0.0) },
|
||||
{ table::CellAddress(0, 0, 1), sheet::SolverConstraintOperator_LESS_EQUAL, uno::Any(10.0) },
|
||||
// x + y <= 4 (cell B1)
|
||||
{ table::CellAddress(0, 1, 0), sheet::SolverConstraintOperator_LESS_EQUAL, uno::Any(4.0) },
|
||||
// x + 3y <= 6 (cell B2)
|
||||
{ table::CellAddress(0, 1, 1), sheet::SolverConstraintOperator_LESS_EQUAL, uno::Any(6.0) }
|
||||
};
|
||||
|
||||
xSolver->setDocument(xDocument);
|
||||
xSolver->setObjective(aObjective);
|
||||
xSolver->setVariables(aVariables);
|
||||
xSolver->setConstraints(aConstraints);
|
||||
xSolver->setMaximize(true);
|
||||
|
||||
xSolver->solve();
|
||||
|
||||
CPPUNIT_ASSERT(xSolver->getSuccess());
|
||||
|
||||
uno::Sequence<double> aSolution = xSolver->getSolution();
|
||||
CPPUNIT_ASSERT_EQUAL(aVariables.getLength(), aSolution.getLength());
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(3.0, aSolution[0], 1E-3);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, aSolution[1], 1E-3);
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(SwarmSolverTest);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.spreadsheet">
|
||||
<office:body>
|
||||
<office:spreadsheet>
|
||||
<table:table table:name="Sheet1">
|
||||
<table:table-column table:number-columns-repeated="2"/>
|
||||
<table:table-row>
|
||||
<table:table-cell office:value-type="float" office:value="0"/>
|
||||
<table:table-cell table:formula="of:=[.A1]+[.A2]" office:value-type="float" office:value="0"/>
|
||||
</table:table-row>
|
||||
<table:table-row>
|
||||
<table:table-cell office:value-type="float" office:value="0"/>
|
||||
<table:table-cell table:formula="of:=[.A1]+3*[.A2]" office:value-type="float" office:value="0"/>
|
||||
</table:table-row>
|
||||
<table:table-row>
|
||||
<table:table-cell/>
|
||||
<table:table-cell table:formula="of:=2*[.A1]+4*[.A2]" office:value-type="float" office:value="0"/>
|
||||
</table:table-row>
|
||||
</table:table>
|
||||
</office:spreadsheet>
|
||||
</office:body>
|
||||
</office:document>
|
||||
Reference in New Issue
Block a user