Skip to content

Commit 6bba1c5

Browse files
authored
Merge pull request #2639 from fwesselm/speedUpDomColRed
Speed up dominated columns reduction
2 parents 771d015 + 384b9af commit 6bba1c5

File tree

1 file changed

+60
-22
lines changed

1 file changed

+60
-22
lines changed

highs/presolve/HPresolve.cpp

Lines changed: 60 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,13 +1156,25 @@ HPresolve::Result HPresolve::dominatedColumns(
11561156
}
11571157

11581158
// count number of fixed columns and modified bounds
1159+
HighsInt numCols = 0;
11591160
HighsInt numFixedCols = 0;
1160-
HighsInt numModifiedBounds = 0;
1161+
HighsInt numFixedColsPredBndAnalysis = 0;
1162+
HighsInt numModifiedBndsPredBndAnalysis = 0;
1163+
1164+
// parameters for predictive bound analysis
1165+
const size_t maxAverageNumDomChecksPredBndAnalysis = 10000;
1166+
const double minAverageNumRedsPredBndAnalysis = 1e-2;
1167+
1168+
// perform predictive bound analysis?
1169+
bool allowPredBndAnalysis = true;
11611170

11621171
for (HighsInt j = 0; j < model->num_col_; ++j) {
11631172
// skip deleted columns
11641173
if (colDeleted[j]) continue;
11651174

1175+
// increment counter for number of columns
1176+
numCols++;
1177+
11661178
// initialise
11671179
HighsInt bestRowPlus = -1;
11681180
HighsInt bestRowPlusLen = kHighsIInf;
@@ -1254,20 +1266,22 @@ HPresolve::Result HPresolve::dominatedColumns(
12541266
if (lowerBound > model->col_lower_[col] + primal_feastol) {
12551267
if (model->integrality_[col] != HighsVarType::kContinuous)
12561268
lowerBound = std::ceil(lowerBound - primal_feastol);
1257-
if (lowerBound == model->col_upper_[col])
1269+
if (lowerBound == model->col_upper_[col]) {
1270+
numFixedColsPredBndAnalysis++;
12581271
HPRESOLVE_CHECKED_CALL(fixCol(col, HighsInt{1}));
1259-
else if (model->integrality_[col] != HighsVarType::kContinuous) {
1260-
numModifiedBounds++;
1272+
} else if (model->integrality_[col] != HighsVarType::kContinuous) {
1273+
numModifiedBndsPredBndAnalysis++;
12611274
changeColLower(col, lowerBound);
12621275
}
12631276
}
12641277
if (upperBound < model->col_upper_[col] - primal_feastol) {
12651278
if (model->integrality_[col] != HighsVarType::kContinuous)
12661279
upperBound = std::floor(upperBound + primal_feastol);
1267-
if (upperBound == model->col_lower_[col])
1280+
if (upperBound == model->col_lower_[col]) {
1281+
numFixedColsPredBndAnalysis++;
12681282
HPRESOLVE_CHECKED_CALL(fixCol(col, HighsInt{-1}));
1269-
else if (model->integrality_[col] != HighsVarType::kContinuous) {
1270-
numModifiedBounds++;
1283+
} else if (model->integrality_[col] != HighsVarType::kContinuous) {
1284+
numModifiedBndsPredBndAnalysis++;
12711285
changeColUpper(col, upperBound);
12721286
}
12731287
}
@@ -1346,6 +1360,7 @@ HPresolve::Result HPresolve::dominatedColumns(
13461360
auto checkRow = [&](HighsInt row, HighsInt col, HighsInt direction,
13471361
double bestVal, bool boundImplied, bool hasCliques) {
13481362
storeRow(row);
1363+
bool onlyPredBndAnalysis = !boundImplied && !hasCliques;
13491364
for (const HighsSliceNonzero& nonz : getStoredRow()) {
13501365
// get column index
13511366
HighsInt k = nonz.index();
@@ -1360,7 +1375,7 @@ HPresolve::Result HPresolve::dominatedColumns(
13601375
bool sameVarType = varsHaveSameType(col, k);
13611376

13621377
// skip checks if nothing to do
1363-
if (!boundImplied && !hasCliques && !sameVarType) continue;
1378+
if (onlyPredBndAnalysis && !sameVarType) continue;
13641379

13651380
// try to fix variables or strengthen bounds
13661381
// check already known non-zeros in respective columns in advance to
@@ -1383,26 +1398,49 @@ HPresolve::Result HPresolve::dominatedColumns(
13831398
return Result::kOk;
13841399
};
13851400

1401+
// check if bounds are implied or there are cliques
1402+
bool lowerImplied = isLowerImplied(j);
1403+
bool upperImplied = isUpperImplied(j);
1404+
bool hasNegCliques =
1405+
isBinary(j) && mipsolver->mipdata_->cliquetable.numCliques(j, 0) > 0;
1406+
bool hasPosCliques =
1407+
isBinary(j) && mipsolver->mipdata_->cliquetable.numCliques(j, 1) > 0;
1408+
13861409
// use row 'bestRowMinus'
1387-
if (bestRowMinus != -1)
1388-
HPRESOLVE_CHECKED_CALL(checkRow(
1389-
bestRowMinus, j, HighsInt{-1}, ajBestRowMinus, isLowerImplied(j),
1390-
isBinary(j) &&
1391-
mipsolver->mipdata_->cliquetable.numCliques(j, 0) > 0));
1410+
if (bestRowMinus != -1 &&
1411+
(allowPredBndAnalysis || lowerImplied || hasNegCliques))
1412+
HPRESOLVE_CHECKED_CALL(checkRow(bestRowMinus, j, HighsInt{-1},
1413+
ajBestRowMinus, lowerImplied,
1414+
hasNegCliques));
13921415

13931416
// use row 'bestRowPlus'
1394-
if (!colDeleted[j] && bestRowPlus != -1)
1395-
HPRESOLVE_CHECKED_CALL(checkRow(
1396-
bestRowPlus, j, HighsInt{1}, ajBestRowPlus, isUpperImplied(j),
1397-
isBinary(j) &&
1398-
mipsolver->mipdata_->cliquetable.numCliques(j, 1) > 0));
1399-
}
1400-
1401-
if (numFixedCols > 0 || numModifiedBounds > 0)
1417+
if (!colDeleted[j] && bestRowPlus != -1 &&
1418+
(allowPredBndAnalysis || upperImplied || hasPosCliques))
1419+
HPRESOLVE_CHECKED_CALL(checkRow(bestRowPlus, j, HighsInt{1},
1420+
ajBestRowPlus, upperImplied,
1421+
hasPosCliques));
1422+
1423+
// do not use predictive bound analysis if it requires many domination
1424+
// checks and only yields few fixings or improved bounds on average
1425+
size_t averageNumDomChecksPredBndAnalysis =
1426+
numDomChecksPredBndAnalysis / static_cast<size_t>(numCols);
1427+
double averageNumRedsPredBndAnalysis =
1428+
(numFixedColsPredBndAnalysis + numModifiedBndsPredBndAnalysis) /
1429+
static_cast<double>(numCols);
1430+
allowPredBndAnalysis =
1431+
allowPredBndAnalysis &&
1432+
(numDomChecksPredBndAnalysis <=
1433+
30 * maxAverageNumDomChecksPredBndAnalysis ||
1434+
(averageNumDomChecksPredBndAnalysis <=
1435+
maxAverageNumDomChecksPredBndAnalysis &&
1436+
averageNumRedsPredBndAnalysis >= minAverageNumRedsPredBndAnalysis));
1437+
}
1438+
1439+
if (numFixedCols > 0 || numModifiedBndsPredBndAnalysis > 0)
14021440
highsLogDev(options->log_options, HighsLogType::kInfo,
14031441
"Fixed %d dominated columns and strengthened %d bounds\n",
14041442
static_cast<int>(numFixedCols),
1405-
static_cast<int>(numModifiedBounds));
1443+
static_cast<int>(numModifiedBndsPredBndAnalysis));
14061444

14071445
return Result::kOk;
14081446
}

0 commit comments

Comments
 (0)