Skip to content

Commit 22b1ed1

Browse files
authored
Merge pull request #2724 from fwesselm/solutionEnumeratiosImprovements
Minor improvements to solution enumeration
2 parents 367cdba + b213563 commit 22b1ed1

File tree

1 file changed

+40
-41
lines changed

1 file changed

+40
-41
lines changed

highs/presolve/HPresolve.cpp

Lines changed: 40 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4880,6 +4880,7 @@ HPresolve::Result HPresolve::enumerateSolutions(
48804880
// maximum size of a row and maximum number of rows that will be checked
48814881
const size_t maxRowSize = 8;
48824882
const HighsInt maxNumRowsChecked = 400;
4883+
const size_t maxNumSolutions = 1 << maxRowSize;
48834884

48844885
// check rows
48854886
struct candidaterow {
@@ -4921,22 +4922,22 @@ HPresolve::Result HPresolve::enumerateSolutions(
49214922
size_t numDomainChanges;
49224923
size_t numChangedCols;
49234924
};
4924-
std::vector<std::vector<HighsInt>> solutions;
4925-
std::vector<HighsInt> vars;
4926-
std::vector<branch> branches;
4925+
std::vector<std::array<HighsInt, maxNumSolutions>> solutions(maxRowSize);
4926+
std::vector<HighsInt> vars(maxRowSize);
4927+
std::vector<branch> branches(maxRowSize);
49274928
std::vector<HighsInt> worstCaseBounds(model->num_col_);
49284929
std::vector<double> worstCaseLowerBound(model->num_col_, kHighsInf);
49294930
std::vector<double> worstCaseUpperBound(model->num_col_, -kHighsInf);
49304931
std::vector<double> col_lower(domain.col_lower_);
49314932
std::vector<double> col_upper(domain.col_upper_);
49324933

49334934
// lambda for branching (just performs initial lower branch)
4934-
auto doBranch = [&](HighsInt& numBranches) {
4935+
auto doBranch = [&](size_t numVars, HighsInt& numBranches) {
49354936
// find variable for branching
49364937
HighsInt branchvar = -1;
4937-
for (HighsInt j : vars) {
4938-
if (!domain.isFixed(j)) {
4939-
branchvar = j;
4938+
for (size_t i = 0; i < numVars; i++) {
4939+
if (!domain.isFixed(vars[i])) {
4940+
branchvar = vars[i];
49404941
break;
49414942
}
49424943
}
@@ -4974,25 +4975,26 @@ HPresolve::Result HPresolve::enumerateSolutions(
49744975
};
49754976

49764977
// lambda for checking if a solution was found
4977-
auto solutionFound = [&]() {
4978-
for (HighsInt j : vars)
4979-
if (!domain.isFixed(j)) return false;
4978+
auto solutionFound = [&](size_t numVars) {
4979+
for (size_t i = 0; i < numVars; i++)
4980+
if (!domain.isFixed(vars[i])) return false;
49804981
return true;
49814982
};
49824983

49834984
// lambda for checking whether the values of two binary variables are
49844985
// identical in all feasible solutions
4985-
auto identicalVars = [&](size_t index1, size_t index2) {
4986-
for (size_t sol = 0; sol < solutions[index1].size(); sol++) {
4986+
auto identicalVars = [&](size_t numSolutions, size_t index1, size_t index2) {
4987+
for (size_t sol = 0; sol < numSolutions; sol++) {
49874988
if (solutions[index1][sol] != solutions[index2][sol]) return false;
49884989
}
49894990
return true;
49904991
};
49914992

49924993
// lambda for checking whether the values of two binary variables are
49934994
// complementary in all feasible solutions
4994-
auto complementaryVars = [&](size_t index1, size_t index2) {
4995-
for (size_t sol = 0; sol < solutions[index1].size(); sol++) {
4995+
auto complementaryVars = [&](size_t numSolutions, size_t index1,
4996+
size_t index2) {
4997+
for (size_t sol = 0; sol < numSolutions; sol++) {
49964998
if (solutions[index1][sol] != 1 - solutions[index2][sol]) return false;
49974999
}
49985000
return true;
@@ -5014,12 +5016,13 @@ HPresolve::Result HPresolve::enumerateSolutions(
50145016
numWorstCaseBounds--;
50155017
};
50165018

5017-
auto handleSolution = [&](size_t& numWorstCaseBounds, bool& noReductions) {
5019+
auto handleSolution = [&](size_t numVars, size_t& numSolutions,
5020+
size_t& numWorstCaseBounds, bool& noReductions) {
50185021
// propagate
50195022
domain.propagate();
50205023
if (domain.infeasible()) return;
50215024
// handling of worst-case bounds
5022-
if (solutions[0].empty()) {
5025+
if (numSolutions == 0) {
50235026
// initialize
50245027
for (HighsInt col : domain.getChangedCols()) {
50255028
worstCaseBounds[numWorstCaseBounds++] = col;
@@ -5052,17 +5055,18 @@ HPresolve::Result HPresolve::enumerateSolutions(
50525055
}
50535056
}
50545057
// store solution
5055-
for (size_t i = 0; i < vars.size(); i++)
5056-
solutions[i].push_back(domain.col_lower_[vars[i]] == 0.0 ? HighsInt{0}
5057-
: HighsInt{1});
5058+
for (size_t i = 0; i < numVars; i++)
5059+
solutions[i][numSolutions] =
5060+
(domain.col_lower_[vars[i]] == 0.0 ? HighsInt{0} : HighsInt{1});
5061+
numSolutions++;
50585062

50595063
// if no reductions are possible, stop enumerating solutions
50605064
noReductions = numWorstCaseBounds == 0;
50615065
if (noReductions) {
5062-
for (size_t i = 0; i < vars.size() - 1; i++) {
5063-
for (size_t ii = i + 1; ii < vars.size(); ii++) {
5064-
noReductions = noReductions && !identicalVars(i, ii) &&
5065-
!complementaryVars(i, ii);
5066+
for (size_t i = 0; i < numVars - 1; i++) {
5067+
for (size_t ii = i + 1; ii < numVars; ii++) {
5068+
noReductions = noReductions && !identicalVars(numSolutions, i, ii) &&
5069+
!complementaryVars(numSolutions, i, ii);
50665070
if (!noReductions) break;
50675071
}
50685072
if (!noReductions) break;
@@ -5082,44 +5086,39 @@ HPresolve::Result HPresolve::enumerateSolutions(
50825086
// check if maximum is reached
50835087
if (numRowsChecked > maxNumRowsChecked) break;
50845088
// check row
5085-
vars.clear();
5086-
vars.reserve(rowsize[row]);
5089+
size_t numVars = 0;
50875090
for (HighsInt j = mipsolver->mipdata_->ARstart_[row];
50885091
j < mipsolver->mipdata_->ARstart_[row + 1]; j++) {
50895092
// get index
50905093
HighsInt col = mipsolver->mipdata_->ARindex_[j];
50915094
// skip fixed variables
50925095
if (domain.isFixed(col)) continue;
50935096
// store index of binary variable
5094-
vars.push_back(col);
5097+
vars[numVars++] = col;
50955098
}
5096-
if (vars.empty()) continue;
5099+
if (numVars == 0) continue;
50975100

50985101
// clear changed cols
50995102
domain.clearChangedCols();
51005103

5101-
// vectors for storing variable status and solutions
5102-
branches.clear();
5103-
solutions.clear();
5104-
branches.resize(vars.size());
5105-
solutions.resize(vars.size());
5106-
51075104
// main loop
51085105
HighsInt numBranches = -1;
51095106
size_t numWorstCaseBounds = 0;
5107+
size_t numSolutions = 0;
51105108
bool noReductions = false;
51115109
while (true) {
51125110
bool backtrack = domain.infeasible();
51135111
if (!backtrack) {
5114-
backtrack = solutionFound();
5112+
backtrack = solutionFound(numVars);
51155113
if (backtrack) {
5116-
handleSolution(numWorstCaseBounds, noReductions);
5114+
handleSolution(numVars, numSolutions, numWorstCaseBounds,
5115+
noReductions);
51175116
if (noReductions) break;
51185117
}
51195118
}
51205119
// branch or backtrack
51215120
if (!backtrack)
5122-
doBranch(numBranches);
5121+
doBranch(numVars, numBranches);
51235122
else if (!doBacktrack(numBranches))
51245123
break;
51255124
}
@@ -5131,7 +5130,7 @@ HPresolve::Result HPresolve::enumerateSolutions(
51315130
}
51325131

51335132
// no solutions -> infeasible
5134-
HPRESOLVE_CHECKED_CALL(handleInfeasibility(solutions[0].empty()));
5133+
HPRESOLVE_CHECKED_CALL(handleInfeasibility(numSolutions == 0));
51355134

51365135
// analyse worst-case bounds
51375136
for (size_t i = 0; i < numWorstCaseBounds; i++) {
@@ -5160,26 +5159,26 @@ HPresolve::Result HPresolve::enumerateSolutions(
51605159
worstCaseBounds[i] = 0;
51615160
}
51625161

5163-
for (size_t i = 0; i < vars.size() - 1; i++) {
5162+
for (size_t i = 0; i < numVars - 1; i++) {
51645163
// get column index
51655164
HighsInt col = vars[i];
51665165
// skip already fixed columns
51675166
if (domain.isFixed(col)) continue;
5168-
for (size_t ii = i + 1; ii < vars.size(); ii++) {
5167+
for (size_t ii = i + 1; ii < numVars; ii++) {
51695168
// get column index
51705169
HighsInt col2 = vars[ii];
51715170
// skip already fixed columns
51725171
if (domain.isFixed(col2)) continue;
51735172
// check if two binary variables take identical or complementary
51745173
// values in all feasible solutions
5175-
if (identicalVars(i, ii)) {
5174+
if (identicalVars(numSolutions, i, ii)) {
51765175
// add clique x_1 + (1 - x_2) = 1 to clique table
51775176
std::array<HighsCliqueTable::CliqueVar, 2> clique;
51785177
clique[0] = HighsCliqueTable::CliqueVar(col, 0);
51795178
clique[1] = HighsCliqueTable::CliqueVar(col2, 1);
51805179
cliquetable.addClique(*mipsolver, clique.data(), 2, true);
51815180
HPRESOLVE_CHECKED_CALL(handleInfeasibility(domain.infeasible()));
5182-
} else if (complementaryVars(i, ii)) {
5181+
} else if (complementaryVars(numSolutions, i, ii)) {
51835182
// add clique x_1 + x_2 = 1 to clique table
51845183
std::array<HighsCliqueTable::CliqueVar, 2> clique;
51855184
clique[0] = HighsCliqueTable::CliqueVar(col, 0);

0 commit comments

Comments
 (0)