Skip to content

Commit 1aaf5da

Browse files
committed
Add more lambda functions
1 parent 9345801 commit 1aaf5da

File tree

4 files changed

+126
-88
lines changed

4 files changed

+126
-88
lines changed

highs/mip/HighsLpRelaxation.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,10 +237,10 @@ void HighsLpRelaxation::loadModel() {
237237
colUbBuffer.resize(lpmodel.num_col_);
238238
}
239239

240-
void HighsLpRelaxation::resetToGlobalDomain() {
240+
void HighsLpRelaxation::resetToGlobalDomain(HighsDomain& globaldom) {
241241
lpsolver.changeColsBounds(0, mipsolver.numCol() - 1,
242-
mipsolver.mipdata_->domain.col_lower_.data(),
243-
mipsolver.mipdata_->domain.col_upper_.data());
242+
globaldom.col_lower_.data(),
243+
globaldom.col_upper_.data());
244244
}
245245

246246
void HighsLpRelaxation::computeBasicDegenerateDuals(double threshold,

highs/mip/HighsLpRelaxation.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ class HighsLpRelaxation {
169169
this->adjustSymBranchingCol = adjustSymBranchingCol;
170170
}
171171

172-
void resetToGlobalDomain();
172+
void resetToGlobalDomain(HighsDomain& globaldom);
173173

174174
void computeBasicDegenerateDuals(double threshold,
175175
HighsDomain* localdom = nullptr);

highs/mip/HighsMipSolver.cpp

Lines changed: 120 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ void HighsMipSolver::run() {
351351
} else {
352352
recreatePools(1, master_worker);
353353
}
354+
master_worker.upper_bound = mipdata_->upper_bound;
354355
}
355356

356357
// Create / re-initialise workers
@@ -371,6 +372,7 @@ void HighsMipSolver::run() {
371372
recreateLpAndDomains(i, mipdata_->workers.at(i));
372373
mipdata_->workers[i].resetSearch();
373374
}
375+
mipdata_->workers[i].upper_bound = mipdata_->upper_bound;
374376
}
375377

376378
// Lambda for combining limit_reached across searches
@@ -405,17 +407,106 @@ void HighsMipSolver::run() {
405407
return search.performed_dive_;
406408
};
407409

408-
while (search.hasNode()) {
410+
auto syncSolutions = [&]() -> void {
411+
for (HighsMipWorker& worker : mipdata_->workers) {
412+
for (auto& sol : worker.solutions_) {
413+
mipdata_->addIncumbent(std::get<0>(sol), std::get<1>(sol),
414+
std::get<2>(sol));
415+
}
416+
worker.solutions_.clear();
417+
}
418+
// Pass the new upper bound information back to the worker
419+
for (HighsMipWorker& worker : mipdata_->workers) {
420+
assert(mipdata_->upper_bound <= worker.upper_bound);
421+
worker.upper_bound = mipdata_->upper_bound;
422+
}
423+
};
424+
425+
auto syncGlobalDomain = [&]() -> void {
426+
if (mipdata_->workers.size() <= 1) return;
427+
for (HighsMipWorker& worker : mipdata_->workers) {
428+
const auto& domchgstack = worker.globaldom_.getDomainChangeStack();
429+
for (const HighsDomainChange& domchg : domchgstack) {
430+
mipdata_->domain.changeBound(domchg,
431+
HighsDomain::Reason::unspecified());
432+
}
433+
}
434+
};
435+
436+
auto resetDomains = [&]() -> void {
437+
search.resetLocalDomain();
438+
mipdata_->domain.clearChangedCols();
439+
if (mipdata_->workers.size() <= 1) return;
440+
for (HighsInt i = 1; i < mip_search_concurrency; i++) {
441+
mipdata_->domains[i] = mipdata_->domain;
442+
mipdata_->workers[i].globaldom_ = mipdata_->domains[i];
443+
mipdata_->workers[i].search_ptr_->resetLocalDomain();
444+
}
445+
};
446+
447+
auto nodesRemaining = [&]() -> bool {
448+
for (HighsMipWorker& worker : mipdata_->workers) {
449+
if (worker.search_ptr_->hasNode()) return true;
450+
}
451+
return false;
452+
};
453+
454+
auto infeasibleGlobalDomain = [&]() -> bool {
455+
for (HighsMipWorker& worker : mipdata_->workers) {
456+
if (worker.globaldom_.infeasible()) return true;
457+
}
458+
return false;
459+
};
460+
461+
auto diveAllSearches = [&]() -> bool {
462+
std::vector<double> dive_times(mip_search_concurrency,
463+
-analysis_.mipTimerRead(kMipClockTheDive));
464+
std::vector<HighsSearch::NodeResult> dive_results(
465+
mip_search_concurrency, HighsSearch::NodeResult::kBranched);
466+
if (mip_search_concurrency > 1) {
467+
for (int i = 0; i < mip_search_concurrency; i++) {
468+
tg.spawn([&, i]() {
469+
if (!mipdata_->workers[i].search_ptr_->hasNode() ||
470+
mipdata_->workers[i].search_ptr_->currentNodePruned()) {
471+
dive_times[i] = -1;
472+
} else {
473+
dive_results[i] = mipdata_->workers[i].search_ptr_->dive();
474+
dive_times[i] += analysis_.mipTimerRead(kMipClockNodeSearch);
475+
}
476+
});
477+
}
478+
tg.taskWait();
479+
} else {
480+
if (!search.currentNodePruned()) {
481+
dive_results[0] = search.dive();
482+
dive_times[0] += analysis_.mipTimerRead(kMipClockNodeSearch);
483+
}
484+
}
485+
bool suboptimal = false;
486+
for (int i = 0; i < mip_search_concurrency; i++) {
487+
if (dive_times[i] != -1) {
488+
analysis_.dive_time.push_back(dive_times[i]);
489+
if (dive_results[i] == HighsSearch::NodeResult::kSubOptimal) {
490+
suboptimal = true;
491+
} else {
492+
++mipdata_->num_leaves;
493+
mipdata_->workers[i].search_ptr_->flushStatistics();
494+
}
495+
}
496+
}
497+
return suboptimal;
498+
};
499+
500+
while (nodesRemaining()) {
409501
// Possibly look for primal solution from the user
410502
if (!submip && callback_->user_callback &&
411503
callback_->active[kCallbackMipUserSolution])
412504
mipdata_->callbackUserSolution(solution_objective_,
413505
kUserMipSolutionCallbackOriginBeforeDive);
414506

415507
analysis_.mipTimerStart(kMipClockPerformAging1);
416-
mipdata_->conflictPool.performAging();
417-
for (int i = 0; i < mip_search_concurrency; i++) {
418-
mipdata_->workers[i].conflictpool_.performAging();
508+
for (HighsConflictPool& conflictpool : mipdata_->conflictpools) {
509+
conflictpool.performAging();
419510
}
420511
analysis_.mipTimerStop(kMipClockPerformAging1);
421512
// set iteration limit for each lp solve during the dive to 10 times the
@@ -489,62 +580,19 @@ void HighsMipSolver::run() {
489580

490581
considerHeuristics = false;
491582

492-
if (mipdata_->domain.infeasible()) break;
583+
if (mipdata_->parallelLockActive()) syncSolutions();
584+
if (infeasibleGlobalDomain()) break;
493585

494-
// MT: My attempt at a parallel dive
495-
std::vector<double> dive_times(mip_search_concurrency,
496-
-analysis_.mipTimerRead(kMipClockTheDive));
497-
std::vector<HighsSearch::NodeResult> dive_results(
498-
mip_search_concurrency, HighsSearch::NodeResult::kBranched);
499-
for (int i = 0; i < mip_search_concurrency; i++) {
500-
tg.spawn([&, i]() {
501-
if (!mipdata_->workers[i].search_ptr_->hasNode() ||
502-
mipdata_->workers[i].search_ptr_->currentNodePruned()) {
503-
dive_times[i] = -1;
504-
} else {
505-
dive_results[i] = mipdata_->workers[i].search_ptr_->dive();
506-
dive_times[i] += analysis_.mipTimerRead(kMipClockNodeSearch);
507-
}
508-
});
509-
}
510-
tg.taskWait();
511-
bool suboptimal = false;
512-
for (int i = 0; i < 1; i++) {
513-
if (dive_times[i] != -1) {
514-
analysis_.dive_time.push_back(dive_times[i]);
515-
if (dive_results[i] == HighsSearch::NodeResult::kSubOptimal) {
516-
suboptimal = true;
517-
} else {
518-
++mipdata_->num_leaves;
519-
mipdata_->workers[i].search_ptr_->flushStatistics();
520-
}
521-
}
522-
}
586+
bool suboptimal = diveAllSearches();
523587
if (suboptimal) break;
524588

525-
// if (!search.currentNodePruned()) {
526-
// double this_dive_time = -analysis_.mipTimerRead(kMipClockTheDive);
527-
// analysis_.mipTimerStart(kMipClockTheDive);
528-
// const HighsSearch::NodeResult search_dive_result = search.dive();
529-
// analysis_.mipTimerStop(kMipClockTheDive);
530-
// if (analysis_.analyse_mip_time) {
531-
// this_dive_time += analysis_.mipTimerRead(kMipClockNodeSearch);
532-
// analysis_.dive_time.push_back(this_dive_time);
533-
// }
534-
// if (search_dive_result == HighsSearch::NodeResult::kSubOptimal)
535-
// break;
536-
//
537-
// ++mipdata_->num_leaves;
538-
//
539-
// search.flushStatistics();
540-
// }
541-
589+
if (mipdata_->parallelLockActive()) syncSolutions();
542590
if (mipdata_->checkLimits()) {
543591
limit_reached = true;
544592
break;
545593
}
546594

547-
if (mipdata_->workers.size() <= 1) {
595+
if (!mipdata_->parallelLockActive()) {
548596
HighsInt numPlungeNodes = mipdata_->num_nodes - plungestart;
549597
if (numPlungeNodes >= 100) break;
550598

@@ -555,51 +603,39 @@ void HighsMipSolver::run() {
555603
if (!backtrack_plunge) break;
556604
}
557605

558-
assert(search.hasNode());
606+
if (!mipdata_->parallelLockActive()) assert(search.hasNode());
559607

560-
if (mipdata_->conflictPool.getNumConflicts() >
561-
options_mip_->mip_pool_soft_limit) {
562-
analysis_.mipTimerStart(kMipClockPerformAging2);
563-
mipdata_->conflictPool.performAging();
564-
analysis_.mipTimerStop(kMipClockPerformAging2);
608+
analysis_.mipTimerStart(kMipClockPerformAging2);
609+
for (HighsConflictPool& conflictpool : mipdata_->conflictpools) {
610+
if (conflictpool.getNumConflicts() >
611+
options_mip_->mip_pool_soft_limit) {
612+
conflictpool.performAging();
613+
}
565614
}
566-
// for (int i = 0; i < mip_search_concurrency; i++) {
567-
// if (mipdata_->workers[i].conflictpool_.getNumConflicts() >
568-
// options_mip_->mip_pool_soft_limit) {
569-
// analysis_.mipTimerStart(kMipClockPerformAging2);
570-
// mipdata_->workers[i].conflictpool_.performAging();
571-
// analysis_.mipTimerStop(kMipClockPerformAging2);
572-
// }
573-
// }
615+
analysis_.mipTimerStop(kMipClockPerformAging2);
574616

575617
for (int i = 0; i < mip_search_concurrency; i++) {
576618
mipdata_->workers[i].search_ptr_->flushStatistics();
577619
}
578620
mipdata_->printDisplayLine();
579-
if (mipdata_->workers.size() >= 2) break;
621+
if (mipdata_->parallelLockActive()) break;
580622
// printf("continue plunging due to good estimate\n");
581623
} // while (true)
582624
analysis_.mipTimerStop(kMipClockDive);
583625

584626
analysis_.mipTimerStart(kMipClockOpenNodesToQueue0);
585-
search.openNodesToQueue(mipdata_->nodequeue);
586-
// for (int i = 0; i < mip_search_concurrency; i++) {
587-
// mipdata_->workers[i].search_ptr_->openNodesToQueue(mipdata_->nodequeue);
588-
// }
627+
for (HighsMipWorker& worker : mipdata_->workers) {
628+
if (worker.search_ptr_->hasNode()) {
629+
worker.search_ptr_->openNodesToQueue(mipdata_->nodequeue);
630+
}
631+
}
589632
analysis_.mipTimerStop(kMipClockOpenNodesToQueue0);
590633

591634
for (int i = 0; i < mip_search_concurrency; i++) {
592635
mipdata_->workers[i].search_ptr_->flushStatistics();
593636
}
594637

595-
// MT: Should a primal solution sync be done here?
596-
for (int i = 0; i < mip_search_concurrency; i++) {
597-
for (auto& sol : mipdata_->workers[i].solutions_) {
598-
mipdata_->addIncumbent(std::get<0>(sol), std::get<1>(sol),
599-
std::get<2>(sol));
600-
}
601-
mipdata_->workers[i].solutions_.clear();
602-
}
638+
if (mipdata_->parallelLockActive()) syncSolutions();
603639

604640
if (limit_reached) {
605641
double prev_lower_bound = mipdata_->lower_bound;
@@ -617,11 +653,12 @@ void HighsMipSolver::run() {
617653
}
618654

619655
// the search datastructure should have no installed node now
620-
assert(!search.hasNode());
656+
assert(!nodesRemaining());
621657

622658
// propagate the global domain
623-
// todo MT: When does the global domain ever update in parallel dive?
624659
analysis_.mipTimerStart(kMipClockDomainPropgate);
660+
// sync global domain changes from parallel dives
661+
syncGlobalDomain();
625662
mipdata_->domain.propagate();
626663
analysis_.mipTimerStop(kMipClockDomainPropgate);
627664

@@ -671,9 +708,10 @@ void HighsMipSolver::run() {
671708
mipdata_->implications.cleanupVarbounds(col);
672709

673710
mipdata_->domain.setDomainChangeStack(std::vector<HighsDomainChange>());
711+
// resetDomains();
674712
search.resetLocalDomain();
675-
676713
mipdata_->domain.clearChangedCols();
714+
677715
mipdata_->removeFixedIndices();
678716
analysis_.mipTimerStop(kMipClockUpdateLocalDomain);
679717
}

highs/mip/HighsSearch.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,7 @@ int64_t HighsSearch::getStrongBranchingLpIterations() const {
919919
}
920920

921921
void HighsSearch::resetLocalDomain() {
922-
this->lp->resetToGlobalDomain();
922+
this->lp->resetToGlobalDomain(getDomain());
923923
localdom = getDomain();
924924

925925
#ifndef NDEBUG
@@ -1997,7 +1997,7 @@ const std::vector<HighsInt>& HighsSearch::getIntegralCols() const {
19971997
}
19981998

19991999
HighsDomain& HighsSearch::getDomain() const {
2000-
return mipsolver.mipdata_->domain;
2000+
return mipworker.globaldom_;
20012001
}
20022002

20032003
HighsConflictPool& HighsSearch::getConflictPool() const {

0 commit comments

Comments
 (0)