Skip to content

Commit 88782e9

Browse files
committed
Add an utility for a lower bound change
1 parent c4012f5 commit 88782e9

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
@@ -929,14 +929,7 @@ void HighsMipSolverData::runSetup() {
929929
if (domain.infeasible()) {
930930
mipsolver.modelstatus_ = HighsModelStatus::kInfeasible;
931931

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

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

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

1001987
pruned_treeweight = 1.0;
1002988
return;
@@ -1389,19 +1375,14 @@ void HighsMipSolverData::performRestart() {
13891375
// is never applied, since MIP solving is complete, and
13901376
// lower_bound is set to upper_bound, so apply the offset now, so
13911377
// that housekeeping in updatePrimalDualIntegral is correct
1392-
double prev_lower_bound = lower_bound - mipsolver.model_->offset_;
1393-
1394-
lower_bound = upper_bound;
1378+
lower_bound -= mipsolver.model_->offset_;
13951379

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

18251806
if (domain.infeasible()) {
1826-
double prev_lower_bound = lower_bound;
1827-
1828-
lower_bound = std::min(kHighsInf, upper_bound);
1829-
1830-
bool bound_change = lower_bound != prev_lower_bound;
1831-
if (!mipsolver.submip && bound_change)
1832-
updatePrimalDualIntegral(prev_lower_bound, lower_bound, upper_bound,
1833-
upper_bound);
1807+
updateLowerBound(std::min(kHighsInf, upper_bound));
18341808
pruned_treeweight = 1.0;
18351809
num_nodes += 1;
18361810
num_leaves += 1;
@@ -1872,15 +1846,7 @@ HighsLpRelaxation::Status HighsMipSolverData::evaluateRootLp() {
18721846
addIncumbent(lp.getLpSolver().getSolution().col_value,
18731847
lp.getObjective(), kSolutionSourceEvaluateNode)) {
18741848
mipsolver.modelstatus_ = HighsModelStatus::kOptimal;
1875-
1876-
double prev_lower_bound = lower_bound;
1877-
1878-
lower_bound = upper_bound;
1879-
1880-
bool bound_change = lower_bound != prev_lower_bound;
1881-
if (!mipsolver.submip && bound_change)
1882-
updatePrimalDualIntegral(prev_lower_bound, lower_bound, upper_bound,
1883-
upper_bound);
1849+
updateLowerBound(upper_bound);
18841850
pruned_treeweight = 1.0;
18851851
num_nodes += 1;
18861852
num_leaves += 1;
@@ -1895,29 +1861,15 @@ HighsLpRelaxation::Status HighsMipSolverData::evaluateRootLp() {
18951861
status = lp.getStatus();
18961862

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

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

19221874
if (lpWasSolved) {
19231875
redcostfixing.addRootRedcost(mipsolver,
@@ -1994,14 +1946,7 @@ void HighsMipSolverData::evaluateRootNode() {
19941946
domain.clearChangedCols();
19951947
lp.setObjectiveLimit(upper_limit);
19961948

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

20061951
printDisplayLine();
20071952

@@ -2690,6 +2635,15 @@ void HighsMipSolverData::limitsToBounds(double& dual_bound,
26902635
}
26912636
}
26922637

2638+
void HighsMipSolverData::updateLowerBound(double new_lower_bound) {
2639+
// Update lower bound
2640+
double prev_lower_bound = lower_bound;
2641+
lower_bound = new_lower_bound;
2642+
if (!mipsolver.submip && lower_bound != prev_lower_bound)
2643+
updatePrimalDualIntegral(prev_lower_bound, lower_bound, upper_bound,
2644+
upper_bound);
2645+
}
2646+
26932647
// Interface to callbackAction, with mipsolver_objective_value since
26942648
// incumbent value (mipsolver.solution_objective_) is not right for
26952649
// 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
@@ -314,17 +314,9 @@ void HighsPrimalHeuristics::rootReducedCost() {
314314
if (localdom.infeasible()) {
315315
localdom.conflictAnalysis(mipsolver.mipdata_->conflictPool);
316316

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

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

0 commit comments

Comments
 (0)