Skip to content

Commit f4de558

Browse files
committed
Fixed issue and added comments
1 parent 3559715 commit f4de558

File tree

1 file changed

+39
-27
lines changed

1 file changed

+39
-27
lines changed

highs/presolve/HPresolve.cpp

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4568,12 +4568,21 @@ HPresolve::Result HPresolve::dualFixing(HighsPostsolveStack& postsolve_stack,
45684568
downLockRow = -1;
45694569
upLockRow = -1;
45704570

4571+
// consider objective function
4572+
if (model->col_cost_[col] > 0)
4573+
numUpLocks++;
4574+
else if (model->col_cost_[col] < 0)
4575+
numDownLocks++;
4576+
45714577
// check coefficients
45724578
for (const auto& nz : getColumnVector(col)) {
45734579
// get row index and coefficient
45744580
HighsInt row = nz.index();
45754581
double val = nz.value();
45764582

4583+
// skip redundant rows
4584+
if (isRedundant(row)) continue;
4585+
45774586
// check lhs and rhs for finiteness
45784587
bool lhsFinite = model->row_lower_[row] != -kHighsInf;
45794588
bool rhsFinite = model->row_upper_[row] != kHighsInf;
@@ -4614,9 +4623,10 @@ HPresolve::Result HPresolve::dualFixing(HighsPostsolveStack& postsolve_stack,
46144623
// lambda for variable substitution
46154624
auto substituteCol = [&](HighsInt col, HighsInt row, HighsInt direction,
46164625
double colBound, double otherColBound) {
4617-
// some bookkeeping
4618-
HighsInt colNonZerosChecked = 0;
4619-
HighsInt binVarsTried = 0;
4626+
// check lhs and rhs for finiteness
4627+
bool lhsFinite = model->row_lower_[row] != -kHighsInf;
4628+
bool rhsFinite = model->row_upper_[row] != kHighsInf;
4629+
46204630
// use storeRow and getStoredRow since getRowVector's rowroot[row] would be
46214631
// overwritten by subsequent findNonZero calls, which would produce
46224632
// undefined behavior
@@ -4631,21 +4641,21 @@ HPresolve::Result HPresolve::dualFixing(HighsPostsolveStack& postsolve_stack,
46314641
model->col_upper_[rowNz.index()] != 1.0)
46324642
continue;
46334643

4634-
// skip binary variable if setting it to its lower bound bound does not
4635-
// make the row redundant
4636-
if (model->row_upper_[row] != kHighsInf &&
4637-
impliedRowBounds.getResidualSumUpperOrig(row, rowNz.index(),
4638-
rowNz.value()) >
4639-
model->row_upper_[row] + primal_feastol)
4644+
// skip binary variable if setting it to its lower bound does not make the
4645+
// row redundant
4646+
if (rhsFinite && impliedRowBounds.getResidualSumUpperOrig(
4647+
row, rowNz.index(), rowNz.value()) >
4648+
model->row_upper_[row] + primal_feastol)
46404649
continue;
4641-
if (model->row_lower_[row] != -kHighsInf &&
4642-
impliedRowBounds.getResidualSumLowerOrig(row, rowNz.index(),
4643-
rowNz.value()) <
4644-
model->row_lower_[row] - primal_feastol)
4650+
if (lhsFinite && impliedRowBounds.getResidualSumLowerOrig(
4651+
row, rowNz.index(), rowNz.value()) <
4652+
model->row_lower_[row] - primal_feastol)
46454653
continue;
46464654

4647-
// store triplets (row, nonzero, nonzero) in a vector to speed up search
4648-
binVarsTried++;
4655+
// now compute the implied lower bound (direction = 1) or implied upper
4656+
// bound (direction = -1) provided that the binary variable is set to its
4657+
// upper bound. store triplets (row, nonzero, nonzero) in a vector to
4658+
// speed up search
46494659
nzs.clear();
46504660
if (colsize[col] < colsize[rowNz.index()]) {
46514661
for (const auto& colNz : getColumnVector(col)) {
@@ -4667,12 +4677,11 @@ HPresolve::Result HPresolve::dualFixing(HighsPostsolveStack& postsolve_stack,
46674677
}
46684678
}
46694679

4670-
// store best bound
4680+
// find best bound
46714681
double bestBound = -kHighsInf;
46724682
for (const auto& triplet : nzs) {
46734683
// compute implied bound from row given that the binary variable is at
46744684
// its upper bound
4675-
colNonZerosChecked++;
46764685
double rhs = 0.0;
46774686
double residual = 0.0;
46784687
if (direction * triplet.jval < 0) {
@@ -4686,12 +4695,19 @@ HPresolve::Result HPresolve::dualFixing(HighsPostsolveStack& postsolve_stack,
46864695
triplet.jval) +
46874696
std::min(triplet.kval, 0.0);
46884697
}
4698+
// direction = 1: compute implied lower bound
4699+
// direction = -1: compute implied upper bound
46894700
double candidateBound = direction * (rhs - residual) / triplet.jval;
4701+
// remember best bound (note the sign switch for direction < 0 above)
46904702
bestBound = std::max(bestBound, candidateBound);
46914703
}
46924704

4705+
// round bound
4706+
if (model->integrality_[col] != HighsVarType::kContinuous)
4707+
bestBound = std::ceil(bestBound - primal_feastol);
4708+
46934709
// check if lower / upper bound is implied
4694-
if (direction * bestBound >= direction * colBound - primal_feastol) {
4710+
if (bestBound >= direction * colBound - primal_feastol) {
46954711
// substitute variable
46964712
double offset = otherColBound;
46974713
double scale = colBound - otherColBound;
@@ -4785,8 +4801,7 @@ HPresolve::Result HPresolve::dualFixing(HighsPostsolveStack& postsolve_stack,
47854801
computeLocks(col, numDownLocks, numUpLocks, downLockRow, upLockRow);
47864802

47874803
// check if variable can be fixed
4788-
if (numDownLocks + (model->col_cost_[col] < 0 ? 1 : 0) == 0 ||
4789-
numUpLocks + (model->col_cost_[col] > 0 ? 1 : 0) == 0) {
4804+
if (numDownLocks == 0 || numUpLocks == 0) {
47904805
// fix variable
47914806
if (numDownLocks == 0 ? fixColToLowerOrUnbounded(postsolve_stack, col)
47924807
: fixColToUpperOrUnbounded(postsolve_stack, col)) {
@@ -4795,22 +4810,19 @@ HPresolve::Result HPresolve::dualFixing(HighsPostsolveStack& postsolve_stack,
47954810
return Result::kDualInfeasible;
47964811
}
47974812
} else {
4798-
if (mipsolver != nullptr && (numDownLocks == 1 || numUpLocks == 1) &&
4799-
model->col_lower_[col] != -kHighsInf &&
4813+
if (mipsolver != nullptr && model->col_lower_[col] != -kHighsInf &&
48004814
model->col_upper_[col] != kHighsInf) {
48014815
// try substitution
4802-
if (numDownLocks == 1) {
4816+
if (numDownLocks == 1 && downLockRow != -1) {
48034817
HPRESOLVE_CHECKED_CALL(substituteCol(col, downLockRow, HighsInt{1},
48044818
model->col_upper_[col],
48054819
model->col_lower_[col]));
4806-
if (colDeleted[col]) return Result::kOk;
4807-
}
4808-
if (numUpLocks == 1) {
4820+
} else if (numUpLocks == 1 && upLockRow != -1) {
48094821
HPRESOLVE_CHECKED_CALL(substituteCol(col, upLockRow, HighsInt{-1},
48104822
model->col_lower_[col],
48114823
model->col_upper_[col]));
4812-
if (colDeleted[col]) return Result::kOk;
48134824
}
4825+
if (colDeleted[col]) return Result::kOk;
48144826
}
48154827
// try to strengthen bounds
48164828
double newBound = 0.0;

0 commit comments

Comments
 (0)