Skip to content

Commit 88e3eb2

Browse files
committed
Add master_worker.search as default
1 parent 353896d commit 88e3eb2

File tree

4 files changed

+123
-32
lines changed

4 files changed

+123
-32
lines changed

highs/mip/HighsDomain.cpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1634,13 +1634,15 @@ void HighsDomain::updateActivityLbChange(HighsInt col, double oldbound,
16341634
}
16351635
}
16361636

1637-
if (!infeasible_) {
1638-
for (CutpoolPropagation& cutpoolprop : cutpoolpropagation)
1639-
cutpoolprop.updateActivityLbChange(col, oldbound, newbound);
1640-
} else {
1637+
if (infeasible_) {
16411638
assert(infeasible_reason.type == Reason::kModelRowLower ||
1642-
infeasible_reason.type == Reason::kModelRowUpper);
1639+
infeasible_reason.type == Reason::kModelRowUpper);
16431640
assert(infeasible_reason.index == mip->a_matrix_.index_[end - 1]);
1641+
} else {
1642+
for (CutpoolPropagation& cutpoolprop : cutpoolpropagation)
1643+
if (!infeasible_) {
1644+
cutpoolprop.updateActivityLbChange(col, oldbound, newbound);
1645+
}
16441646
}
16451647

16461648
if (infeasible_) {
@@ -1795,13 +1797,15 @@ void HighsDomain::updateActivityUbChange(HighsInt col, double oldbound,
17951797
}
17961798
}
17971799

1798-
if (!infeasible_) {
1799-
for (CutpoolPropagation& cutpoolprop : cutpoolpropagation)
1800-
cutpoolprop.updateActivityUbChange(col, oldbound, newbound);
1801-
} else {
1800+
if (infeasible_) {
18021801
assert(infeasible_reason.type == Reason::kModelRowLower ||
1803-
infeasible_reason.type == Reason::kModelRowUpper);
1802+
infeasible_reason.type == Reason::kModelRowUpper);
18041803
assert(infeasible_reason.index == mip->a_matrix_.index_[end - 1]);
1804+
} else {
1805+
for (CutpoolPropagation& cutpoolprop : cutpoolpropagation)
1806+
if (!infeasible_) {
1807+
cutpoolprop.updateActivityUbChange(col, oldbound, newbound);
1808+
}
18051809
}
18061810

18071811
if (infeasible_) {

highs/mip/HighsMipSolver.cpp

Lines changed: 95 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,11 @@ void HighsMipSolver::run() {
256256

257257
// This version works during refactor with the master pseudocost.
258258
// valgrind OK.
259-
HighsSearch search{master_worker, mipdata_->pseudocost};
260-
search.setLpRelaxation(&mipdata_->lp);
259+
// HighsSearch search{master_worker, mipdata_->pseudocost};
260+
// search.setLpRelaxation(&mipdata_->lp);
261+
// MT: I think search should be ties to the master worker
262+
master_worker.resetSearchDomain();
263+
HighsSearch& search = *master_worker.search_ptr_;
261264

262265
// This search is from the worker and will use the worker pseudocost.
263266
// does not work yet, fails at domain propagation somewhere.
@@ -312,18 +315,23 @@ void HighsMipSolver::run() {
312315
search_started = true;
313316
const HighsInt mip_search_concurrency = options_mip_->mip_search_concurrency;
314317
const HighsInt num_worker = mip_search_concurrency - 1;
318+
highs::parallel::TaskGroup tg;
315319

316-
for (int i = 0; i < num_worker; i++) {
317-
mipdata_->lps.emplace_back(*this);
318-
mipdata_->workers.emplace_back(*this, mipdata_->lps.back());
320+
for (int i = 1; i < mip_search_concurrency; i++) {
321+
if (mipdata_->numRestarts <= mipdata_->numRestartsRoot) {
322+
mipdata_->lps.emplace_back(*this);
323+
mipdata_->workers.emplace_back(*this, mipdata_->lps.back());
324+
} else {
325+
mipdata_->workers[i].resetSearchDomain();
326+
}
319327
}
320328

321329
// Lambda for combining limit_reached across searches
322330
auto limitReached = [&]() -> bool {
323331
bool limit_reached = false;
324332
for (HighsInt iSearch = 0; iSearch < mip_search_concurrency; iSearch++)
325-
limit_reached =
326-
limit_reached || mipdata_->workers[iSearch].search_ptr_->limit_reached_;
333+
limit_reached = limit_reached ||
334+
mipdata_->workers[iSearch].search_ptr_->limit_reached_;
327335
return limit_reached;
328336
};
329337

@@ -332,13 +340,13 @@ void HighsMipSolver::run() {
332340
bool break_search = false;
333341
for (HighsInt iSearch = 0; iSearch < mip_search_concurrency; iSearch++)
334342
break_search =
335-
break_search || mipdata_->workers[iSearch].search_ptr_->break_search_;
343+
break_search || mipdata_->workers[iSearch].search_ptr_->break_search_;
336344
return break_search;
337345
};
338346

339347
// Lambda checking whether loop pass is to be skipped
340348
auto performedDive = [&](const HighsSearch& search,
341-
const HighsInt iSearch) -> bool {
349+
const HighsInt iSearch) -> bool {
342350
if (iSearch == 0) {
343351
assert(search.performed_dive_);
344352
} else {
@@ -359,6 +367,9 @@ void HighsMipSolver::run() {
359367

360368
analysis_.mipTimerStart(kMipClockPerformAging1);
361369
mipdata_->conflictPool.performAging();
370+
for (int i = 0; i < mip_search_concurrency; i++) {
371+
mipdata_->workers[i].conflictpool_.performAging();
372+
}
362373
analysis_.mipTimerStop(kMipClockPerformAging1);
363374
// set iteration limit for each lp solve during the dive to 10 times the
364375
// average nodes
@@ -369,6 +380,9 @@ void HighsMipSolver::run() {
369380
HighsInt((3 * mipdata_->firstrootlpiters) / 2)});
370381

371382
mipdata_->lp.setIterationLimit(iterlimit);
383+
for (int i = 0; i < mip_search_concurrency; i++) {
384+
mipdata_->lps[i].setIterationLimit(iterlimit);
385+
}
372386

373387
// perform the dive and put the open nodes to the queue
374388
size_t plungestart = mipdata_->num_nodes;
@@ -430,21 +444,80 @@ void HighsMipSolver::run() {
430444

431445
if (mipdata_->domain.infeasible()) break;
432446

433-
if (!search.currentNodePruned()) {
434-
double this_dive_time = -analysis_.mipTimerRead(kMipClockTheDive);
435-
analysis_.mipTimerStart(kMipClockTheDive);
436-
const HighsSearch::NodeResult search_dive_result = search.dive();
437-
analysis_.mipTimerStop(kMipClockTheDive);
438-
if (analysis_.analyse_mip_time) {
439-
this_dive_time += analysis_.mipTimerRead(kMipClockNodeSearch);
440-
analysis_.dive_time.push_back(this_dive_time);
447+
// MT: My attempt at a parallel dive
448+
std::vector<double> dive_times(mip_search_concurrency,
449+
-analysis_.mipTimerRead(kMipClockTheDive));
450+
std::vector<HighsSearch::NodeResult> dive_results(
451+
mip_search_concurrency, HighsSearch::NodeResult::kBranched);
452+
for (int i = 0; i < mip_search_concurrency; i++) {
453+
printf("%d is the value used!!\n", i);
454+
tg.spawn([&, i]() {
455+
printf("%d is the value used in start of the spawn!!\n", i);
456+
if (!mipdata_->workers[i].search_ptr_->hasNode() ||
457+
mipdata_->workers[i].search_ptr_->currentNodePruned()) {
458+
dive_times[i] = -1;
459+
} else {
460+
dive_results[i] = mipdata_->workers[i].search_ptr_->dive();
461+
dive_times[i] += analysis_.mipTimerRead(kMipClockNodeSearch);
462+
}
463+
printf("%d = !hasNode\n", !mipdata_->workers[i].search_ptr_->hasNode());
464+
printf("%d is the value used in the spawn!!\n", i);
465+
});
466+
}
467+
// auto task = [&](const int idx) {
468+
// if (!mipdata_->workers[idx].search_ptr_->hasNode() ||
469+
// mipdata_->workers[idx].search_ptr_->currentNodePruned()) {
470+
// dive_times[idx] = -1;
471+
// } else {
472+
// dive_results[idx] = mipdata_->workers[idx].search_ptr_->dive();
473+
// dive_times[idx] += analysis_.mipTimerRead(kMipClockNodeSearch);
474+
// }
475+
// };
476+
// for (int i = 0; i < mip_search_concurrency; i++) {
477+
// tg.spawn([&]() {
478+
// task(i);
479+
// });
480+
// }
481+
// tg.spawn([&]() {
482+
// if (!mipdata_->workers[0].search_ptr_->hasNode() ||
483+
// mipdata_->workers[0].search_ptr_->currentNodePruned()) {
484+
// dive_times[0] = -1;
485+
// } else {
486+
// dive_results[0] = mipdata_->workers[0].search_ptr_->dive();
487+
// dive_times[0] += analysis_.mipTimerRead(kMipClockNodeSearch);
488+
// }
489+
// });
490+
tg.sync();
491+
bool suboptimal = false;
492+
for (int i = 0; i < 1; i++) {
493+
if (dive_times[i] != -1) {
494+
analysis_.dive_time.push_back(dive_times[i]);
495+
if (dive_results[i] == HighsSearch::NodeResult::kSubOptimal) {
496+
suboptimal = true;
497+
} else {
498+
++mipdata_->num_leaves;
499+
mipdata_->workers[i].search_ptr_->flushStatistics();
500+
}
441501
}
442-
if (search_dive_result == HighsSearch::NodeResult::kSubOptimal) break;
443-
444-
++mipdata_->num_leaves;
445-
446-
search.flushStatistics();
447502
}
503+
if (suboptimal) break;
504+
505+
// if (!search.currentNodePruned()) {
506+
// double this_dive_time = -analysis_.mipTimerRead(kMipClockTheDive);
507+
// analysis_.mipTimerStart(kMipClockTheDive);
508+
// const HighsSearch::NodeResult search_dive_result = search.dive();
509+
// analysis_.mipTimerStop(kMipClockTheDive);
510+
// if (analysis_.analyse_mip_time) {
511+
// this_dive_time += analysis_.mipTimerRead(kMipClockNodeSearch);
512+
// analysis_.dive_time.push_back(this_dive_time);
513+
// }
514+
// if (search_dive_result == HighsSearch::NodeResult::kSubOptimal)
515+
// break;
516+
//
517+
// ++mipdata_->num_leaves;
518+
//
519+
// search.flushStatistics();
520+
// }
448521

449522
if (mipdata_->checkLimits()) {
450523
limit_reached = true;

highs/mip/HighsMipWorker.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,18 @@ HighsMipWorker::HighsMipWorker(const HighsMipSolver& mipsolver__,
6969

7070
const HighsMipSolver& HighsMipWorker::getMipSolver() { return mipsolver_; }
7171

72+
void HighsMipWorker::resetSearchDomain() {
73+
search_ptr_.reset();
74+
search_ptr_ =
75+
std::unique_ptr<HighsSearch>(new HighsSearch(*this, pseudocost_));
76+
// search_ptr_->getLocalDomain().addCutpool(mipsolver_.mipdata_->cutpool);
77+
// search_ptr_->getLocalDomain().addConflictPool(
78+
// mipsolver_.mipdata_->conflictPool);
79+
search_ptr_->getLocalDomain().addCutpool(cutpool_);
80+
search_ptr_->getLocalDomain().addConflictPool(conflictpool_);
81+
search_ptr_->setLpRelaxation(&lprelaxation_);
82+
}
83+
7284
bool HighsMipWorker::addIncumbent(const std::vector<double>& sol, double solobj,
7385
const int solution_source,
7486
const bool print_display_line) {

highs/mip/HighsMipWorker.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ class HighsMipWorker {
6363

6464
const bool checkLimits(int64_t nodeOffset = 0) const;
6565

66+
void resetSearchDomain();
67+
6668
bool addIncumbent(const std::vector<double>& sol, double solobj,
6769
const int solution_source,
6870
const bool print_display_line = true);

0 commit comments

Comments
 (0)