Skip to content

Commit 7ff42d0

Browse files
authored
Merge pull request #2669 from fwesselm/addUtilityLowerBndChange
Add utility for lower bound change
2 parents a7033a1 + 805fc8d commit 7ff42d0

File tree

4 files changed

+33
-139
lines changed

4 files changed

+33
-139
lines changed

highs/mip/HighsMipSolver.cpp

Lines changed: 11 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -220,15 +220,7 @@ void HighsMipSolver::run() {
220220
search.setLpRelaxation(&mipdata_->lp);
221221
sepa.setLpRelaxation(&mipdata_->lp);
222222

223-
double prev_lower_bound = mipdata_->lower_bound;
224-
225-
mipdata_->lower_bound = mipdata_->nodequeue.getBestLowerBound();
226-
227-
bool bound_change = mipdata_->lower_bound != prev_lower_bound;
228-
if (!submip && bound_change)
229-
mipdata_->updatePrimalDualIntegral(prev_lower_bound, mipdata_->lower_bound,
230-
mipdata_->upper_bound,
231-
mipdata_->upper_bound);
223+
mipdata_->updateLowerBound(mipdata_->nodequeue.getBestLowerBound());
232224

233225
mipdata_->printDisplayLine();
234226
search.installNode(mipdata_->nodequeue.popBestBoundNode());
@@ -368,16 +360,8 @@ void HighsMipSolver::run() {
368360
search.flushStatistics();
369361

370362
if (limit_reached) {
371-
double prev_lower_bound = mipdata_->lower_bound;
372-
373-
mipdata_->lower_bound = std::min(mipdata_->upper_bound,
374-
mipdata_->nodequeue.getBestLowerBound());
375-
376-
bool bound_change = mipdata_->lower_bound != prev_lower_bound;
377-
if (!submip && bound_change)
378-
mipdata_->updatePrimalDualIntegral(
379-
prev_lower_bound, mipdata_->lower_bound, mipdata_->upper_bound,
380-
mipdata_->upper_bound);
363+
mipdata_->updateLowerBound(std::min(
364+
mipdata_->upper_bound, mipdata_->nodequeue.getBestLowerBound()));
381365
mipdata_->printDisplayLine();
382366
break;
383367
}
@@ -399,29 +383,13 @@ void HighsMipSolver::run() {
399383
if (mipdata_->domain.infeasible()) {
400384
mipdata_->nodequeue.clear();
401385
mipdata_->pruned_treeweight = 1.0;
402-
403-
double prev_lower_bound = mipdata_->lower_bound;
404-
405-
mipdata_->lower_bound = std::min(kHighsInf, mipdata_->upper_bound);
406-
407-
bool bound_change = mipdata_->lower_bound != prev_lower_bound;
408-
if (!submip && bound_change)
409-
mipdata_->updatePrimalDualIntegral(
410-
prev_lower_bound, mipdata_->lower_bound, mipdata_->upper_bound,
411-
mipdata_->upper_bound);
386+
mipdata_->updateLowerBound(std::min(kHighsInf, mipdata_->upper_bound));
412387
mipdata_->printDisplayLine();
413388
break;
414389
}
415390

416-
double prev_lower_bound = mipdata_->lower_bound;
417-
418-
mipdata_->lower_bound = std::min(mipdata_->upper_bound,
419-
mipdata_->nodequeue.getBestLowerBound());
420-
bool bound_change = mipdata_->lower_bound != prev_lower_bound;
421-
if (!submip && bound_change)
422-
mipdata_->updatePrimalDualIntegral(
423-
prev_lower_bound, mipdata_->lower_bound, mipdata_->upper_bound,
424-
mipdata_->upper_bound);
391+
mipdata_->updateLowerBound(std::min(
392+
mipdata_->upper_bound, mipdata_->nodequeue.getBestLowerBound()));
425393
mipdata_->printDisplayLine();
426394
if (mipdata_->nodequeue.empty()) break;
427395

@@ -594,15 +562,9 @@ void HighsMipSolver::run() {
594562
mipdata_->nodequeue.clear();
595563
mipdata_->pruned_treeweight = 1.0;
596564

597-
double prev_lower_bound = mipdata_->lower_bound;
598-
599-
mipdata_->lower_bound = std::min(kHighsInf, mipdata_->upper_bound);
565+
mipdata_->updateLowerBound(
566+
std::min(kHighsInf, mipdata_->upper_bound));
600567

601-
bool bound_change = mipdata_->lower_bound != prev_lower_bound;
602-
if (!submip && bound_change)
603-
mipdata_->updatePrimalDualIntegral(
604-
prev_lower_bound, mipdata_->lower_bound, mipdata_->upper_bound,
605-
mipdata_->upper_bound);
606568
analysis_.mipTimerStop(kMipClockNodePrunedLoop);
607569
break;
608570
}
@@ -613,16 +575,9 @@ void HighsMipSolver::run() {
613575
}
614576

615577
// analysis_.mipTimerStart(kMipClockStoreBasis);
616-
double prev_lower_bound = mipdata_->lower_bound;
578+
mipdata_->updateLowerBound(std::min(
579+
mipdata_->upper_bound, mipdata_->nodequeue.getBestLowerBound()));
617580

618-
mipdata_->lower_bound = std::min(
619-
mipdata_->upper_bound, mipdata_->nodequeue.getBestLowerBound());
620-
621-
bool bound_change = mipdata_->lower_bound != prev_lower_bound;
622-
if (!submip && bound_change)
623-
mipdata_->updatePrimalDualIntegral(
624-
prev_lower_bound, mipdata_->lower_bound, mipdata_->upper_bound,
625-
mipdata_->upper_bound);
626581
mipdata_->printDisplayLine();
627582

628583
if (!mipdata_->domain.getChangedCols().empty()) {
@@ -661,15 +616,7 @@ void HighsMipSolver::run() {
661616
mipdata_->pruned_treeweight = 1.0;
662617

663618
analysis_.mipTimerStart(kMipClockStoreBasis);
664-
double prev_lower_bound = mipdata_->lower_bound;
665-
666-
mipdata_->lower_bound = std::min(kHighsInf, mipdata_->upper_bound);
667-
668-
bool bound_change = mipdata_->lower_bound != prev_lower_bound;
669-
if (!submip && bound_change)
670-
mipdata_->updatePrimalDualIntegral(
671-
prev_lower_bound, mipdata_->lower_bound, mipdata_->upper_bound,
672-
mipdata_->upper_bound);
619+
mipdata_->updateLowerBound(std::min(kHighsInf, mipdata_->upper_bound));
673620
break;
674621
}
675622

highs/mip/HighsMipSolverData.cpp

Lines changed: 19 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -930,14 +930,7 @@ void HighsMipSolverData::runSetup() {
930930
if (domain.infeasible()) {
931931
mipsolver.modelstatus_ = HighsModelStatus::kInfeasible;
932932

933-
double prev_lower_bound = lower_bound;
934-
935-
lower_bound = kHighsInf;
936-
937-
bool bound_change = lower_bound != prev_lower_bound;
938-
if (!mipsolver.submip && bound_change)
939-
updatePrimalDualIntegral(prev_lower_bound, lower_bound, upper_bound,
940-
upper_bound);
933+
updateLowerBound(kHighsInf);
941934

942935
pruned_treeweight = 1.0;
943936
return;
@@ -990,14 +983,7 @@ void HighsMipSolverData::runSetup() {
990983
// integer variable is fixed to a fractional value -> infeasible
991984
mipsolver.modelstatus_ = HighsModelStatus::kInfeasible;
992985

993-
double prev_lower_bound = lower_bound;
994-
995-
lower_bound = kHighsInf;
996-
997-
bool bound_change = lower_bound != prev_lower_bound;
998-
if (!mipsolver.submip && bound_change)
999-
updatePrimalDualIntegral(prev_lower_bound, lower_bound,
1000-
upper_bound, upper_bound);
986+
updateLowerBound(kHighsInf);
1001987

1002988
pruned_treeweight = 1.0;
1003989
return;
@@ -1390,19 +1376,14 @@ void HighsMipSolverData::performRestart() {
13901376
// is never applied, since MIP solving is complete, and
13911377
// lower_bound is set to upper_bound, so apply the offset now, so
13921378
// that housekeeping in updatePrimalDualIntegral is correct
1393-
double prev_lower_bound = lower_bound - mipsolver.model_->offset_;
1394-
1395-
lower_bound = upper_bound;
1379+
lower_bound -= mipsolver.model_->offset_;
13961380

13971381
// There must be a gap change, since it's now zero, so always call
13981382
// updatePrimalDualIntegral (unless solving a sub-MIP)
13991383
//
14001384
// Surely there must be a lower bound change
1401-
bool bound_change = lower_bound != prev_lower_bound;
1402-
assert(bound_change);
1403-
if (!mipsolver.submip && bound_change)
1404-
updatePrimalDualIntegral(prev_lower_bound, lower_bound, upper_bound,
1405-
upper_bound);
1385+
updateLowerBound(upper_bound);
1386+
14061387
if (mipsolver.solution_objective_ != kHighsInf &&
14071388
mipsolver.modelstatus_ == HighsModelStatus::kInfeasible)
14081389
mipsolver.modelstatus_ = HighsModelStatus::kOptimal;
@@ -1824,14 +1805,7 @@ HighsLpRelaxation::Status HighsMipSolverData::evaluateRootLp() {
18241805
globalOrbits->orbitalFixing(domain);
18251806

18261807
if (domain.infeasible()) {
1827-
double prev_lower_bound = lower_bound;
1828-
1829-
lower_bound = std::min(kHighsInf, upper_bound);
1830-
1831-
bool bound_change = lower_bound != prev_lower_bound;
1832-
if (!mipsolver.submip && bound_change)
1833-
updatePrimalDualIntegral(prev_lower_bound, lower_bound, upper_bound,
1834-
upper_bound);
1808+
updateLowerBound(std::min(kHighsInf, upper_bound));
18351809
pruned_treeweight = 1.0;
18361810
num_nodes += 1;
18371811
num_leaves += 1;
@@ -1873,15 +1847,7 @@ HighsLpRelaxation::Status HighsMipSolverData::evaluateRootLp() {
18731847
addIncumbent(lp.getLpSolver().getSolution().col_value,
18741848
lp.getObjective(), kSolutionSourceEvaluateNode)) {
18751849
mipsolver.modelstatus_ = HighsModelStatus::kOptimal;
1876-
1877-
double prev_lower_bound = lower_bound;
1878-
1879-
lower_bound = upper_bound;
1880-
1881-
bool bound_change = lower_bound != prev_lower_bound;
1882-
if (!mipsolver.submip && bound_change)
1883-
updatePrimalDualIntegral(prev_lower_bound, lower_bound, upper_bound,
1884-
upper_bound);
1850+
updateLowerBound(upper_bound);
18851851
pruned_treeweight = 1.0;
18861852
num_nodes += 1;
18871853
num_leaves += 1;
@@ -1896,29 +1862,15 @@ HighsLpRelaxation::Status HighsMipSolverData::evaluateRootLp() {
18961862
status = lp.getStatus();
18971863

18981864
if (status == HighsLpRelaxation::Status::kInfeasible) {
1899-
double prev_lower_bound = lower_bound;
1900-
1901-
lower_bound = std::min(kHighsInf, upper_bound);
1902-
1903-
bool bound_change = lower_bound != prev_lower_bound;
1904-
if (!mipsolver.submip && bound_change)
1905-
updatePrimalDualIntegral(prev_lower_bound, lower_bound, upper_bound,
1906-
upper_bound);
1865+
updateLowerBound(std::min(kHighsInf, upper_bound));
19071866
pruned_treeweight = 1.0;
19081867
num_nodes += 1;
19091868
num_leaves += 1;
19101869
return status;
19111870
}
19121871

19131872
if (lp.unscaledDualFeasible(lp.getStatus())) {
1914-
double prev_lower_bound = lower_bound;
1915-
1916-
lower_bound = std::max(lp.getObjective(), lower_bound);
1917-
1918-
bool bound_change = lower_bound != prev_lower_bound;
1919-
if (!mipsolver.submip && bound_change)
1920-
updatePrimalDualIntegral(prev_lower_bound, lower_bound, upper_bound,
1921-
upper_bound);
1873+
updateLowerBound(std::max(lp.getObjective(), lower_bound));
19221874

19231875
if (lpWasSolved) {
19241876
redcostfixing.addRootRedcost(mipsolver,
@@ -1995,14 +1947,7 @@ void HighsMipSolverData::evaluateRootNode() {
19951947
domain.clearChangedCols();
19961948
lp.setObjectiveLimit(upper_limit);
19971949

1998-
double prev_lower_bound = lower_bound;
1999-
2000-
lower_bound = std::max(lower_bound, domain.getObjectiveLowerBound());
2001-
2002-
bool bound_change = lower_bound != prev_lower_bound;
2003-
if (!mipsolver.submip && bound_change)
2004-
updatePrimalDualIntegral(prev_lower_bound, lower_bound, upper_bound,
2005-
upper_bound);
1950+
updateLowerBound(std::max(lower_bound, domain.getObjectiveLowerBound()));
20061951

20071952
printDisplayLine();
20081953

@@ -2691,6 +2636,15 @@ void HighsMipSolverData::limitsToBounds(double& dual_bound,
26912636
}
26922637
}
26932638

2639+
void HighsMipSolverData::updateLowerBound(double new_lower_bound) {
2640+
// Update lower bound
2641+
double prev_lower_bound = lower_bound;
2642+
lower_bound = new_lower_bound;
2643+
if (!mipsolver.submip && lower_bound != prev_lower_bound)
2644+
updatePrimalDualIntegral(prev_lower_bound, lower_bound, upper_bound,
2645+
upper_bound);
2646+
}
2647+
26942648
// Interface to callbackAction, with mipsolver_objective_value since
26952649
// incumbent value (mipsolver.solution_objective_) is not right for
26962650
// callback_type = kCallbackMipSolution

highs/mip/HighsMipSolverData.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ struct HighsMipSolverData {
293293
bool checkLimits(int64_t nodeOffset = 0) const;
294294
void limitsToBounds(double& dual_bound, double& primal_bound,
295295
double& mip_rel_gap) const;
296+
void updateLowerBound(double new_lower_bound);
296297
void setCallbackDataOut(const double mipsolver_objective_value) const;
297298
bool interruptFromCallbackWithData(const int callback_type,
298299
const double mipsolver_objective_value,

highs/mip/HighsPrimalHeuristics.cpp

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -313,17 +313,9 @@ void HighsPrimalHeuristics::rootReducedCost() {
313313
if (localdom.infeasible()) {
314314
localdom.conflictAnalysis(mipsolver.mipdata_->conflictPool);
315315

316-
double prev_lower_bound = mipsolver.mipdata_->lower_bound;
316+
mipsolver.mipdata_->updateLowerBound(
317+
std::max(mipsolver.mipdata_->lower_bound, currCutoff));
317318

318-
mipsolver.mipdata_->lower_bound =
319-
std::max(mipsolver.mipdata_->lower_bound, currCutoff);
320-
321-
const bool bound_change =
322-
mipsolver.mipdata_->lower_bound != prev_lower_bound;
323-
if (!mipsolver.submip && bound_change)
324-
mipsolver.mipdata_->updatePrimalDualIntegral(
325-
prev_lower_bound, mipsolver.mipdata_->lower_bound,
326-
mipsolver.mipdata_->upper_bound, mipsolver.mipdata_->upper_bound);
327319
localdom.backtrack();
328320
if (localdom.getBranchDepth() == 0) break;
329321
neighbourhood.backtracked();

0 commit comments

Comments
 (0)