@@ -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) -> bool {
542534 int64_t inferences = -(int64_t )localdom.getDomainChangeStack ().size () - 1 ;
535+ HighsBoundType boundtype =
536+ upbranch ? HighsBoundType::kLower : 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,23 @@ 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+ } else {
562+ branchUpwards (col, upval, fracval);
563+ }
565564 nodestack[nodestack.size () - 2 ].opensubtrees = 0 ;
566565 nodestack[nodestack.size () - 2 ].skipDepthCount = 1 ;
567566 depthoffset -= 1 ;
568567
569- return - 1 ;
568+ return true ;
570569 }
571570
572- pseudocost.addInferenceObservation (col, inferences, false );
571+ pseudocost.addInferenceObservation (col, inferences, upbranch );
573572
574573 int64_t numiters = lp->getNumLpIterations ();
575574 HighsLpRelaxation::Status status = playground.solveLp (localdom);
@@ -580,18 +579,23 @@ HighsInt HighsSearch::selectBranchingCandidate(int64_t maxSbIters,
580579 if (lp->scaledOptimal (status)) {
581580 lp->performAging ();
582581
583- double delta = downval - fracval;
582+ double delta = upbranch ? upval - fracval : downval - fracval;
584583 bool integerfeasible;
585584 const std::vector<double >& sol = lp->getSolution ().col_value ;
586585 double solobj = checkSol (sol, integerfeasible);
587586
588587 double objdelta = std::max (solobj - lp->getObjective (), 0.0 );
589588 if (objdelta <= mipsolver.mipdata_ ->epsilon ) objdelta = 0.0 ;
590589
591- downscore[candidate] = objdelta;
592- downscorereliable[candidate] = true ;
593-
594- markBranchingVarDownReliableAtNode (col);
590+ if (upbranch) {
591+ upscore[candidate] = objdelta;
592+ upscorereliable[candidate] = true ;
593+ markBranchingVarUpReliableAtNode (col);
594+ } else {
595+ downscore[candidate] = objdelta;
596+ downscorereliable[candidate] = true ;
597+ markBranchingVarDownReliableAtNode (col);
598+ }
595599 pseudocost.addObservation (col, delta, objdelta);
596600 analyzeSolution (objdelta, sol);
597601
@@ -607,7 +611,11 @@ HighsInt HighsSearch::selectBranchingCandidate(int64_t maxSbIters,
607611 }
608612
609613 if (lp->unscaledDualFeasible (status)) {
610- downbound[candidate] = solobj;
614+ if (upbranch) {
615+ upbound[candidate] = solobj;
616+ } else {
617+ downbound[candidate] = solobj;
618+ }
611619 if (solobj > mipsolver.mipdata_ ->optimality_limit ) {
612620 addBoundExceedingConflict ();
613621
@@ -617,13 +625,17 @@ HighsInt HighsSearch::selectBranchingCandidate(int64_t maxSbIters,
617625 localdom.backtrack ();
618626 lp->flushDomain (localdom);
619627
620- branchUpwards (col, upval, fracval);
628+ if (upbranch) {
629+ branchDownwards (col, downval, fracval);
630+ } else {
631+ branchUpwards (col, upval, fracval);
632+ }
621633 nodestack[nodestack.size () - 2 ].opensubtrees = pruned ? 0 : 1 ;
622634 nodestack[nodestack.size () - 2 ].other_child_lb = solobj;
623635 nodestack[nodestack.size () - 2 ].skipDepthCount = 1 ;
624636 depthoffset -= 1 ;
625637
626- return - 1 ;
638+ return true ;
627639 }
628640 } else if (solobj > getCutoffBound ()) {
629641 addBoundExceedingConflict ();
@@ -633,27 +645,35 @@ HighsInt HighsSearch::selectBranchingCandidate(int64_t maxSbIters,
633645 localdom.backtrack ();
634646 lp->flushDomain (localdom);
635647
636- branchUpwards (col, upval, fracval);
648+ if (upbranch) {
649+ branchDownwards (col, downval, fracval);
650+ } else {
651+ branchUpwards (col, upval, fracval);
652+ }
637653 nodestack[nodestack.size () - 2 ].opensubtrees = 0 ;
638654 nodestack[nodestack.size () - 2 ].skipDepthCount = 1 ;
639655 depthoffset -= 1 ;
640656
641- return - 1 ;
657+ return true ;
642658 }
643659 }
644660 } else if (status == HighsLpRelaxation::Status::kInfeasible ) {
645661 mipsolver.mipdata_ ->debugSolution .nodePruned (localdom);
646662 addInfeasibleConflict ();
647- pseudocost.addCutoffObservation (col, false );
663+ pseudocost.addCutoffObservation (col, upbranch );
648664 localdom.backtrack ();
649665 lp->flushDomain (localdom);
650666
651- branchUpwards (col, upval, fracval);
667+ if (upbranch) {
668+ branchDownwards (col, downval, fracval);
669+ } else {
670+ branchUpwards (col, upval, fracval);
671+ }
652672 nodestack[nodestack.size () - 2 ].opensubtrees = 0 ;
653673 nodestack[nodestack.size () - 2 ].skipDepthCount = 1 ;
654674 depthoffset -= 1 ;
655675
656- return - 1 ;
676+ return true ;
657677 } else {
658678 // printf("todo2\n");
659679 // in case of an LP error we set the score of this variable to zero to
@@ -668,140 +688,24 @@ HighsInt HighsSearch::selectBranchingCandidate(int64_t maxSbIters,
668688
669689 localdom.backtrack ();
670690 lp->flushDomain (localdom);
691+ return false ;
692+ };
693+
694+ if (!downscorereliable[candidate] &&
695+ (upscorereliable[candidate] ||
696+ std::make_pair (downscore[candidate],
697+ pseudocost.getAvgInferencesDown (col)) >=
698+ std::make_pair (upscore[candidate],
699+ pseudocost.getAvgInferencesUp (col)))) {
700+ // evaluate down branch
701+ // if (!mipsolver.submip)
702+ // printf("down eval col=%d fracval=%g\n", col, fracval);
703+ if (strongBranch (false )) return -1 ;
671704 } else {
672705 // if (!mipsolver.submip)
673706 // printf("up eval col=%d fracval=%g\n", col, fracval);
674707 // 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);
708+ if (strongBranch (true )) return -1 ;
805709 }
806710 }
807711}
0 commit comments