Remove continuous singletons from double-sided rows - #2962
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## latest #2962 +/- ##
==========================================
- Coverage 73.22% 73.18% -0.04%
==========================================
Files 445 445
Lines 107826 108030 +204
Branches 17262 17313 +51
==========================================
+ Hits 78951 79059 +108
- Misses 28599 28695 +96
Partials 276 276 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
This is great, @Opt-Mucca! I would like to experiment with this a llittle more. Also, there is |
|
@fwesselm I was worried that I was missing something, so please make any changes you want. |
|
@Opt-Mucca I've merge the fix for
|
|
This is now draft until the maths has been checked and the error-checking code has been removed |
… HPresolve::zeroCostSingleton
|
|
|
@fwesselm, this now looks correct for LPs. My This is good to merge into latest, particularly as if fixes a bug in basis postsolve |
| // fix variable | ||
| if (numDownLocks == 0) | ||
| // fix variable if cost is driving it to its bound | ||
| if (numDownLocks == 0 && |
There was a problem hiding this comment.
The number of down-locks and up-locks includes the objective coefficient, so numDownLocks == 0 implies that model->col_cost_[col] >= 0. Similarly, numUpLocks == 0 implies model->col_cost_[col] <= 0.
There was a problem hiding this comment.
If I recall correctly, it was correcting an edge case of your logic that prompted my modification. If the cost is of the right sign but sufficiently small, then it doesn't force the column to its bound.
That said, I may have a sign wrong
I'll re-investigate and get back to you
There was a problem hiding this comment.
I also had another look and I think the following would work and handle zero cost correctly (slight modification of the code from my original PR):
while (true) {
if (numDownLocks == 0 &&
(model->col_cost_[col] > 0 || model->col_lower_[col] != -kHighsInf)) {
HPRESOLVE_CHECKED_CALL(fixColToLower(postsolve_stack, col));
break;
}
if (numUpLocks == 0 &&
(model->col_cost_[col] < 0 || model->col_upper_[col] != kHighsInf)) {
HPRESOLVE_CHECKED_CALL(fixColToUpper(postsolve_stack, col));
}
break;
}
There was a problem hiding this comment.
I also had another look and I think the following would work and handle zero cost correctly (slight modification of the code from my original PR):
while (true) { if (numDownLocks == 0 && (model->col_cost_[col] > 0 || model->col_lower_[col] != -kHighsInf)) { HPRESOLVE_CHECKED_CALL(fixColToLower(postsolve_stack, col)); break; } if (numUpLocks == 0 && (model->col_cost_[col] < 0 || model->col_upper_[col] != kHighsInf)) { HPRESOLVE_CHECKED_CALL(fixColToUpper(postsolve_stack, col)); } break; }
I appreciate the desire to fix variables, but if |cost| <= dual_feasibility_tolerance then the variable is dual feasible at any value, so there's no forcing fix. If a small cost is zero with exact arithmetic, but nonzero due to rounding error then, with your logic, there's a chance of fixing a variable to an infinite bound in error.
I'd rather be cautious and use
while (true) {
if (numDownLocks == 0 &&
(model->col_cost_[col] > options->dual_feasibility_tolerance || model->col_lower_[col] != -kHighsInf)) {
HPRESOLVE_CHECKED_CALL(fixColToLower(postsolve_stack, col));
break;
}
if (numUpLocks == 0 &&
(model->col_cost_[col] < -options->dual_feasibility_tolerance || model->col_upper_[col] != kHighsInf)) {
HPRESOLVE_CHECKED_CALL(fixColToUpper(postsolve_stack, col));
}
break;
}
I think that very few fixing opportunities will be missed, as original costs are likely to be 0 or greater than dual_feasibility_tolerance, and numerical cancelling of a cost is typically exact.
There was a problem hiding this comment.
@jajhall, my suggestion was not using a tolerance, thank you for adding this!
General idea: We currently have no explicit reduction for a column
s, with0cost, and that only appears in a single double-sided rowb_0 <= a^Tx + cs <= b_1. Dual fixing removes all cases whereb_0 == -kHighsInforb_1 == kHighsInf, but the column is left alone ifb_0andb_1are finite. Removing the column may allow additional reductions to be made.Motivation: I was playing around with an instance, trying to figure out why HiGHS wasn't making a reduction, and thought this would help (spoiler: it did not), but while doing so I stumbled upon an old TODO in the code with the exact suggestion.
@fwesselm Three major questions:
shas infinite bounds, but in theory we could handle that here. The issue is I'm not sure what to do with infinite values in postsolve.Edit: Need to look into the failing tests (they're passing locally.....). Windows does not like this change at all.