Skip to content

Commit c4cf00b

Browse files
committed
Add heuristics to dive
1 parent a4ac096 commit c4cf00b

File tree

1 file changed

+84
-42
lines changed

1 file changed

+84
-42
lines changed

highs/mip/HighsMipSolver.cpp

Lines changed: 84 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,16 @@ void HighsMipSolver::run() {
501501
return search_indices;
502502
};
503503

504+
auto getSearchIndicesWithNodes = [&]() -> std::vector<HighsInt> {
505+
std::vector<HighsInt> search_indices;
506+
for (HighsInt i = 0; i < mip_search_concurrency; i++) {
507+
if (mipdata_->workers[i].search_ptr_->hasNode()) {
508+
search_indices.emplace_back(i);
509+
}
510+
}
511+
return search_indices;
512+
};
513+
504514
auto installNodes = [&](std::vector<HighsInt>& search_indices,
505515
bool& limit_reached) -> void {
506516
for (HighsInt index : search_indices) {
@@ -791,9 +801,81 @@ void HighsMipSolver::run() {
791801
return false;
792802
};
793803

804+
auto doRunHeuristics = [&](HighsMipWorker& worker) -> void {
805+
bool clocks = !mipdata_->parallelLockActive();
806+
if (clocks) analysis_.mipTimerStart(kMipClockDiveEvaluateNode);
807+
const HighsSearch::NodeResult evaluate_node_result =
808+
worker.search_ptr_->evaluateNode();
809+
if (clocks) analysis_.mipTimerStop(kMipClockDiveEvaluateNode);
810+
811+
if (evaluate_node_result == HighsSearch::NodeResult::kSubOptimal) return;
812+
813+
if (worker.search_ptr_->currentNodePruned()) {
814+
if (clocks) {
815+
++mipdata_->num_leaves;
816+
search.flushStatistics();
817+
}
818+
} else {
819+
if (clocks) analysis_.mipTimerStart(kMipClockDivePrimalHeuristics);
820+
// TODO MT: Make trivial heuristics work locally
821+
if (mipdata_->incumbent.empty() && clocks) {
822+
analysis_.mipTimerStart(kMipClockDiveRandomizedRounding);
823+
mipdata_->heuristics.randomizedRounding(
824+
worker,
825+
worker.lprelaxation_->getLpSolver().getSolution().col_value);
826+
analysis_.mipTimerStop(kMipClockDiveRandomizedRounding);
827+
}
828+
829+
if (mipdata_->incumbent.empty()) {
830+
if (options_mip_->mip_heuristic_run_rens) {
831+
if (clocks) analysis_.mipTimerStart(kMipClockDiveRens);
832+
mipdata_->heuristics.RENS(
833+
worker,
834+
worker.lprelaxation_->getLpSolver().getSolution().col_value);
835+
if (clocks) analysis_.mipTimerStop(kMipClockDiveRens);
836+
}
837+
} else {
838+
if (options_mip_->mip_heuristic_run_rins) {
839+
if (clocks) analysis_.mipTimerStart(kMipClockDiveRins);
840+
mipdata_->heuristics.RINS(
841+
worker,
842+
worker.lprelaxation_->getLpSolver().getSolution().col_value);
843+
if (clocks) analysis_.mipTimerStop(kMipClockDiveRins);
844+
}
845+
}
846+
847+
if (clocks) mipdata_->heuristics.flushStatistics(master_worker);
848+
if (clocks) analysis_.mipTimerStop(kMipClockDivePrimalHeuristics);
849+
}
850+
};
851+
852+
auto runHeuristics = [&]() -> void {
853+
setParallelLock(true);
854+
std::vector<HighsInt> search_indices = getSearchIndicesWithNodes();
855+
for (HighsInt i : search_indices) {
856+
if (mipdata_->parallelLockActive()) {
857+
tg.spawn([&, i]() { doRunHeuristics(mipdata_->workers[i]); });
858+
} else {
859+
doRunHeuristics(mipdata_->workers[i]);
860+
}
861+
}
862+
if (mipdata_->parallelLockActive()) {
863+
tg.taskWait();
864+
for (const HighsInt i : search_indices) {
865+
if (mipdata_->workers[i].search_ptr_->currentNodePruned()) {
866+
++mipdata_->num_leaves;
867+
search.flushStatistics();
868+
} else {
869+
mipdata_->heuristics.flushStatistics(mipdata_->workers[i]);
870+
}
871+
}
872+
}
873+
};
874+
794875
auto diveAllSearches = [&]() -> bool {
795876
std::vector<double> dive_times(mip_search_concurrency,
796877
-analysis_.mipTimerRead(kMipClockTheDive));
878+
analysis_.mipTimerStart(kMipClockTheDive);
797879
std::vector<HighsSearch::NodeResult> dive_results(
798880
mip_search_concurrency, HighsSearch::NodeResult::kBranched);
799881
setParallelLock(true);
@@ -816,6 +898,7 @@ void HighsMipSolver::run() {
816898
dive_times[0] += analysis_.mipTimerRead(kMipClockNodeSearch);
817899
}
818900
}
901+
analysis_.mipTimerStop(kMipClockTheDive);
819902
setParallelLock(false);
820903
bool suboptimal = false;
821904
for (int i = 0; i < mip_search_concurrency; i++) {
@@ -869,48 +952,7 @@ void HighsMipSolver::run() {
869952
while (true) {
870953
// Possibly apply primal heuristics
871954
if (considerHeuristics && mipdata_->moreHeuristicsAllowed()) {
872-
analysis_.mipTimerStart(kMipClockDiveEvaluateNode);
873-
const HighsSearch::NodeResult evaluate_node_result =
874-
search.evaluateNode();
875-
analysis_.mipTimerStop(kMipClockDiveEvaluateNode);
876-
877-
if (evaluate_node_result == HighsSearch::NodeResult::kSubOptimal) break;
878-
879-
if (search.currentNodePruned()) {
880-
// ig: do we update num_leaves here?
881-
++mipdata_->num_leaves;
882-
search.flushStatistics();
883-
} else {
884-
analysis_.mipTimerStart(kMipClockDivePrimalHeuristics);
885-
if (mipdata_->incumbent.empty()) {
886-
analysis_.mipTimerStart(kMipClockDiveRandomizedRounding);
887-
mipdata_->heuristics.randomizedRounding(
888-
master_worker,
889-
mipdata_->lp.getLpSolver().getSolution().col_value);
890-
analysis_.mipTimerStop(kMipClockDiveRandomizedRounding);
891-
}
892-
893-
if (mipdata_->incumbent.empty()) {
894-
if (options_mip_->mip_heuristic_run_rens) {
895-
analysis_.mipTimerStart(kMipClockDiveRens);
896-
mipdata_->heuristics.RENS(
897-
master_worker,
898-
mipdata_->lp.getLpSolver().getSolution().col_value);
899-
analysis_.mipTimerStop(kMipClockDiveRens);
900-
}
901-
} else {
902-
if (options_mip_->mip_heuristic_run_rins) {
903-
analysis_.mipTimerStart(kMipClockDiveRins);
904-
mipdata_->heuristics.RINS(
905-
master_worker,
906-
mipdata_->lp.getLpSolver().getSolution().col_value);
907-
analysis_.mipTimerStop(kMipClockDiveRins);
908-
}
909-
}
910-
911-
mipdata_->heuristics.flushStatistics(master_worker);
912-
analysis_.mipTimerStop(kMipClockDivePrimalHeuristics);
913-
}
955+
runHeuristics();
914956
}
915957

916958
considerHeuristics = false;

0 commit comments

Comments
 (0)