@@ -4605,10 +4605,23 @@ HPresolve::Result HPresolve::dualFixing(HighsPostsolveStack& postsolve_stack,
46054605 }
46064606 };
46074607
4608+ // lambda for checking whether a row provides an implied bound
4609+ auto hasImpliedBound = [&](HighsInt row, double val) {
4610+ return ((val < 0 && model->row_upper_ [row] != kHighsInf ) ||
4611+ (val > 0 && model->row_lower_ [row] != -kHighsInf ));
4612+ };
4613+
46084614 // lambda for variable substitution
46094615 auto substituteCol = [&](HighsInt col, HighsInt row, HighsInt direction,
46104616 double colBound, double otherColBound) {
4611- for (const auto & rowNz : getRowVector (row)) {
4617+ // some bookkeeping
4618+ HighsInt colNonZerosChecked = 0 ;
4619+ HighsInt binVarsTried = 0 ;
4620+ // use storeRow and getStoredRow since getRowVector's rowroot[row] would be
4621+ // overwritten by subsequent findNonZero calls, which would produce
4622+ // undefined behavior
4623+ storeRow (row);
4624+ for (const auto & rowNz : getStoredRow ()) {
46124625 // skip column index that was passed to this lambda
46134626 if (rowNz.index () == col) continue ;
46144627
@@ -4618,25 +4631,27 @@ HPresolve::Result HPresolve::dualFixing(HighsPostsolveStack& postsolve_stack,
46184631 model->col_upper_ [rowNz.index ()] != 1.0 )
46194632 continue ;
46204633
4621- // check if setting the binary variable to its lower bound bound makes the
4622- // row redundant
4623- double rhs = 0.0 ;
4624- double residual = 0.0 ;
4625- if (model->row_upper_ [row] != kHighsInf ) {
4626- rhs = model->row_upper_ [row];
4627- residual = impliedRowBounds.getResidualSumUpperOrig (row, rowNz.index (),
4628- rowNz.value ());
4629- } else {
4630- rhs = -model->row_lower_ [row];
4631- residual = -impliedRowBounds.getResidualSumLowerOrig (row, rowNz.index (),
4632- rowNz.value ());
4633- }
4634- // skip binary variable if the row has not become redundant
4635- if (residual > rhs + primal_feastol) continue ;
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)
4640+ continue ;
4641+ if (model->row_lower_ [row] != -kHighsInf &&
4642+ impliedRowBounds.getResidualSumLowerOrig (row, rowNz.index (),
4643+ rowNz.value ()) <
4644+ model->row_lower_ [row] - primal_feastol)
4645+ continue ;
46364646
46374647 // store triplets (row, nonzero, nonzero) in a vector to speed up search
4648+ binVarsTried++;
4649+ nzs.clear ();
46384650 if (colsize[col] < colsize[rowNz.index ()]) {
46394651 for (const auto & colNz : getColumnVector (col)) {
4652+ // skip non-zeros that do not yield an implied bound
4653+ if (!hasImpliedBound (colNz.index (), direction * colNz.value ()))
4654+ continue ;
46404655 HighsInt nzPos = findNonzero (colNz.index (), rowNz.index ());
46414656 if (nzPos == -1 ) continue ;
46424657 nzs.push_back ({colNz.index (), colNz.value (), Avalue[nzPos]});
@@ -4645,22 +4660,19 @@ HPresolve::Result HPresolve::dualFixing(HighsPostsolveStack& postsolve_stack,
46454660 for (const auto & colNz : getColumnVector (rowNz.index ())) {
46464661 HighsInt nzPos = findNonzero (colNz.index (), col);
46474662 if (nzPos == -1 ) continue ;
4663+ // skip non-zeros that do not yield an implied bound
4664+ if (!hasImpliedBound (colNz.index (), direction * Avalue[nzPos]))
4665+ continue ;
46484666 nzs.push_back ({colNz.index (), Avalue[nzPos], colNz.value ()});
46494667 }
46504668 }
46514669
4652- // identify best implied bound
4670+ // store best bound
46534671 double bestBound = -kHighsInf ;
46544672 for (const auto & triplet : nzs) {
4655- // skip rows directly that do not yield an implied bound
4656- if ((direction * triplet.jval > 0 ||
4657- model->row_upper_ [triplet.row ] == kHighsInf ) &&
4658- (direction * triplet.jval < 0 ||
4659- model->row_lower_ [triplet.row ] == -kHighsInf ))
4660- continue ;
4661-
46624673 // compute implied bound from row given that the binary variable is at
46634674 // its upper bound
4675+ colNonZerosChecked++;
46644676 double rhs = 0.0 ;
46654677 double residual = 0.0 ;
46664678 if (direction * triplet.jval < 0 ) {
@@ -4692,7 +4704,6 @@ HPresolve::Result HPresolve::dualFixing(HighsPostsolveStack& postsolve_stack,
46924704 HPRESOLVE_CHECKED_CALL (checkLimits (postsolve_stack));
46934705 break ;
46944706 }
4695- nzs.clear ();
46964707 }
46974708 return Result::kOk ;
46984709 };
0 commit comments