Skip to content

Commit bc26bb7

Browse files
committed
Introduce new serial parameter to runTask
1 parent 5a0e839 commit bc26bb7

2 files changed

Lines changed: 38 additions & 15 deletions

File tree

‎highs/mip/HighsMipSolver.cpp‎

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,11 @@ HighsMipSolver::~HighsMipSolver() = default;
7373

7474
template <class F>
7575
void HighsMipSolver::runTask(F&& f, highs::parallel::TaskGroup& tg,
76-
bool parallel_lock,
76+
bool parallel_lock, bool force_serial,
7777
const std::vector<HighsInt>& indices) {
7878
if (indices.empty()) return;
7979
setParallelLock(parallel_lock);
80-
const bool spawn_tasks = mipdata_->parallelLockActive() &&
81-
indices.size() > 1 &&
80+
const bool spawn_tasks = !force_serial && indices.size() > 1 &&
8281
!options_mip_->mip_search_simulate_concurrency;
8382
for (HighsInt i : indices) {
8483
if (spawn_tasks) {
@@ -396,6 +395,8 @@ void HighsMipSolver::run() {
396395
#endif
397396
worker.getGlobalDomain().setDomainChangeStack(
398397
std::vector<HighsDomainChange>());
398+
// Warning: Resetting local domain cannot be done in parallel (changes
399+
// propagationDomains of main pool)
399400
worker.search_ptr_->resetLocalDomain();
400401
worker.getGlobalDomain().clearChangedCols();
401402
};
@@ -412,7 +413,7 @@ void HighsMipSolver::run() {
412413
// Sync worker domains here. cleanupFixed might have found extra changes
413414
std::vector<HighsInt> indices(num_workers);
414415
std::iota(indices.begin(), indices.end(), 0);
415-
runTask(doResetWorkerDomain, tg, false, indices);
416+
runTask(doResetWorkerDomain, tg, false, true, indices);
416417
}
417418
for (const HighsInt col : mipdata_->domain.getChangedCols())
418419
mipdata_->implications.cleanupVarbounds(col);
@@ -448,7 +449,7 @@ void HighsMipSolver::run() {
448449
auto doResetWorkerPseudoCost = [&](HighsInt i) -> void {
449450
mipdata_->pseudocost.syncPseudoCost(mipdata_->workers[i].getPseudocost());
450451
};
451-
runTask(doResetWorkerPseudoCost, tg, false, indices);
452+
runTask(doResetWorkerPseudoCost, tg, false, false, indices);
452453
};
453454

454455
destroyOldWorkers();
@@ -566,7 +567,7 @@ void HighsMipSolver::run() {
566567
search_results[i] = mipdata_->workers[i].search_ptr_->evaluateNode();
567568
};
568569
analysis_.mipTimerStart(kMipClockEvaluateNode1);
569-
runTask(doEvaluateNode, tg, true, indices);
570+
runTask(doEvaluateNode, tg, true, false, indices);
570571
analysis_.mipTimerStop(kMipClockEvaluateNode1);
571572
for (size_t i = 0; i != indices.size(); i++) {
572573
HighsInt worker_id = indices[i];
@@ -633,7 +634,7 @@ void HighsMipSolver::run() {
633634
mipdata_->upper_bound);
634635
};
635636
analysis_.mipTimerStart(kMipClockNodePrunedLoop);
636-
runTask(doHandlePrunedNodes, tg, true, indices);
637+
runTask(doHandlePrunedNodes, tg, true, false, indices);
637638
// Flush pruned nodes statistics that haven't yet been flushed
638639
for (HighsInt i : indices) {
639640
if (flush[i] == 1) {
@@ -697,7 +698,7 @@ void HighsMipSolver::run() {
697698
mipdata_->workers[i].search_ptr_->getLocalDomain());
698699
};
699700
analysis_.mipTimerStart(kMipClockNodeSearchSeparation);
700-
runTask(doSeparate, tg, true, indices);
701+
runTask(doSeparate, tg, true, false, indices);
701702
analysis_.mipTimerStop(kMipClockNodeSearchSeparation);
702703

703704
auto syncSepaStats = [&](HighsMipWorker& worker) {
@@ -755,7 +756,7 @@ void HighsMipSolver::run() {
755756
}
756757
};
757758

758-
runTask(doStoreBasis, tg, false, indices);
759+
runTask(doStoreBasis, tg, false, false, indices);
759760
return false;
760761
};
761762

@@ -775,7 +776,7 @@ void HighsMipSolver::run() {
775776
};
776777

777778
analysis_.mipTimerStart(kMipClockBacktrackPlunge);
778-
runTask(doBacktrackPlunge, tg, true, indices);
779+
runTask(doBacktrackPlunge, tg, true, false, indices);
779780
analysis_.mipTimerStop(kMipClockBacktrackPlunge);
780781

781782
// Remove search indices that were not backtracked
@@ -819,6 +820,27 @@ void HighsMipSolver::run() {
819820
return;
820821
}
821822

823+
// TODO MT: ERORRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
824+
// When a domain is created (based on another existing domain)
825+
// , e.g., in randomizedRounding (as an object
826+
// that we can propagate and play around with) or in RINS (where one
827+
// is created as part of the HighsSearch object), it is going to notify
828+
// all cutpools / conflictpools that the original was propagating.
829+
// This "notify" is going to append the domain to the vector of
830+
// pools, which is going to be non-deterministic and error-prone.
831+
// We therefore need to either make the vector robust to multiple changes,
832+
// or consider not propagating the main pool if parallel lock is active?
833+
// The first would be complicated, and the second would make
834+
// heuristics take longer (potentially less effective?)
835+
// For the second: iN THE HighsDomain constructor there is the line,
836+
// cutpoolpropagation(other.cutpoolpropagation),
837+
// This will call the line:
838+
// HighsDomain::CutpoolPropagation::CutpoolPropagation()
839+
// which will call this cutpool->addPropagationDomain(this);
840+
// Consider checking at that stage and simply not notifying the cut pool!
841+
// Information would be one way -> cutpool update wouldn't change
842+
// the local domain, but that's not a problem in this case.
843+
822844
// analysis_.mipTimerStart(kMipClockDivePrimalHeuristics);
823845
if (mipdata_->incumbent.empty()) {
824846
// analysis_.mipTimerStart(kMipClockDiveRandomizedRounding);
@@ -844,7 +866,7 @@ void HighsMipSolver::run() {
844866

845867
// analysis_.mipTimerStop(kMipClockDivePrimalHeuristics);
846868
};
847-
runTask(doRunHeuristics, tg, true, indices);
869+
runTask(doRunHeuristics, tg, true, false, indices);
848870
for (const HighsInt i : indices) {
849871
if (suboptimal[i] == 0) {
850872
if (mipdata_->workers[i].search_ptr_->currentNodePruned()) {
@@ -886,7 +908,7 @@ void HighsMipSolver::run() {
886908
return;
887909
dive_results[i] = worker.search_ptr_->dive();
888910
};
889-
runTask(doDiveSearch, tg, true, non_pruned_indices);
911+
runTask(doDiveSearch, tg, true, false, non_pruned_indices);
890912
analysis_.mipTimerStop(kMipClockTheDive);
891913

892914
for (const HighsInt i : non_pruned_indices) {

‎highs/mip/HighsMipSolver.h‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,10 @@ class HighsMipSolver {
108108
~HighsMipSolver();
109109

110110
template <class F>
111-
void runTask(
112-
F&& f, highs::parallel::TaskGroup& tg, bool parallel_lock,
113-
const std::vector<HighsInt>& indices = std::vector<HighsInt>(1, 0));
111+
void runTask(F&& f, highs::parallel::TaskGroup& tg, bool parallel_lock,
112+
bool force_serial,
113+
const std::vector<HighsInt>& indices = std::vector<HighsInt>(1,
114+
0));
114115

115116
void setModel(const HighsLp& model) {
116117
model_ = &model;

0 commit comments

Comments
 (0)