Skip to content

Commit 224696e

Browse files
committed
Improve handling of worst-case bounds
1 parent 9450ee5 commit 224696e

File tree

4 files changed

+62
-40
lines changed

4 files changed

+62
-40
lines changed

highs/mip/HighsDomain.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1948,7 +1948,7 @@ double HighsDomain::doChangeBound(const HighsDomainChange& boundchg) {
19481948
if (!infeasible_)
19491949
updateActivityLbChange(boundchg.column, oldbound, boundchg.boundval);
19501950

1951-
if (!changedcolsflags_[boundchg.column]) {
1951+
if (!isChangedCol(boundchg.column)) {
19521952
changedcolsflags_[boundchg.column] = 1;
19531953
changedcols_.push_back(boundchg.column);
19541954
}
@@ -1960,7 +1960,7 @@ double HighsDomain::doChangeBound(const HighsDomainChange& boundchg) {
19601960
if (!infeasible_)
19611961
updateActivityUbChange(boundchg.column, oldbound, boundchg.boundval);
19621962

1963-
if (!changedcolsflags_[boundchg.column]) {
1963+
if (!isChangedCol(boundchg.column)) {
19641964
changedcolsflags_[boundchg.column] = 1;
19651965
changedcols_.push_back(boundchg.column);
19661966
}

highs/mip/HighsDomain.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -444,18 +444,19 @@ class HighsDomain {
444444

445445
changedcols_.erase(
446446
std::remove_if(changedcols_.begin(), changedcols_.end(),
447-
[&](HighsInt i) { return !changedcolsflags_[i]; }),
447+
[&](HighsInt i) { return !isChangedCol(i); }),
448448
changedcols_.end());
449449
}
450450

451-
void clearChangedCols(HighsInt start) {
452-
HighsInt end = changedcols_.size();
453-
for (HighsInt i = start; i != end; ++i)
451+
void clearChangedCols(size_t start) {
452+
for (size_t i = start; i != changedcols_.size(); ++i)
454453
changedcolsflags_[changedcols_[i]] = 0;
455454

456455
changedcols_.resize(start);
457456
}
458457

458+
bool isChangedCol(HighsInt col) const { return changedcolsflags_[col] != 0; }
459+
459460
void markPropagate(HighsInt row);
460461

461462
bool isActive(const HighsDomainChange& domchg) const {

highs/mip/HighsSearch.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ HighsInt HighsSearch::selectBranchingCandidate(int64_t maxSbIters,
413413

414414
auto analyzeSolution = [&](double objdelta,
415415
const std::vector<double>& sol) {
416-
HighsInt numChangedCols = localdom.getChangedCols().size();
416+
size_t numChangedCols = localdom.getChangedCols().size();
417417
HighsInt domchgStackSize = localdom.getDomainChangeStack().size();
418418
const auto& domchgstack = localdom.getDomainChangeStack();
419419

@@ -1518,7 +1518,7 @@ bool HighsSearch::backtrack(bool recoverBasis) {
15181518
// repropagate the node, as it may have become infeasible due to
15191519
// conflicts
15201520
HighsInt oldNumDomchgs = localdom.getNumDomainChanges();
1521-
HighsInt oldNumChangedCols = localdom.getChangedCols().size();
1521+
size_t oldNumChangedCols = localdom.getChangedCols().size();
15221522
localdom.propagate();
15231523
if (!localdom.infeasible() &&
15241524
oldNumDomchgs != localdom.getNumDomainChanges()) {
@@ -1565,7 +1565,7 @@ bool HighsSearch::backtrack(bool recoverBasis) {
15651565
if (fallbackbranch)
15661566
currnode.branching_point = currnode.branchingdecision.boundval;
15671567

1568-
HighsInt numChangedCols = localdom.getChangedCols().size();
1568+
size_t numChangedCols = localdom.getChangedCols().size();
15691569
bool passStabilizerToChildNode =
15701570
orbitsValidInChildNode(currnode.branchingdecision);
15711571
localdom.changeBound(currnode.branchingdecision);
@@ -1695,7 +1695,7 @@ bool HighsSearch::backtrackPlunge(HighsNodeQueue& nodequeue) {
16951695
currnode.branching_point = currnode.branchingdecision.boundval;
16961696

16971697
HighsInt domchgPos = domchgstack.size();
1698-
HighsInt numChangedCols = localdom.getChangedCols().size();
1698+
size_t numChangedCols = localdom.getChangedCols().size();
16991699
bool passStabilizerToChildNode =
17001700
orbitsValidInChildNode(currnode.branchingdecision);
17011701
localdom.changeBound(currnode.branchingdecision);

highs/presolve/HPresolve.cpp

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4924,10 +4924,9 @@ HPresolve::Result HPresolve::enumerateSolutions(
49244924
std::vector<std::vector<HighsInt>> solutions;
49254925
std::vector<HighsInt> vars;
49264926
std::vector<branch> branches;
4927-
std::set<HighsInt> worstCaseBounds;
4927+
std::vector<HighsInt> worstCaseBounds(model->num_col_);
49284928
std::vector<double> worstCaseLowerBound(model->num_col_, kHighsInf);
49294929
std::vector<double> worstCaseUpperBound(model->num_col_, -kHighsInf);
4930-
std::vector<HighsInt> numWorstCaseBounds(model->num_col_);
49314930

49324931
// lambda for branching (just performs initial lower branch)
49334932
auto doBranch = [&](HighsDomain& domain, const std::vector<HighsInt>& vars,
@@ -5048,6 +5047,7 @@ HPresolve::Result HPresolve::enumerateSolutions(
50485047

50495048
// main loop
50505049
HighsInt numBranches = -1;
5050+
size_t numWorstCaseBounds = 0;
50515051
while (true) {
50525052
bool backtrack = domain.infeasible();
50535053
if (!backtrack) {
@@ -5056,14 +5056,37 @@ HPresolve::Result HPresolve::enumerateSolutions(
50565056
// propagate
50575057
domain.propagate();
50585058
if (!domain.infeasible()) {
5059-
// update worst-case bounds
5060-
for (HighsInt col : domain.getChangedCols()) {
5061-
worstCaseBounds.emplace(col);
5062-
numWorstCaseBounds[col]++;
5063-
worstCaseLowerBound[col] =
5064-
std::min(worstCaseLowerBound[col], domain.col_lower_[col]);
5065-
worstCaseUpperBound[col] =
5066-
std::max(worstCaseUpperBound[col], domain.col_upper_[col]);
5059+
// handling of worst-case bounds
5060+
if (solutions[0].empty()) {
5061+
for (HighsInt col : domain.getChangedCols()) {
5062+
// initialize
5063+
worstCaseBounds[numWorstCaseBounds++] = col;
5064+
worstCaseLowerBound[col] =
5065+
std::min(worstCaseLowerBound[col], domain.col_lower_[col]);
5066+
worstCaseUpperBound[col] =
5067+
std::max(worstCaseUpperBound[col], domain.col_upper_[col]);
5068+
}
5069+
} else {
5070+
size_t i = 0;
5071+
while (i < numWorstCaseBounds) {
5072+
HighsInt col = worstCaseBounds[i];
5073+
if (!domain.isChangedCol(col)) {
5074+
// no bound changes for this variable -> reset worst-case
5075+
// bounds and remove variable
5076+
worstCaseLowerBound[col] = kHighsInf;
5077+
worstCaseUpperBound[col] = -kHighsInf;
5078+
worstCaseBounds[i] = worstCaseBounds[numWorstCaseBounds - 1];
5079+
worstCaseBounds[numWorstCaseBounds - 1] = 0;
5080+
numWorstCaseBounds--;
5081+
} else {
5082+
// update worst-case bounds
5083+
worstCaseLowerBound[col] = std::min(worstCaseLowerBound[col],
5084+
domain.col_lower_[col]);
5085+
worstCaseUpperBound[col] = std::max(worstCaseUpperBound[col],
5086+
domain.col_upper_[col]);
5087+
i++;
5088+
}
5089+
}
50675090
}
50685091
// store solution
50695092
for (size_t i = 0; i < vars.size(); i++)
@@ -5087,31 +5110,29 @@ HPresolve::Result HPresolve::enumerateSolutions(
50875110
HPRESOLVE_CHECKED_CALL(handleInfeasibility(numSolutions == 0));
50885111

50895112
// analyse worst-case bounds
5090-
for (HighsInt col : worstCaseBounds) {
5091-
if (numWorstCaseBounds[col] == numSolutions) {
5092-
assert(worstCaseLowerBound[col] >= domain.col_lower_[col]);
5093-
assert(worstCaseUpperBound[col] <= domain.col_upper_[col]);
5094-
if (worstCaseLowerBound[col] > domain.col_lower_[col]) {
5095-
// tighten lower bound
5096-
domain.changeBound(HighsBoundType::kLower, col,
5097-
worstCaseLowerBound[col],
5098-
HighsDomain::Reason::unspecified());
5099-
HPRESOLVE_CHECKED_CALL(handleInfeasibility(domain.infeasible()));
5100-
}
5101-
if (worstCaseUpperBound[col] < domain.col_upper_[col]) {
5102-
// tighten upper bound
5103-
domain.changeBound(HighsBoundType::kUpper, col,
5104-
worstCaseUpperBound[col],
5105-
HighsDomain::Reason::unspecified());
5106-
HPRESOLVE_CHECKED_CALL(handleInfeasibility(domain.infeasible()));
5107-
}
5113+
for (size_t i = 0; i < numWorstCaseBounds; i++) {
5114+
HighsInt col = worstCaseBounds[i];
5115+
assert(worstCaseLowerBound[col] >= domain.col_lower_[col]);
5116+
assert(worstCaseUpperBound[col] <= domain.col_upper_[col]);
5117+
if (worstCaseLowerBound[col] > domain.col_lower_[col]) {
5118+
// tighten lower bound
5119+
domain.changeBound(HighsBoundType::kLower, col,
5120+
worstCaseLowerBound[col],
5121+
HighsDomain::Reason::unspecified());
5122+
HPRESOLVE_CHECKED_CALL(handleInfeasibility(domain.infeasible()));
5123+
}
5124+
if (worstCaseUpperBound[col] < domain.col_upper_[col]) {
5125+
// tighten upper bound
5126+
domain.changeBound(HighsBoundType::kUpper, col,
5127+
worstCaseUpperBound[col],
5128+
HighsDomain::Reason::unspecified());
5129+
HPRESOLVE_CHECKED_CALL(handleInfeasibility(domain.infeasible()));
51085130
}
51095131
// clean up
51105132
worstCaseLowerBound[col] = kHighsInf;
51115133
worstCaseUpperBound[col] = -kHighsInf;
5112-
numWorstCaseBounds[col] = 0;
5134+
worstCaseBounds[i] = 0;
51135135
}
5114-
worstCaseBounds.clear();
51155136

51165137
for (size_t i = 0; i < vars.size(); i++) {
51175138
// get column index

0 commit comments

Comments
 (0)