Skip to content

Commit 0ff2fae

Browse files
committed
Check if variables form a clique
1 parent f623bf8 commit 0ff2fae

1 file changed

Lines changed: 40 additions & 9 deletions

File tree

highs/presolve/HPresolve.cpp

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5018,8 +5018,16 @@ HPresolve::Result HPresolve::enumerateSolutions(
50185018
numWorstCaseBounds--;
50195019
};
50205020

5021+
auto varsFormClique = [&](size_t numVars, size_t minNumActiveCols,
5022+
size_t maxNumActiveCols) {
5023+
return (maxNumActiveCols == 1 || (minNumActiveCols == numVars - 1 &&
5024+
maxNumActiveCols == numVars - 1));
5025+
};
5026+
50215027
auto handleSolution = [&](size_t numVars, size_t& numSolutions,
5022-
size_t& numWorstCaseBounds, bool& noReductions) {
5028+
size_t& numWorstCaseBounds,
5029+
size_t& minNumActiveCols, size_t& maxNumActiveCols,
5030+
bool& noReductions) {
50235031
// propagate
50245032
domain.propagate();
50255033
if (domain.infeasible()) return;
@@ -5056,14 +5064,21 @@ HPresolve::Result HPresolve::enumerateSolutions(
50565064
}
50575065
}
50585066
}
5059-
// store solution
5060-
for (size_t i = 0; i < numVars; i++)
5061-
solutions[i][numSolutions] =
5062-
(domain.col_lower_[vars[i]] == 0.0 ? HighsInt{0} : HighsInt{1});
5067+
// store solution and compute minimum and maximum number of active variables
5068+
// (i.e. those having solution value of 1)
5069+
size_t numActiveCols = 0;
5070+
for (size_t i = 0; i < numVars; i++) {
5071+
HighsInt solValue = domain.col_lower_[vars[i]] == 0.0 ? 0 : 1;
5072+
solutions[i][numSolutions] = solValue;
5073+
if (solValue != 0) numActiveCols++;
5074+
}
5075+
minNumActiveCols = std::min(minNumActiveCols, numActiveCols);
5076+
maxNumActiveCols = std::max(maxNumActiveCols, numActiveCols);
50635077
numSolutions++;
50645078

50655079
// if no reductions are possible, stop enumerating solutions
5066-
noReductions = numWorstCaseBounds == 0;
5080+
noReductions = numWorstCaseBounds == 0 &&
5081+
!varsFormClique(numVars, minNumActiveCols, maxNumActiveCols);
50675082
if (noReductions) {
50685083
for (size_t i = 0; i < numVars - 1; i++) {
50695084
for (size_t ii = i + 1; ii < numVars; ii++) {
@@ -5078,6 +5093,7 @@ HPresolve::Result HPresolve::enumerateSolutions(
50785093

50795094
// loop over candidate rows
50805095
HighsInt numRowsChecked = 0;
5096+
HighsInt numCliquesFound = 0;
50815097
for (const auto& r : rows) {
50825098
// get row index
50835099
HighsInt row = r.row;
@@ -5107,14 +5123,16 @@ HPresolve::Result HPresolve::enumerateSolutions(
51075123
HighsInt numBranches = -1;
51085124
size_t numWorstCaseBounds = 0;
51095125
size_t numSolutions = 0;
5126+
size_t minNumActiveCols = numVars;
5127+
size_t maxNumActiveCols = 0;
51105128
bool noReductions = false;
51115129
while (true) {
51125130
bool backtrack = domain.infeasible();
51135131
if (!backtrack) {
51145132
backtrack = solutionFound(numVars);
51155133
if (backtrack) {
51165134
handleSolution(numVars, numSolutions, numWorstCaseBounds,
5117-
noReductions);
5135+
minNumActiveCols, maxNumActiveCols, noReductions);
51185136
if (noReductions) break;
51195137
}
51205138
}
@@ -5138,11 +5156,22 @@ HPresolve::Result HPresolve::enumerateSolutions(
51385156
// no solutions -> infeasible
51395157
HPRESOLVE_CHECKED_CALL(handleInfeasibility(numSolutions == 0));
51405158

5159+
// check if all variables form a clique
5160+
if (varsFormClique(numVars, minNumActiveCols, maxNumActiveCols)) {
5161+
numCliquesFound++;
5162+
std::vector<HighsCliqueTable::CliqueVar> clique(numVars);
5163+
for (size_t i = 0; i < numVars; i++)
5164+
clique[i] =
5165+
HighsCliqueTable::CliqueVar(vars[i], maxNumActiveCols == 1 ? 1 : 0);
5166+
cliquetable.addClique(*mipsolver, clique.data(),
5167+
static_cast<HighsInt>(numVars),
5168+
minNumActiveCols == maxNumActiveCols);
5169+
HPRESOLVE_CHECKED_CALL(handleInfeasibility(domain.infeasible()));
5170+
}
5171+
51415172
// analyse worst-case bounds
51425173
for (size_t i = 0; i < numWorstCaseBounds; i++) {
51435174
HighsInt col = worstCaseBounds[i];
5144-
assert(worstCaseLowerBound[col] >= domain.col_lower_[col]);
5145-
assert(worstCaseUpperBound[col] <= domain.col_upper_[col]);
51465175
if (worstCaseLowerBound[col] > domain.col_lower_[col]) {
51475176
// tighten lower bound
51485177
col_lower[col] = worstCaseLowerBound[col];
@@ -5175,13 +5204,15 @@ HPresolve::Result HPresolve::enumerateSolutions(
51755204
// values in all feasible solutions
51765205
if (identicalVars(numSolutions, i, ii)) {
51775206
// add clique (1 - x_1) + x_2 = 1 to clique table
5207+
numCliquesFound++;
51785208
std::array<HighsCliqueTable::CliqueVar, 2> clique;
51795209
clique[0] = HighsCliqueTable::CliqueVar(col, 0);
51805210
clique[1] = HighsCliqueTable::CliqueVar(col2, 1);
51815211
cliquetable.addClique(*mipsolver, clique.data(), 2, true);
51825212
HPRESOLVE_CHECKED_CALL(handleInfeasibility(domain.infeasible()));
51835213
} else if (complementaryVars(numSolutions, i, ii)) {
51845214
// add clique (1 - x_1) + (1 - x_2) = 1 to clique table
5215+
numCliquesFound++;
51855216
std::array<HighsCliqueTable::CliqueVar, 2> clique;
51865217
clique[0] = HighsCliqueTable::CliqueVar(col, 0);
51875218
clique[1] = HighsCliqueTable::CliqueVar(col2, 0);

0 commit comments

Comments
 (0)