@@ -629,8 +629,8 @@ void HighsMipSolver::run() {
629629 std::vector<bool > prune (search_indices.size (), false );
630630 for (HighsInt i = 0 ; i < search_indices.size (); i++) {
631631 // TODO MT: Remove this redundant if
632- if (search_indices[i] != 0 ||
633- !mipdata_-> workers [search_indices[i]] .search_ptr_ ->currentNodePruned ())
632+ if (search_indices[i] != 0 || !mipdata_-> workers [search_indices[i]]
633+ .search_ptr_ ->currentNodePruned ())
634634 continue ;
635635 infeasible.emplace_back (false );
636636 flush.emplace_back (false );
@@ -658,8 +658,7 @@ void HighsMipSolver::run() {
658658 }
659659
660660 // Remove search indices that need a new node
661- HighsInt num_search_indices =
662- static_cast <HighsInt>(search_indices.size ());
661+ HighsInt num_search_indices = static_cast <HighsInt>(search_indices.size ());
663662 for (HighsInt i = num_search_indices - 1 ; i >= 0 ; i--) {
664663 if (prune[i]) {
665664 num_search_indices--;
@@ -695,6 +694,70 @@ void HighsMipSolver::run() {
695694 return std::make_pair (false , false );
696695 };
697696
697+ auto separateAndStoreBasis =
698+ [&](std::vector<HighsInt>& search_indices) -> bool {
699+ // the node is still not fathomed, so perform separation
700+ analysis_.mipTimerStart (kMipClockNodeSearchSeparation );
701+ for (HighsInt i : search_indices) {
702+ // TODO MT: Get rid of this line
703+ if (i != 0 ) continue ;
704+ if (mipdata_->parallelLockActive ()) {
705+ tg.spawn ([&, i]() {
706+ mipdata_->workers [i].sepa_ptr_ ->separate (mipdata_->workers [i], mipdata_->workers [i].search_ptr_ ->getLocalDomain ());
707+ });
708+ } else {
709+ mipdata_->workers [i].sepa_ptr_ ->separate (
710+ mipdata_->workers [i],
711+ mipdata_->workers [i].search_ptr_ ->getLocalDomain ());
712+ }
713+ }
714+ analysis_.mipTimerStop (kMipClockNodeSearchSeparation );
715+ if (mipdata_->parallelLockActive ()) tg.taskWait ();
716+
717+ for (HighsInt i : search_indices) {
718+ // TODO MT: Get rid of this line
719+ if (i != 0 ) continue ;
720+ if (mipdata_->workers [i].globaldom_ .infeasible ()) {
721+ mipdata_->workers [i].search_ptr_ ->cutoffNode ();
722+ analysis_.mipTimerStart (kMipClockOpenNodesToQueue1 );
723+ mipdata_->workers [i].search_ptr_ ->openNodesToQueue (mipdata_->nodequeue );
724+ analysis_.mipTimerStop (kMipClockOpenNodesToQueue1 );
725+ mipdata_->nodequeue .clear ();
726+ mipdata_->pruned_treeweight = 1.0 ;
727+
728+ analysis_.mipTimerStart (kMipClockStoreBasis );
729+ double prev_lower_bound = mipdata_->lower_bound ;
730+
731+ mipdata_->lower_bound = std::min (kHighsInf , mipdata_->upper_bound );
732+
733+ bool bound_change = mipdata_->lower_bound != prev_lower_bound;
734+ if (!submip && bound_change)
735+ mipdata_->updatePrimalDualIntegral (
736+ prev_lower_bound, mipdata_->lower_bound , mipdata_->upper_bound ,
737+ mipdata_->upper_bound );
738+ return true ;
739+ }
740+ // after separation we store the new basis and proceed with the outer loop
741+ // to perform a dive from this node
742+ if (mipdata_->workers [i].lprelaxation_ ->getStatus () !=
743+ HighsLpRelaxation::Status::kError &&
744+ mipdata_->workers [i].lprelaxation_ ->getStatus () !=
745+ HighsLpRelaxation::Status::kNotSet )
746+ mipdata_->workers [i].lprelaxation_ ->storeBasis ();
747+
748+ basis = mipdata_->workers [i].lprelaxation_ ->getStoredBasis ();
749+ if (!basis || !isBasisConsistent (
750+ mipdata_->workers [i].lprelaxation_ ->getLp (), *basis)) {
751+ HighsBasis b = mipdata_->firstrootbasis ;
752+ b.row_status .resize (mipdata_->workers [i].lprelaxation_ ->numRows (),
753+ HighsBasisStatus::kBasic );
754+ basis = std::make_shared<const HighsBasis>(std::move (b));
755+ mipdata_->workers [i].lprelaxation_ ->setStoredBasis (basis);
756+ }
757+ }
758+ return false ;
759+ };
760+
698761 auto diveAllSearches = [&]() -> bool {
699762 std::vector<double > dive_times (mip_search_concurrency,
700763 -analysis_.mipTimerRead (kMipClockTheDive ));
@@ -1040,6 +1103,7 @@ void HighsMipSolver::run() {
10401103 // printf("popping node from nodequeue (length = %" HIGHSINT_FORMAT ")\n",
10411104 // (HighsInt)nodequeue.size());
10421105 std::vector<HighsInt> search_indices = getSearchIndicesWithNoNodes ();
1106+ if (search_indices[0 ] != 0 ) break ;
10431107 // if (search_indices.size() >= mip_search_concurrency) break;
10441108
10451109 installNodes (search_indices, limit_reached);
@@ -1058,47 +1122,8 @@ void HighsMipSolver::run() {
10581122 // TODO MT: Change this line
10591123 if (search_indices.empty () || search_indices[0 ] != 0 ) continue ;
10601124
1061- // the node is still not fathomed, so perform separation
1062- analysis_.mipTimerStart (kMipClockNodeSearchSeparation );
1063- sepa.separate (master_worker, search.getLocalDomain ());
1064- analysis_.mipTimerStop (kMipClockNodeSearchSeparation );
1065-
1066- if (mipdata_->domain .infeasible ()) {
1067- search.cutoffNode ();
1068- analysis_.mipTimerStart (kMipClockOpenNodesToQueue1 );
1069- search.openNodesToQueue (mipdata_->nodequeue );
1070- analysis_.mipTimerStop (kMipClockOpenNodesToQueue1 );
1071- mipdata_->nodequeue .clear ();
1072- mipdata_->pruned_treeweight = 1.0 ;
1073-
1074- analysis_.mipTimerStart (kMipClockStoreBasis );
1075- double prev_lower_bound = mipdata_->lower_bound ;
1076-
1077- mipdata_->lower_bound = std::min (kHighsInf , mipdata_->upper_bound );
1078-
1079- bool bound_change = mipdata_->lower_bound != prev_lower_bound;
1080- if (!submip && bound_change)
1081- mipdata_->updatePrimalDualIntegral (
1082- prev_lower_bound, mipdata_->lower_bound , mipdata_->upper_bound ,
1083- mipdata_->upper_bound );
1084- break ;
1085- }
1086-
1087- // after separation we store the new basis and proceed with the outer loop
1088- // to perform a dive from this node
1089- if (mipdata_->lp .getStatus () != HighsLpRelaxation::Status::kError &&
1090- mipdata_->lp .getStatus () != HighsLpRelaxation::Status::kNotSet )
1091- mipdata_->lp .storeBasis ();
1092-
1093- basis = mipdata_->lp .getStoredBasis ();
1094- if (!basis || !isBasisConsistent (mipdata_->lp .getLp (), *basis)) {
1095- HighsBasis b = mipdata_->firstrootbasis ;
1096- b.row_status .resize (mipdata_->lp .numRows (), HighsBasisStatus::kBasic );
1097- basis = std::make_shared<const HighsBasis>(std::move (b));
1098- mipdata_->lp .setStoredBasis (basis);
1099- }
1100-
1101- break ;
1125+ bool infeasible = separateAndStoreBasis (search_indices);
1126+ if (infeasible) break ;
11021127 } // while(!mipdata_->nodequeue.empty())
11031128 analysis_.mipTimerStop (kMipClockNodeSearch );
11041129 if (analysis_.analyse_mip_time ) {
0 commit comments