-
Notifications
You must be signed in to change notification settings - Fork 23
Open
Description
In my use case, I need to solve the same LP problem many times, enabling and disabling the same constraints as required.
I noticed that more often than not the results after a previous solve were incorrect, as if they were stuck in the previous basis.
In fact, forcing a refresh with clearBasis
between each solve fixes the issue, but that means having a cold start every time.
I was wondering if this behaviour is intended or something is going wrong within the internals of the solver.
The following is minimal snippet to reproduce the problem.
I have just started investigating it, so I probably missed something.
#include "soplex.h"
#include <iostream>
using namespace soplex;
void check_and_print_solution(SoPlex &soplex, int expected) {
SPxSolver::Status stat;
DVectorRational prim(2);
DVectorRational dual(1);
stat = soplex.optimize();
if (stat != SPxSolver::OPTIMAL || soplex.objValueRational() != expected) {
throw std::runtime_error((std::stringstream{}
<< "SoPlex returned with status "
<< std::to_string(stat) << " and objective value "
<< soplex.objValueRational() << " instead of "
<< expected)
.str());
}
soplex.getPrimalRational(prim);
soplex.getDualRational(dual);
std::cout << "LP solved to optimality.\n";
std::cout << "Objective value is " << soplex.objValueRational() << ".\n";
std::cout << "Primal solution is [" << prim[0] << ", " << prim[1] << "].\n";
std::cout << "Dual solution is [" << dual[0] << "].\n";
}
void test_rational() {
SoPlex mysoplex;
/* set parameters for exact solving */
mysoplex.setIntParam(SoPlex::READMODE, SoPlex::READMODE_RATIONAL);
mysoplex.setIntParam(SoPlex::SOLVEMODE, SoPlex::SOLVEMODE_RATIONAL);
mysoplex.setIntParam(SoPlex::CHECKMODE, SoPlex::CHECKMODE_RATIONAL);
mysoplex.setIntParam(SoPlex::SYNCMODE, SoPlex::SYNCMODE_AUTO);
mysoplex.setIntParam(SoPlex::SIMPLIFIER, SoPlex::SIMPLIFIER_OFF);
mysoplex.setRealParam(SoPlex::FEASTOL, 0.0);
mysoplex.setRealParam(SoPlex::OPTTOL, 0.0);
/* set the objective sense (MAXIMIZE) */
mysoplex.setIntParam(SoPlex::OBJSENSE, SoPlex::OBJSENSE_MAXIMIZE);
/* we first add variables (the integer data is converted to type Rational) */
mysoplex.addColRational(LPColRational(0, DSVectorRational(), infinity, 0)); // 0 <= x0 | 0 coeff
mysoplex.addColRational(LPColRational(1, DSVectorRational(), 1, 0)); // 0 <= x1 <= 1 | 1 coeff
/* then constraints one by one (here we show how Rationals can be used
* directly) */
DSVectorRational row1(2);
row1.add(0, 1);
row1.add(1, 1);
mysoplex.addRowRational(LPRowRational(-infinity, row1, infinity)); // C0: x0 + x1 <= infinity
// Maximize
// obj: 1 x1
// Subject To
// C0 : 1 x0 + 1 x1 <= infinity
// Bounds
// x1 <= 1
// End
check_and_print_solution(mysoplex, 1);
// Maximize
// obj: 1 x1
// Subject To
// C0 : 1 x0 + 1 x1 <= 0
// Bounds
// x1 <= 1
// End
// Enable C0
mysoplex.changeRangeRational(0, -infinity, 0); // C0: x0 + x1 <= 0
check_and_print_solution(mysoplex, 0);
// Maximize
// obj: 1 x1
// Subject To
// C0 : 1 x0 + 1 x1 <= infinity
// Bounds
// x1 <= 1
// End
// Disable C0 again
mysoplex.changeRangeRational(0, -infinity, infinity); // C0: x0 + x1 <= infinity
// mysoplex.clearBasis(); // Adding this fixes the issue, but it's very expensive, especially for repeated solves
//
// mysoplex.syncLPRational(); // Gets ignored because of SYNCMODE_AUTO
//
// mysoplex._syncLPRational(); // Does nothing
//
// mysoplex._solver.reLoad(); // Does nothing
//
// mysoplex._hasBasis = false; // Solve the issue, but requires private access and still expensive
// ERROR: we don't get 1 anymore (like in the original problem), but 0 (like the last one)
check_and_print_solution(mysoplex, 1); }
int main() {
test_rational();
return 0;
}
Metadata
Metadata
Assignees
Labels
No labels