Skip to content

Commit

Permalink
Merge pull request #2035 from fwesselm/impliedEqUtils
Browse files Browse the repository at this point in the history
Add two utility methods to presolve
  • Loading branch information
jajhall authored Nov 12, 2024
2 parents 02aeb70 + 835b87e commit 5cdf9ba
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 45 deletions.
90 changes: 45 additions & 45 deletions src/presolve/HPresolve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,26 @@ void HPresolve::dualImpliedFreeGetRhsAndRowType(
}
}

bool HPresolve::isImpliedEquationAtLower(HighsInt row) const {
// if the implied lower bound on a row dual is strictly positive then the row
// is an implied equation (using its lower bound) due to complementary
// slackness
bool isLbndPositive =
implRowDualLower[row] > options->dual_feasibility_tolerance;
assert(!isLbndPositive || model->row_lower_[row] != -kHighsInf);
return isLbndPositive;
}

bool HPresolve::isImpliedEquationAtUpper(HighsInt row) const {
// if the implied upper bound on a row dual is strictly negative then the row
// is an implied equation (using its upper bound) due to complementary
// slackness
bool isUbndNegative =
implRowDualUpper[row] < -options->dual_feasibility_tolerance;
assert(!isUbndNegative || model->row_upper_[row] != kHighsInf);
return isUbndNegative;
}

bool HPresolve::isImpliedIntegral(HighsInt col) {
bool runDualDetection = true;

Expand All @@ -236,15 +256,13 @@ bool HPresolve::isImpliedIntegral(HighsInt col) {
continue;
}

double rowLower =
implRowDualUpper[nz.index()] < -options->dual_feasibility_tolerance
? model->row_upper_[nz.index()]
: model->row_lower_[nz.index()];
double rowLower = isImpliedEquationAtUpper(nz.index())
? model->row_upper_[nz.index()]
: model->row_lower_[nz.index()];

double rowUpper =
implRowDualLower[nz.index()] > options->dual_feasibility_tolerance
? model->row_lower_[nz.index()]
: model->row_upper_[nz.index()];
double rowUpper = isImpliedEquationAtLower(nz.index())
? model->row_lower_[nz.index()]
: model->row_upper_[nz.index()];

if (rowUpper == rowLower) {
// if there is an equation the dual detection does not need to be tried
Expand Down Expand Up @@ -308,15 +326,13 @@ bool HPresolve::isImpliedInteger(HighsInt col) {
continue;
}

double rowLower =
implRowDualUpper[nz.index()] < -options->dual_feasibility_tolerance
? model->row_upper_[nz.index()]
: model->row_lower_[nz.index()];
double rowLower = isImpliedEquationAtUpper(nz.index())
? model->row_upper_[nz.index()]
: model->row_lower_[nz.index()];

double rowUpper =
implRowDualLower[nz.index()] > options->dual_feasibility_tolerance
? model->row_lower_[nz.index()]
: model->row_upper_[nz.index()];
double rowUpper = isImpliedEquationAtLower(nz.index())
? model->row_lower_[nz.index()]
: model->row_upper_[nz.index()];

if (rowUpper == rowLower) {
// if there is an equation the dual detection does not need to be tried
Expand Down Expand Up @@ -564,12 +580,10 @@ void HPresolve::updateRowDualImpliedBounds(HighsInt row, HighsInt col,

void HPresolve::updateColImpliedBounds(HighsInt row, HighsInt col, double val) {
// propagate implied column bound upper bound if row has an upper bound
double rowUpper = implRowDualLower[row] > options->dual_feasibility_tolerance
? model->row_lower_[row]
: model->row_upper_[row];
double rowLower = implRowDualUpper[row] < -options->dual_feasibility_tolerance
? model->row_upper_[row]
: model->row_lower_[row];
double rowUpper = isImpliedEquationAtLower(row) ? model->row_lower_[row]
: model->row_upper_[row];
double rowLower = isImpliedEquationAtUpper(row) ? model->row_upper_[row]
: model->row_lower_[row];

assert(rowLower != kHighsInf);
assert(rowUpper != -kHighsInf);
Expand Down Expand Up @@ -3067,7 +3081,7 @@ HPresolve::Result HPresolve::rowPresolve(HighsPostsolveStack& postsolve_stack,
double origRowLower = model->row_lower_[row];

if (model->row_lower_[row] != model->row_upper_[row]) {
if (implRowDualLower[row] > options->dual_feasibility_tolerance) {
if (isImpliedEquationAtLower(row)) {
// Convert to equality constraint (note that currently postsolve will not
// know about this conversion)
model->row_upper_[row] = model->row_lower_[row];
Expand All @@ -3076,7 +3090,7 @@ HPresolve::Result HPresolve::rowPresolve(HighsPostsolveStack& postsolve_stack,
changeRowDualLower(row, -kHighsInf);
if (mipsolver == nullptr)
checkRedundantBounds(rowDualLowerSource[row], row);
} else if (implRowDualUpper[row] < -options->dual_feasibility_tolerance) {
} else if (isImpliedEquationAtUpper(row)) {
// Convert to equality constraint (note that currently postsolve will not
// know about this conversion)
model->row_lower_[row] = model->row_upper_[row];
Expand Down Expand Up @@ -3769,27 +3783,13 @@ HPresolve::Result HPresolve::rowPresolve(HighsPostsolveStack& postsolve_stack,
}
}

bool hasRowUpper =
model->row_upper_[row] != kHighsInf ||
implRowDualUpper[row] < -options->dual_feasibility_tolerance;
// #1711: This looks very dodgy: surely model->row_lower_[row] !=
// -kHighsInf: dates from before 25/02/21
//
// bool hasRowLower =
// model->row_lower_[row] != kHighsInf ||
// implRowDualLower[row] > options->dual_feasibility_tolerance;
//
// Using this corrected line will reduce the number of calls to
// updateColImpliedBounds, as model->row_lower_[row] != kHighsInf is
// never false
bool hasRowLower =
model->row_lower_[row] != -kHighsInf ||
implRowDualLower[row] > options->dual_feasibility_tolerance;
// #1711: Unsurprisingly, the assert is triggered very frequently
// assert(true_hasRowLower == hasRowLower);

if ((hasRowUpper && impliedRowBounds.getNumInfSumLowerOrig(row) <= 1) ||
(hasRowLower && impliedRowBounds.getNumInfSumUpperOrig(row) <= 1)) {
// implied bounds can only be computed when row bounds are available and
// bounds on activity contain at most one infinite bound
if (((model->row_upper_[row] != kHighsInf || isImpliedEquationAtLower(row)) &&
impliedRowBounds.getNumInfSumLowerOrig(row) <= 1) ||
((model->row_lower_[row] != -kHighsInf ||
isImpliedEquationAtUpper(row)) &&
impliedRowBounds.getNumInfSumUpperOrig(row) <= 1)) {
for (const HighsSliceNonzero& nonzero : getRowVector(row))
updateColImpliedBounds(row, nonzero.index(), nonzero.value());
}
Expand Down
4 changes: 4 additions & 0 deletions src/presolve/HPresolve.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ class HPresolve {
HighsPostsolveStack::RowType& rowType,
bool relaxRowDualBounds = false);

bool isImpliedEquationAtLower(HighsInt row) const;

bool isImpliedEquationAtUpper(HighsInt row) const;

bool isImpliedIntegral(HighsInt col);

bool isImpliedInteger(HighsInt col);
Expand Down

0 comments on commit 5cdf9ba

Please sign in to comment.