Skip to content

Commit 257bacd

Browse files
committed
Disable parallelism for submips. Add missing search domain sync
1 parent 701a8e7 commit 257bacd

File tree

1 file changed

+37
-48
lines changed

1 file changed

+37
-48
lines changed

highs/mip/HighsMipSolver.cpp

Lines changed: 37 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -278,33 +278,20 @@ void HighsMipSolver::run() {
278278
// int(mipdata_->lps.at(0).getLpSolver().getNumRow()));
279279

280280
std::shared_ptr<const HighsBasis> basis;
281-
282281
double prev_lower_bound = mipdata_->lower_bound;
283-
284282
mipdata_->lower_bound = mipdata_->nodequeue.getBestLowerBound();
285-
286283
bool bound_change = mipdata_->lower_bound != prev_lower_bound;
287284
if (!submip && bound_change)
288285
mipdata_->updatePrimalDualIntegral(prev_lower_bound, mipdata_->lower_bound,
289286
mipdata_->upper_bound,
290287
mipdata_->upper_bound);
291-
292288
mipdata_->printDisplayLine();
293-
int64_t num_nodes = mipdata_->nodequeue.numNodes();
294-
if (num_nodes > 1) {
295-
// Should be exactly one node on the queue?
296-
if (debug_logging)
297-
printf(
298-
"HighsMipSolver::run() popping node from nodequeue with %d > 1 "
299-
"nodes\n",
300-
HighsInt(num_nodes));
301-
assert(num_nodes == 1);
302-
}
303289

304290
// Initialize worker relaxations and mipworkers
305291
const HighsInt mip_search_concurrency = options_mip_->mip_search_concurrency;
306292
const HighsInt num_workers =
307-
highs::parallel::num_threads() == 1 || mip_search_concurrency <= 1
293+
highs::parallel::num_threads() == 1 || mip_search_concurrency <= 1 ||
294+
submip
308295
? 1
309296
: mip_search_concurrency * highs::parallel::num_threads();
310297
highs::parallel::TaskGroup tg;
@@ -487,8 +474,14 @@ void HighsMipSolver::run() {
487474

488475
// TODO: Should we be propagating this first?
489476
destroyOldWorkers();
490-
if (num_workers > 1) resetGlobalDomain(true);
491-
if (num_workers > 1) constructAdditionalWorkerData(master_worker);
477+
// TODO: Is this reset actually needed? Is copying over all
478+
// the current domain changes actually going to cause an error?
479+
if (num_workers > 1) {
480+
resetGlobalDomain(true);
481+
constructAdditionalWorkerData(master_worker);
482+
} else {
483+
master_worker.search_ptr_->resetLocalDomain();
484+
}
492485
master_worker.upper_bound = mipdata_->upper_bound;
493486
master_worker.upper_limit = mipdata_->upper_limit;
494487
master_worker.optimality_limit = mipdata_->optimality_limit;
@@ -607,8 +600,7 @@ void HighsMipSolver::run() {
607600
}
608601
};
609602

610-
auto handlePrunedNodes =
611-
[&](std::vector<HighsInt>& search_indices) -> std::pair<bool, bool> {
603+
auto handlePrunedNodes = [&](std::vector<HighsInt>& search_indices) -> bool {
612604
// If flush then change statistics for all searches where this was the case
613605
// If infeasible then global domain is infeasible and stop the solve
614606
// If limit_reached then return something appropriate
@@ -673,10 +665,6 @@ void HighsMipSolver::run() {
673665
prev_lower_bound, mipdata_->lower_bound, mipdata_->upper_bound,
674666
mipdata_->upper_bound);
675667

676-
if (!multiple_workers) {
677-
assert(i == 0);
678-
resetGlobalDomain();
679-
}
680668
prune[i] = true;
681669
};
682670
analysis_.mipTimerStart(kMipClockNodePrunedLoop);
@@ -714,7 +702,7 @@ void HighsMipSolver::run() {
714702
prev_lower_bound, mipdata_->lower_bound, mipdata_->upper_bound,
715703
mipdata_->upper_bound);
716704
analysis_.mipTimerStop(kMipClockNodePrunedLoop);
717-
return std::make_pair(false, true);
705+
return true;
718706
}
719707
}
720708

@@ -731,12 +719,11 @@ void HighsMipSolver::run() {
731719
mipdata_->upper_bound);
732720
}
733721

722+
analysis_.mipTimerStop(kMipClockNodePrunedLoop);
734723
if (mipdata_->checkLimits()) {
735-
analysis_.mipTimerStop(kMipClockNodePrunedLoop);
736-
return std::make_pair(true, false);
724+
return true;
737725
}
738-
analysis_.mipTimerStop(kMipClockNodePrunedLoop);
739-
return std::make_pair(false, false);
726+
return false;
740727
};
741728

742729
auto separateAndStoreBasis =
@@ -901,8 +888,9 @@ void HighsMipSolver::run() {
901888
solution_objective_, kExternalMipSolutionQueryOriginBeforeDive);
902889

903890
analysis_.mipTimerStart(kMipClockPerformAging1);
904-
for (HighsConflictPool& conflictpool : mipdata_->conflictpools) {
905-
conflictpool.performAging();
891+
// TODO: Is there a need to age local pools? They're essentially deleted.
892+
for (HighsConflictPool& conflict_pool : mipdata_->conflictpools) {
893+
conflict_pool.performAging();
906894
}
907895
analysis_.mipTimerStop(kMipClockPerformAging1);
908896
// set iteration limit for each lp solve during the dive to 10 times the
@@ -956,22 +944,22 @@ void HighsMipSolver::run() {
956944
search.backtrackPlunge(mipdata_->nodequeue);
957945
analysis_.mipTimerStop(kMipClockBacktrackPlunge);
958946
if (!backtrack_plunge) break;
959-
}
947+
assert(search.hasNode());
960948

961-
if (!mipdata_->hasMultipleWorkers()) assert(search.hasNode());
949+
analysis_.mipTimerStart(kMipClockPerformAging2);
950+
for (HighsConflictPool& conflictpool : mipdata_->conflictpools) {
951+
if (conflictpool.getNumConflicts() >
952+
options_mip_->mip_pool_soft_limit) {
953+
conflictpool.performAging();
954+
}
955+
}
956+
analysis_.mipTimerStop(kMipClockPerformAging2);
962957

963-
analysis_.mipTimerStart(kMipClockPerformAging2);
964-
for (HighsConflictPool& conflictpool : mipdata_->conflictpools) {
965-
if (conflictpool.getNumConflicts() >
966-
options_mip_->mip_pool_soft_limit) {
967-
conflictpool.performAging();
958+
for (HighsMipWorker& worker : mipdata_->workers) {
959+
worker.search_ptr_->flushStatistics();
968960
}
969961
}
970-
analysis_.mipTimerStop(kMipClockPerformAging2);
971962

972-
for (HighsMipWorker& worker : mipdata_->workers) {
973-
worker.search_ptr_->flushStatistics();
974-
}
975963
mipdata_->printDisplayLine();
976964
if (mipdata_->hasMultipleWorkers()) break;
977965
// printf("continue plunging due to good estimate\n");
@@ -990,6 +978,7 @@ void HighsMipSolver::run() {
990978
worker.search_ptr_->flushStatistics();
991979
}
992980

981+
// TODO: Is this sync needed?
993982
syncSolutions();
994983

995984
if (limit_reached) {
@@ -1013,8 +1002,8 @@ void HighsMipSolver::run() {
10131002
// propagate the global domain
10141003
analysis_.mipTimerStart(kMipClockDomainPropgate);
10151004
// sync global domain changes from parallel dives
1016-
syncGlobalDomain();
10171005
syncPools();
1006+
syncGlobalDomain();
10181007
mipdata_->domain.propagate();
10191008
analysis_.mipTimerStop(kMipClockDomainPropgate);
10201009

@@ -1057,7 +1046,8 @@ void HighsMipSolver::run() {
10571046
if (mipdata_->hasMultipleWorkers()) resetWorkerDomains();
10581047
// flush all changes made to the global domain
10591048
resetGlobalDomain();
1060-
if (!mipdata_->hasMultipleWorkers()) search.resetLocalDomain();
1049+
// TODO: Does this line need to be here? Isn't it already reset above?
1050+
// if (!mipdata_->hasMultipleWorkers()) search.resetLocalDomain();
10611051

10621052
if (!submip && mipdata_->num_nodes >= nextCheck) {
10631053
auto nTreeRestarts = mipdata_->numRestarts - mipdata_->numRestartsRoot;
@@ -1157,11 +1147,10 @@ void HighsMipSolver::run() {
11571147
// new global information before we perform separation rounds for the node
11581148
evaluateNodes(search_indices);
11591149

1160-
// if the node was pruned we remove it from the search and install the
1161-
// next node from the queue
1162-
std::pair<bool, bool> limit_or_infeas = handlePrunedNodes(search_indices);
1163-
if (limit_or_infeas.first) limit_reached = true;
1164-
if (limit_or_infeas.first || limit_or_infeas.second) break;
1150+
// if the node was pruned we remove it from the search
1151+
// TODO MT: I'm overloading limit_reached with an infeasible status here.
1152+
limit_reached = handlePrunedNodes(search_indices);
1153+
if (limit_reached) break;
11651154
// TODO MT: If everything was pruned then do a global sync!
11661155
if (search_indices.empty()) {
11671156
if (mipdata_->hasMultipleWorkers()) {

0 commit comments

Comments
 (0)