@@ -458,11 +458,6 @@ void HPresolve::unlink(HighsInt pos) {
458458 markChangedCol (Acol[pos]);
459459
460460 impliedDualRowBounds.remove (Acol[pos], Arow[pos], Avalue[pos]);
461- if (colUpperSource[Acol[pos]] == Arow[pos])
462- changeImplColUpper (Acol[pos], kHighsInf , -1 );
463-
464- if (colLowerSource[Acol[pos]] == Arow[pos])
465- changeImplColLower (Acol[pos], -kHighsInf , -1 );
466461 }
467462
468463 auto get_row_left = [&](HighsInt pos) -> HighsInt& { return ARleft[pos]; };
@@ -482,14 +477,16 @@ void HPresolve::unlink(HighsInt pos) {
482477 else
483478 markChangedRow (Arow[pos]);
484479 impliedRowBounds.remove (Arow[pos], Acol[pos], Avalue[pos]);
480+ }
485481
486- if (rowDualUpperSource[Arow[pos]] == Acol[pos])
487- changeImplRowDualUpper (Arow[pos], kHighsInf , -1 );
482+ // remove implied bounds on row duals that where implied by this column's dual
483+ // constraint
484+ resetRowDualImpliedBoundsDerivedFromCol (Acol[pos]);
488485
489- if (rowDualLowerSource[Arow[pos]] == Acol[pos])
490- changeImplRowDualLower (Arow[pos], -kHighsInf , -1 );
491- }
486+ // remove implied bounds on columns that where implied by this row
487+ resetColImpliedBoundsDerivedFromRow (Arow[pos]);
492488
489+ // remove non-zero
493490 Avalue[pos] = 0 ;
494491
495492 freeslots.push_back (pos);
@@ -666,43 +663,60 @@ void HPresolve::updateColImpliedBounds(HighsInt row, HighsInt col, double val) {
666663 HighsInt{-1 });
667664}
668665
669- void HPresolve::recomputeColImpliedBounds (HighsInt row) {
670- // recompute implied column bounds affected by a modification in a row
666+ void HPresolve::resetColImpliedBounds (HighsInt col, HighsInt row) {
667+ assert (row == -1 || colLowerSource[col] == row || colUpperSource[col] == row);
668+ if (!colDeleted[col]) {
669+ // set implied bounds to infinite values if (1) they were deduced from the
670+ // given row or (2) no row was given
671+ if (colLowerSource[col] != -1 && (row == -1 || colLowerSource[col] == row))
672+ changeImplColLower (col, -kHighsInf , -1 );
673+ if (colUpperSource[col] != -1 && (row == -1 || colUpperSource[col] == row))
674+ changeImplColUpper (col, kHighsInf , -1 );
675+ } else if (row != -1 && !rowDeleted[row]) {
676+ // remove column from row-wise implied bound storage
677+ colImplSourceByRow[row].erase (col);
678+ }
679+ }
680+
681+ void HPresolve::resetRowDualImpliedBounds (HighsInt row, HighsInt col) {
682+ assert (col == -1 || rowDualLowerSource[row] == col ||
683+ rowDualUpperSource[row] == col);
684+ if (!rowDeleted[row]) {
685+ // set implied bounds to infinite values if (1) they were deduced from the
686+ // given column or (2) no column was given
687+ if (rowDualLowerSource[row] != -1 &&
688+ (col == -1 || rowDualLowerSource[row] == col))
689+ changeImplRowDualLower (row, -kHighsInf , -1 );
690+ if (rowDualUpperSource[row] != -1 &&
691+ (col == -1 || rowDualUpperSource[row] == col))
692+ changeImplRowDualUpper (row, kHighsInf , -1 );
693+ } else if (col != -1 && !colDeleted[col]) {
694+ // remove row from column-wise implied bound storage
695+ implRowDualSourceByCol[col].erase (row);
696+ }
697+ }
698+
699+ void HPresolve::resetColImpliedBoundsDerivedFromRow (HighsInt row) {
700+ // reset implied column bounds affected by a modification in a row
671701 // (removed / added non-zeros, etc.)
672702 if (colImplSourceByRow[row].empty ()) return ;
673703 std::set<HighsInt> affectedCols (colImplSourceByRow[row]);
674704 for (const HighsInt& col : affectedCols) {
675- // set implied bounds to infinite values if they were deduced from the given
676- // row
677- if (colLowerSource[col] == row) changeImplColLower (col, -kHighsInf , -1 );
678- if (colUpperSource[col] == row) changeImplColUpper (col, kHighsInf , -1 );
679-
680- // iterate over column and recompute the implied bounds
681- for (const HighsSliceNonzero& nonz : getColumnVector (col)) {
682- updateColImpliedBounds (nonz.index (), col, nonz.value ());
683- }
705+ // set implied bounds to infinite values if they were deduced from the
706+ // given row
707+ resetColImpliedBounds (col, row);
684708 }
685709}
686710
687- void HPresolve::recomputeRowDualImpliedBounds (HighsInt col) {
688- // recompute implied row dual bounds affected by a modification in a column
711+ void HPresolve::resetRowDualImpliedBoundsDerivedFromCol (HighsInt col) {
712+ // reset implied row dual bounds affected by a modification in a column
689713 // (removed / added non-zeros, etc.)
690714 if (implRowDualSourceByCol[col].empty ()) return ;
691715 std::set<HighsInt> affectedRows (implRowDualSourceByCol[col]);
692716 for (const HighsInt& row : affectedRows) {
693- // set implied bounds to infinite values if they were deduced from the given
694- // column
695- if (rowDualLowerSource[row] == col)
696- changeImplRowDualLower (row, -kHighsInf , -1 );
697- if (rowDualUpperSource[row] == col)
698- changeImplRowDualUpper (row, kHighsInf , -1 );
699-
700- // iterate over row and recompute the implied bounds
701- for (const HighsSliceNonzero& nonz : getRowVector (row)) {
702- // integer columns cannot be used to tighten bounds on dual multipliers
703- if (model->integrality_ [nonz.index ()] != HighsVarType::kInteger )
704- updateRowDualImpliedBounds (row, nonz.index (), nonz.value ());
705- }
717+ // set implied bounds to infinite values if they were deduced from the
718+ // given column
719+ resetRowDualImpliedBounds (row, col);
706720 }
707721}
708722
@@ -1652,23 +1666,25 @@ void HPresolve::addToMatrix(const HighsInt row, const HighsInt col,
16521666 }
16531667
16541668 link (pos);
1669+
1670+ // remove implied bounds on row duals that where implied by this column's
1671+ // dual constraint
1672+ resetRowDualImpliedBoundsDerivedFromCol (col);
1673+
1674+ // remove implied bounds on columns that where implied by this row
1675+ resetColImpliedBoundsDerivedFromRow (row);
1676+
16551677 } else {
16561678 double sum = Avalue[pos] + val;
16571679 if (std::abs (sum) <= options->small_matrix_value ) {
16581680 unlink (pos);
16591681 } else {
1660- // remove implied bounds on the row dual that where implied by this
1661- // columns dual constraint
1662- if (rowDualUpperSource[row] == col)
1663- changeImplRowDualUpper (row, kHighsInf , -1 );
1682+ // remove implied bounds on row duals that where implied by this column's
1683+ // dual constraint
1684+ resetRowDualImpliedBoundsDerivedFromCol (col);
16641685
1665- if (rowDualLowerSource[row] == col)
1666- changeImplRowDualLower (row, -kHighsInf , -1 );
1667-
1668- // remove implied bounds on the column that where implied by this row
1669- if (colUpperSource[col] == row) changeImplColUpper (col, kHighsInf , -1 );
1670-
1671- if (colLowerSource[col] == row) changeImplColLower (col, -kHighsInf , -1 );
1686+ // remove implied bounds on columns that where implied by this row
1687+ resetColImpliedBoundsDerivedFromRow (row);
16721688
16731689 // remove the locks and contribution to implied (dual) row bounds, then
16741690 // add then again
@@ -1711,25 +1727,15 @@ void HPresolve::markRowDeleted(HighsInt row) {
17111727 changedRowFlag[row] = true ;
17121728 rowDeleted[row] = true ;
17131729 ++numDeletedRows;
1714-
1715- // remove row from column-wise implied bound storage
1716- if (rowDualLowerSource[row] != -1 )
1717- implRowDualSourceByCol[rowDualLowerSource[row]].erase (row);
1718- if (rowDualUpperSource[row] != -1 )
1719- implRowDualSourceByCol[rowDualUpperSource[row]].erase (row);
17201730}
17211731
17221732void HPresolve::markColDeleted (HighsInt col) {
17231733 assert (!colDeleted[col]);
1734+
17241735 // prevents col from being added to change vector
17251736 changedColFlag[col] = true ;
17261737 colDeleted[col] = true ;
17271738 ++numDeletedCols;
1728- // remove column from row-wise implied bound storage
1729- if (colLowerSource[col] != -1 )
1730- colImplSourceByRow[colLowerSource[col]].erase (col);
1731- if (colUpperSource[col] != -1 )
1732- colImplSourceByRow[colUpperSource[col]].erase (col);
17331739}
17341740
17351741void HPresolve::changeColUpper (HighsInt col, double newUpper) {
@@ -2437,9 +2443,6 @@ void HPresolve::substitute(HighsInt row, HighsInt col, double rhs) {
24372443 addToMatrix (colrow, Acol[rowiter], scale * Avalue[rowiter]);
24382444 }
24392445
2440- // recompute implied column bounds affected by the substitution
2441- recomputeColImpliedBounds (colrow);
2442-
24432446 // check if this is an equation row and it now has a different size
24442447 reinsertEquation (colrow);
24452448 // printf("after substitution: ");
@@ -2469,12 +2472,6 @@ void HPresolve::substitute(HighsInt row, HighsInt col, double rhs) {
24692472 model->col_cost_ [col] = 0.0 ;
24702473 }
24712474
2472- // recompute implied row dual bounds affected by substitution
2473- for (HighsInt rowiter : rowpositions) {
2474- if (Acol[rowiter] == col) continue ;
2475- recomputeRowDualImpliedBounds (Acol[rowiter]);
2476- }
2477-
24782475 // finally remove the entries of the row that was used for substitution
24792476 for (HighsInt rowiter : rowpositions) unlink (rowiter);
24802477}
@@ -2973,15 +2970,13 @@ HPresolve::Result HPresolve::rowPresolve(HighsPostsolveStack& postsolve_stack,
29732970 assert (model->col_cost_ [col] != 0.0 );
29742971 if (colsize[col] != 1 ) return ;
29752972 if (model->col_cost_ [col] > 0 ) {
2976- assert (model->col_lower_ [col] == -kHighsInf ||
2977- (model->col_lower_ [col] <= implColLower[col] + primal_feastol &&
2978- colLowerSource[col] == row));
2973+ assert (model->col_lower_ [col] == -kHighsInf || !isLowerImplied (col) ||
2974+ colLowerSource[col] == row);
29792975 if (model->col_lower_ [col] > implColLower[col] - primal_feastol)
29802976 changeColLower (col, -kHighsInf );
29812977 } else {
2982- assert (model->col_upper_ [col] == kHighsInf ||
2983- (model->col_upper_ [col] >= implColUpper[col] - primal_feastol &&
2984- colUpperSource[col] == row));
2978+ assert (model->col_upper_ [col] == kHighsInf || !isUpperImplied (col) ||
2979+ colUpperSource[col] == row);
29852980 if (model->col_upper_ [col] < implColUpper[col] + primal_feastol)
29862981 changeColUpper (col, kHighsInf );
29872982 }
@@ -5877,10 +5872,7 @@ HPresolve::Result HPresolve::detectParallelRowsAndCols(
58775872
58785873 // remove implied bounds, since they might in general not be valid
58795874 // anymore
5880- if (colLowerSource[col] != -1 )
5881- changeImplColLower (col, -kHighsInf , -1 );
5882-
5883- if (colUpperSource[col] != -1 ) changeImplColUpper (col, kHighsInf , -1 );
5875+ resetColImpliedBounds (col);
58845876
58855877 // if an implicit integer and an integer column were merged, check if
58865878 // merged continuous column is implicit integer after merge
@@ -6060,10 +6052,9 @@ HPresolve::Result HPresolve::detectParallelRowsAndCols(
60606052 model->row_lower_ [parallelRowCand] = newLower;
60616053 }
60626054 }
6063- if (rowDualLowerSource[parallelRowCand] != -1 )
6064- changeImplRowDualLower (parallelRowCand, -kHighsInf , -1 );
6065- if (rowDualUpperSource[parallelRowCand] != -1 )
6066- changeImplRowDualUpper (parallelRowCand, kHighsInf , -1 );
6055+ // remove implied bounds, since they might in general not be valid
6056+ // anymore
6057+ resetRowDualImpliedBounds (parallelRowCand);
60676058
60686059 postsolve_stack.duplicateRow (parallelRowCand, rowUpperTightened,
60696060 rowLowerTightened, i, rowScale);
0 commit comments