@@ -530,18 +530,13 @@ HighsInt HighsSearch::selectBranchingCandidate(int64_t maxSbIters,
530530 }
531531 };
532532
533- if (!downscorereliable[candidate] &&
534- (upscorereliable[candidate] ||
535- std::make_pair (downscore[candidate],
536- pseudocost.getAvgInferencesDown (col)) >=
537- std::make_pair (upscore[candidate],
538- pseudocost.getAvgInferencesUp (col)))) {
539- // evaluate down branch
540- // if (!mipsolver.submip)
541- // printf("down eval col=%d fracval=%g\n", col, fracval);
533+ auto strongBranch = [&](bool upbranch) {
542534 int64_t inferences = -(int64_t )localdom.getDomainChangeStack ().size () - 1 ;
535+ HighsBoundType boundtype = upbranch ? HighsBoundType::kLower
536+ : HighsBoundType::kUpper ;
537+ double boundval = upbranch ? upval : downval;
538+ HighsDomainChange domchg{boundval, col, boundtype};
543539
544- HighsDomainChange domchg{downval, col, HighsBoundType::kUpper };
545540 bool orbitalFixing =
546541 nodestack.back ().stabilizerOrbits && orbitsValidInChildNode (domchg);
547542 localdom.changeBound (domchg);
@@ -557,19 +552,24 @@ HighsInt HighsSearch::selectBranchingCandidate(int64_t maxSbIters,
557552 inferences += localdom.getDomainChangeStack ().size ();
558553 if (localdom.infeasible ()) {
559554 localdom.conflictAnalysis (mipsolver.mipdata_ ->conflictPool );
560- pseudocost.addCutoffObservation (col, false );
555+ pseudocost.addCutoffObservation (col, upbranch );
561556 localdom.backtrack ();
562557 localdom.clearChangedCols ();
563558
564- branchUpwards (col, upval, fracval);
559+ if (upbranch) {
560+ branchDownwards (col, downval, fracval);
561+ }
562+ else {
563+ branchUpwards (col, upval, fracval);
564+ }
565565 nodestack[nodestack.size () - 2 ].opensubtrees = 0 ;
566566 nodestack[nodestack.size () - 2 ].skipDepthCount = 1 ;
567567 depthoffset -= 1 ;
568568
569- return - 1 ;
569+ return true ;
570570 }
571571
572- pseudocost.addInferenceObservation (col, inferences, false );
572+ pseudocost.addInferenceObservation (col, inferences, upbranch );
573573
574574 int64_t numiters = lp->getNumLpIterations ();
575575 HighsLpRelaxation::Status status = playground.solveLp (localdom);
@@ -580,18 +580,24 @@ HighsInt HighsSearch::selectBranchingCandidate(int64_t maxSbIters,
580580 if (lp->scaledOptimal (status)) {
581581 lp->performAging ();
582582
583- double delta = downval - fracval;
583+ double delta = upbranch ? upval - fracval : downval - fracval;
584584 bool integerfeasible;
585585 const std::vector<double >& sol = lp->getSolution ().col_value ;
586586 double solobj = checkSol (sol, integerfeasible);
587587
588588 double objdelta = std::max (solobj - lp->getObjective (), 0.0 );
589589 if (objdelta <= mipsolver.mipdata_ ->epsilon ) objdelta = 0.0 ;
590590
591- downscore[candidate] = objdelta;
592- downscorereliable[candidate] = true ;
593-
594- markBranchingVarDownReliableAtNode (col);
591+ if (upbranch) {
592+ upscore[candidate] = objdelta;
593+ upscorereliable[candidate] = true ;
594+ markBranchingVarUpReliableAtNode (col);
595+ }
596+ else {
597+ downscore[candidate] = objdelta;
598+ downscorereliable[candidate] = true ;
599+ markBranchingVarDownReliableAtNode (col);
600+ }
595601 pseudocost.addObservation (col, delta, objdelta);
596602 analyzeSolution (objdelta, sol);
597603
@@ -607,7 +613,12 @@ HighsInt HighsSearch::selectBranchingCandidate(int64_t maxSbIters,
607613 }
608614
609615 if (lp->unscaledDualFeasible (status)) {
610- downbound[candidate] = solobj;
616+ if (upbranch) {
617+ upbound[candidate] = solobj;
618+ }
619+ else {
620+ downbound[candidate] = solobj;
621+ }
611622 if (solobj > mipsolver.mipdata_ ->optimality_limit ) {
612623 addBoundExceedingConflict ();
613624
@@ -617,13 +628,18 @@ HighsInt HighsSearch::selectBranchingCandidate(int64_t maxSbIters,
617628 localdom.backtrack ();
618629 lp->flushDomain (localdom);
619630
620- branchUpwards (col, upval, fracval);
631+ if (upbranch) {
632+ branchDownwards (col, downval, fracval);
633+ }
634+ else {
635+ branchUpwards (col, upval, fracval);
636+ }
621637 nodestack[nodestack.size () - 2 ].opensubtrees = pruned ? 0 : 1 ;
622638 nodestack[nodestack.size () - 2 ].other_child_lb = solobj;
623639 nodestack[nodestack.size () - 2 ].skipDepthCount = 1 ;
624640 depthoffset -= 1 ;
625641
626- return - 1 ;
642+ return true ;
627643 }
628644 } else if (solobj > getCutoffBound ()) {
629645 addBoundExceedingConflict ();
@@ -633,27 +649,37 @@ HighsInt HighsSearch::selectBranchingCandidate(int64_t maxSbIters,
633649 localdom.backtrack ();
634650 lp->flushDomain (localdom);
635651
636- branchUpwards (col, upval, fracval);
652+ if (upbranch) {
653+ branchDownwards (col, downval, fracval);
654+ }
655+ else {
656+ branchUpwards (col, upval, fracval);
657+ }
637658 nodestack[nodestack.size () - 2 ].opensubtrees = 0 ;
638659 nodestack[nodestack.size () - 2 ].skipDepthCount = 1 ;
639660 depthoffset -= 1 ;
640661
641- return - 1 ;
662+ return true ;
642663 }
643664 }
644665 } else if (status == HighsLpRelaxation::Status::kInfeasible ) {
645666 mipsolver.mipdata_ ->debugSolution .nodePruned (localdom);
646667 addInfeasibleConflict ();
647- pseudocost.addCutoffObservation (col, false );
668+ pseudocost.addCutoffObservation (col, upbranch );
648669 localdom.backtrack ();
649670 lp->flushDomain (localdom);
650671
651- branchUpwards (col, upval, fracval);
672+ if (upbranch) {
673+ branchDownwards (col, downval, fracval);
674+ }
675+ else {
676+ branchUpwards (col, upval, fracval);
677+ }
652678 nodestack[nodestack.size () - 2 ].opensubtrees = 0 ;
653679 nodestack[nodestack.size () - 2 ].skipDepthCount = 1 ;
654680 depthoffset -= 1 ;
655681
656- return - 1 ;
682+ return true ;
657683 } else {
658684 // printf("todo2\n");
659685 // in case of an LP error we set the score of this variable to zero to
@@ -668,140 +694,24 @@ HighsInt HighsSearch::selectBranchingCandidate(int64_t maxSbIters,
668694
669695 localdom.backtrack ();
670696 lp->flushDomain (localdom);
697+ return false ;
698+ };
699+
700+ if (!downscorereliable[candidate] &&
701+ (upscorereliable[candidate] ||
702+ std::make_pair (downscore[candidate],
703+ pseudocost.getAvgInferencesDown (col)) >=
704+ std::make_pair (upscore[candidate],
705+ pseudocost.getAvgInferencesUp (col)))) {
706+ // evaluate down branch
707+ // if (!mipsolver.submip)
708+ // printf("down eval col=%d fracval=%g\n", col, fracval);
709+ if (strongBranch (false )) return -1 ;
671710 } else {
672711 // if (!mipsolver.submip)
673712 // printf("up eval col=%d fracval=%g\n", col, fracval);
674713 // evaluate up branch
675- int64_t inferences = -(int64_t )localdom.getDomainChangeStack ().size () - 1 ;
676- HighsDomainChange domchg{upval, col, HighsBoundType::kLower };
677- bool orbitalFixing =
678- nodestack.back ().stabilizerOrbits && orbitsValidInChildNode (domchg);
679- localdom.changeBound (domchg);
680- localdom.propagate ();
681-
682- if (!localdom.infeasible ()) {
683- if (orbitalFixing)
684- nodestack.back ().stabilizerOrbits ->orbitalFixing (localdom);
685- else
686- mipsolver.mipdata_ ->symmetries .propagateOrbitopes (localdom);
687- }
688-
689- inferences += localdom.getDomainChangeStack ().size ();
690- if (localdom.infeasible ()) {
691- localdom.conflictAnalysis (mipsolver.mipdata_ ->conflictPool );
692- pseudocost.addCutoffObservation (col, true );
693- localdom.backtrack ();
694- localdom.clearChangedCols ();
695-
696- branchDownwards (col, downval, fracval);
697- nodestack[nodestack.size () - 2 ].opensubtrees = 0 ;
698- nodestack[nodestack.size () - 2 ].skipDepthCount = 1 ;
699- depthoffset -= 1 ;
700-
701- return -1 ;
702- }
703-
704- pseudocost.addInferenceObservation (col, inferences, true );
705-
706- int64_t numiters = lp->getNumLpIterations ();
707- HighsLpRelaxation::Status status = playground.solveLp (localdom);
708- numiters = lp->getNumLpIterations () - numiters;
709- lpiterations += numiters;
710- sblpiterations += numiters;
711-
712- if (lp->scaledOptimal (status)) {
713- lp->performAging ();
714-
715- double delta = upval - fracval;
716- bool integerfeasible;
717-
718- const std::vector<double >& sol =
719- lp->getLpSolver ().getSolution ().col_value ;
720- double solobj = checkSol (sol, integerfeasible);
721-
722- double objdelta = std::max (solobj - lp->getObjective (), 0.0 );
723- if (objdelta <= mipsolver.mipdata_ ->epsilon ) objdelta = 0.0 ;
724-
725- upscore[candidate] = objdelta;
726- upscorereliable[candidate] = true ;
727-
728- markBranchingVarUpReliableAtNode (col);
729- pseudocost.addObservation (col, delta, objdelta);
730- analyzeSolution (objdelta, sol);
731-
732- if (lp->unscaledPrimalFeasible (status) && integerfeasible) {
733- double cutoffbnd = getCutoffBound ();
734- mipsolver.mipdata_ ->addIncumbent (
735- lp->getLpSolver ().getSolution ().col_value , solobj,
736- inheuristic ? kSolutionSourceHeuristic
737- : kSolutionSourceBranching );
738-
739- if (mipsolver.mipdata_ ->upper_limit < cutoffbnd)
740- lp->setObjectiveLimit (mipsolver.mipdata_ ->upper_limit );
741- }
742-
743- if (lp->unscaledDualFeasible (status)) {
744- upbound[candidate] = solobj;
745- if (solobj > mipsolver.mipdata_ ->optimality_limit ) {
746- addBoundExceedingConflict ();
747-
748- bool pruned = solobj > getCutoffBound ();
749- if (pruned) mipsolver.mipdata_ ->debugSolution .nodePruned (localdom);
750-
751- localdom.backtrack ();
752- lp->flushDomain (localdom);
753-
754- branchDownwards (col, downval, fracval);
755- nodestack[nodestack.size () - 2 ].opensubtrees = pruned ? 0 : 1 ;
756- nodestack[nodestack.size () - 2 ].other_child_lb = solobj;
757- nodestack[nodestack.size () - 2 ].skipDepthCount = 1 ;
758- depthoffset -= 1 ;
759-
760- return -1 ;
761- }
762- } else if (solobj > getCutoffBound ()) {
763- addBoundExceedingConflict ();
764- localdom.propagate ();
765- bool infeas = localdom.infeasible ();
766- if (infeas) {
767- localdom.backtrack ();
768- lp->flushDomain (localdom);
769-
770- branchDownwards (col, downval, fracval);
771- nodestack[nodestack.size () - 2 ].opensubtrees = 0 ;
772- nodestack[nodestack.size () - 2 ].skipDepthCount = 1 ;
773- depthoffset -= 1 ;
774-
775- return -1 ;
776- }
777- }
778- } else if (status == HighsLpRelaxation::Status::kInfeasible ) {
779- mipsolver.mipdata_ ->debugSolution .nodePruned (localdom);
780- addInfeasibleConflict ();
781- pseudocost.addCutoffObservation (col, true );
782- localdom.backtrack ();
783- lp->flushDomain (localdom);
784-
785- branchDownwards (col, downval, fracval);
786- nodestack[nodestack.size () - 2 ].opensubtrees = 0 ;
787- nodestack[nodestack.size () - 2 ].skipDepthCount = 1 ;
788- depthoffset -= 1 ;
789-
790- return -1 ;
791- } else {
792- // printf("todo2\n");
793- // in case of an LP error we set the score of this variable to zero to
794- // avoid choosing it as branching candidate if possible
795- downscore[candidate] = 0.0 ;
796- upscore[candidate] = 0.0 ;
797- downscorereliable[candidate] = 1 ;
798- upscorereliable[candidate] = 1 ;
799- markBranchingVarUpReliableAtNode (col);
800- markBranchingVarDownReliableAtNode (col);
801- }
802-
803- localdom.backtrack ();
804- lp->flushDomain (localdom);
714+ if (strongBranch (true )) return -1 ;
805715 }
806716 }
807717}
0 commit comments