Skip to content

Commit caee88f

Browse files
authored
Merge pull request #2151 from fwesselm/fix-1960-new
Fix 1960
2 parents 1cb7c67 + c13d1a0 commit caee88f

File tree

2 files changed

+79
-84
lines changed

2 files changed

+79
-84
lines changed

src/presolve/HPresolve.cpp

Lines changed: 72 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -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

17221732
void 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

17351741
void 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
}
@@ -5876,10 +5871,7 @@ HPresolve::Result HPresolve::detectParallelRowsAndCols(
58765871

58775872
// remove implied bounds, since they might in general not be valid
58785873
// anymore
5879-
if (colLowerSource[col] != -1)
5880-
changeImplColLower(col, -kHighsInf, -1);
5881-
5882-
if (colUpperSource[col] != -1) changeImplColUpper(col, kHighsInf, -1);
5874+
resetColImpliedBounds(col);
58835875

58845876
// if an implicit integer and an integer column were merged, check if
58855877
// merged continuous column is implicit integer after merge
@@ -6059,10 +6051,9 @@ HPresolve::Result HPresolve::detectParallelRowsAndCols(
60596051
model->row_lower_[parallelRowCand] = newLower;
60606052
}
60616053
}
6062-
if (rowDualLowerSource[parallelRowCand] != -1)
6063-
changeImplRowDualLower(parallelRowCand, -kHighsInf, -1);
6064-
if (rowDualUpperSource[parallelRowCand] != -1)
6065-
changeImplRowDualUpper(parallelRowCand, kHighsInf, -1);
6054+
// remove implied bounds, since they might in general not be valid
6055+
// anymore
6056+
resetRowDualImpliedBounds(parallelRowCand);
60666057

60676058
postsolve_stack.duplicateRow(parallelRowCand, rowUpperTightened,
60686059
rowLowerTightened, i, rowScale);

src/presolve/HPresolve.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,15 @@ class HPresolve {
154154

155155
void updateColImpliedBounds(HighsInt row, HighsInt col, double val);
156156

157-
void recomputeColImpliedBounds(HighsInt row);
157+
void updateRowDualImpliedBounds(HighsInt row, HighsInt col, double val);
158158

159-
void recomputeRowDualImpliedBounds(HighsInt col);
159+
void resetColImpliedBounds(HighsInt col, HighsInt row = -1);
160160

161-
void updateRowDualImpliedBounds(HighsInt row, HighsInt col, double val);
161+
void resetRowDualImpliedBounds(HighsInt row, HighsInt col = -1);
162+
163+
void resetColImpliedBoundsDerivedFromRow(HighsInt row);
164+
165+
void resetRowDualImpliedBoundsDerivedFromCol(HighsInt col);
162166

163167
bool rowCoefficientsIntegral(HighsInt row, double scale) const;
164168

0 commit comments

Comments
 (0)