diff --git a/sc/qa/unit/SwarmSolverTest.cxx b/sc/qa/unit/SwarmSolverTest.cxx index 0df2f5806a2d..993b539f19e4 100644 --- a/sc/qa/unit/SwarmSolverTest.cxx +++ b/sc/qa/unit/SwarmSolverTest.cxx @@ -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 xDocument(mxComponent, uno::UNO_QUERY_THROW); + + uno::Reference 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 aVariables{ { 0, 0, 0 }, { 0, 0, 1 } }; + + uno::Sequence 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 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); } diff --git a/sc/qa/unit/data/solver/ConstrainedLinear.fods b/sc/qa/unit/data/solver/ConstrainedLinear.fods new file mode 100644 index 000000000000..5954b9a23f65 --- /dev/null +++ b/sc/qa/unit/data/solver/ConstrainedLinear.fods @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + +