-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Warm start after changing row range #38
Comments
Thanks for posting this well-defined issue. I will look into it. I'm guessing this is on the current master? Just to note: Warm-starting (while still beneficial) is not as impactful in rational solving as in normal double-precision mode. |
Yeah this is definitely a bug in SoPlex (not even the rational part, the same happens if you solve with tolerances). It sets the row to be nonbasic-free after you deactivate it, but the implementation does not consider these types for entering the basis apparently. I will try to fix this, but it might take some time. As a workaround in the meantime, you could set the rhs to some big M (effectively also deactivating it), and it will work correctly. |
Thanks, I'll quickly update you:
If I find any other insights, I'll share them here. void check_and_print_solution_real(SoPlex &soplex, double expected) {
SPxSolver::Status stat;
VectorReal prim(2);
VectorReal 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.getPrimal(prim);
soplex.getDual(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_real() {
SoPlex mysoplex;
/* 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.addColReal(LPColReal(0, DSVectorReal(), infinity, 0)); // 0 <= x0 | 0 coeff
mysoplex.addColReal(LPColReal(1, DSVectorReal(), 1, 0)); // 0 <= x1 <= 1 | 1 coeff
/* then constraints one by one (here we show how Rationals can be used
* directly) */
DSVectorReal row1(2);
row1.add(0, 1);
row1.add(1, 1);
mysoplex.addRowReal(LPRowReal(-infinity, row1, infinity)); // C0: 1 + 1 <= infinity
// Maximize
// obj: 1 x1
// Subject To
// C0 : 1 x0 + 1 x1 <= infinity
// Bounds
// x1 <= 1
// End
check_and_print_solution_real(mysoplex, 1);
// Maximize
// obj: 1 x1
// Subject To
// C0 : 1 x0 + 1 x1 <= 0
// Bounds
// x1 <= 1
// End
// Enable C0
mysoplex.changeRangeReal(0, -infinity, 0); // C0: 1 + 1 <= 0
check_and_print_solution_real(mysoplex, 0);
// Maximize
// obj: 1 x1
// Subject To
// C0 : 1 x0 + 1 x1 <= infinity
// Bounds
// x1 <= 1
// End
// Disable C0 again
mysoplex.changeRangeReal(0, -infinity, infinity); // C1: 1 + 0 <= infinity
// ATTEMPTS
// Adding this fixes the issue, but it's very expensive, especially for repeated solves
// mysoplex.clearBasis();
// Gets ignored because of SYNCMODE_AUTO
// mysoplex.syncLPReal();
// Does nothing
// mysoplex._syncLPReal();
// Does nothing
// mysoplex._solver.reLoad();
// Solve the issue, but requires private access and still expensive
// mysoplex._hasBasis = false;
// ERROR: we don't get 1 anymore (like in the original problem), but 0 (like the last one)
check_and_print_solution_real(mysoplex, 1);
} |
You could try the following workaround (not even a bad one, maybe): Set the rhs to the max. activity of the constraint + small positive value (0.1, e.g.). By max. activity I mean any upper bound on a^T x over the feasible region (assuming the constraint reads a^T x <= b). This effectively removes the constraint, should avoid SoPlex's problems with infinity, and give you a hotstart. It is trivially possible if all your variables have finite bounds. |
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.
The text was updated successfully, but these errors were encountered: