branch_lookahead.c
Go to the documentation of this file.
23 * The (multi-level) lookahead branching rule applies strong branching to every fractional value of the LP solution
24 * at the current node of the branch-and-bound tree, as well as recursivly to every temporary child problem created by this
34 * For a more mathematical description and a comparison between lookahead branching and other branching rules
48 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
81 #define DEFAULT_USEBINARYCONSTRAINTS FALSE /**< should binary constraints be collected and applied? */
82 #define DEFAULT_ADDCLIQUE FALSE /**< add binary constraints with two variables found at the root node also as a clique? */
85 #define DEFAULT_USEDOMAINREDUCTION TRUE /**< Should domain reductions be collected and applied? */
86 #define DEFAULT_MERGEDOMAINREDUCTIONS FALSE /**< should domain reductions of feasible siblings should be merged? */
87 #define DEFAULT_PREFERSIMPLEBOUNDS FALSE /**< should domain reductions only be applied if there are simple bound changes? */
88 #define DEFAULT_ONLYVIOLDOMREDS FALSE /**< Should only domain reductions that violate the LP solution be applied? */
89 #define DEFAULT_MAXNVIOLATEDCONS 1 /**< How many constraints that are violated by the base lp solution
91 #define DEFAULT_MAXNVIOLATEDBINCONS 0 /**< How many binary constraints that are violated by the base lp
94 #define DEFAULT_MAXNVIOLATEDDOMREDS 1 /**< How many domain reductions that are violated by the base lp solution
96 #define DEFAULT_STOREUNVIOLATEDSOL TRUE /**< If only non violating constraints are added, should the branching
98 #define DEFAULT_REEVALAGE 10LL /**< Max number of LPs solved after which a previous prob branching
100 #define DEFAULT_REEVALAGEFSB 10LL /**< Max number of LPs solved after which a previous FSB scoring
103 #define DEFAULT_ADDNONVIOCONS FALSE /**< Should binary constraints, that are not violated by the base LP, be
105 #define DEFAULT_PROPAGATE TRUE /**< Should domain propagation be executed before each temporary node is
107 #define DEFAULT_USELEVEL2DATA TRUE /**< should branching data generated at depth level 2 be stored for re-using it? */
109 #define DEFAULT_ENFORCEMAXDOMREDS FALSE /**< should the maximum number of domain reductions maxnviolateddomreds be enforced? */
110 #define DEFAULT_UPDATEBRANCHINGRESULTS FALSE /**< should branching results (and scores) be updated w.r.t. proven dual bounds? */
111 #define DEFAULT_MAXPROPROUNDS 0 /**< maximum number of propagation rounds to perform at temporary
114 #define DEFAULT_MAXNCANDS 4 /**< If abbreviated: The max number of candidates to consider at the base node */
115 #define DEFAULT_MAXNDEEPERCANDS 2 /**< If abbreviated: The max number of candidates to consider per deeper node
117 #define DEFAULT_REUSEBASIS TRUE /**< If abbreviated: Should the information gathered to obtain the best
119 #define DEFAULT_ABBREVPSEUDO FALSE /**< If abbreviated: Use pseudo costs to estimate the score of a
121 #define DEFAULT_LEVEL2AVGSCORE FALSE /**< should the average score be used for uninitialized scores in level 2? */
126 #define DEFAULT_MINWEIGHT 0.8 /**< default value for the weight of the minimum in the convex combination of two
128 #define DEFAULT_WORSEFACTOR -1.0 /**< if the FSB score is of a candidate is worse than the best by this factor, skip this candidate (-1: disable) */
129 #define DEFAULT_FILTERBYMAXGAIN FALSE /**< should lookahead branching only be applied if the max gain in level 1 is not uniquely that of the best candidate? */
159 /* Writes a debug message without the leading information. Can be used to append something to an output of LABdebugMessage*/
174 /** A struct holding information to speed up the solving time for solving a problem again. This is filled by the FSB
175 * scoring routine that is run to get the best candidates. It is then read by the actual ALAB routine. */
178 SCIP_LPISTATE* lpistate; /**< the basis information that may be set before another solve lp call */
184 /** Allocates the warm start information on the buffer and initializes it with default values. */
230 {
250 WARMSTARTINFO* downwarmstartinfo; /**< the warm start info containing the lp data from a previous down branch */
251 WARMSTARTINFO* upwarmstartinfo; /**< the warm start info containing the lp data from a previous up branch */
260 {
271 }
283 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "freeing warmstart info of candidate <%s>(%u/%u)...\n",
290 }
300 /** Frees the allocated buffer memory of the candidate and clears the contained lpi memories. */
369 /** returns whether the candidate has stored warm starting information for the given direction */
378 return warmStartInfoIsAvailable(down ? candidate->downwarmstartinfo : candidate->upwarmstartinfo);
402 /* As we solved the very same LP some time earlier and stored the state (the basis) and the norms, we can now set those in
404 * Some iterations may occur, as the conflict analysis may have added some constraints in the meantime. */
405 SCIP_CALL( SCIPsetProbingLPState(scip, &(warmstartinfo->lpistate), &(warmstartinfo->lpinorms), warmstartinfo->primalfeas,
408 /* The state and norms will be freed later by the SCIP framework. Therefore they are set to NULL to enforce that we won't
430 SCIP_Bool downdbvalid; /**< Indicator for the validity of the downdb value. Is FALSE, if no actual
445 )
485 * this is used to store the most important information (i.e., the dual bounds obtained) so that it can be used in a
486 * subsequent call in case the LP solution did not change because we only added bound changes that did not forbid the
488 * however, we do not want to store all the domain changes for the two potential child nodes for this rare case, they
525 /* a branching decision is deemed valid, if the var pointer is not on the default NULL value (see the allocate method) */
546 }
583 SCIP_Real dualbound; /**< The best dual bound for this branching, may be changed by deeper level
587 SCIP_Bool dualboundvalid; /**< Is the value of the dual bound valid? That means, was the according LP
591 SCIP_Real bestgain; /**< best gain (w.r.t. to the base lp) on the lowest level below this child */
602 )
674 SCIP_Real lpobjval; /**< the objective value of the solved lp; only contains meaningful data, if
680 unsigned int branchdir1:1; /**< branching direction for first branching variable (0:down, 1:up) */
681 unsigned int branchdir2:1; /**< branching direction for second branching variable (0:down, 1:up) */
696 unsigned int branchdir1:1; /**< branching direction for first branching variable (0:down, 1:up) */
697 unsigned int branchdir2:1; /**< branching direction for second branching variable (0:down, 1:up) */
700 /** allocates a double branching result in the memory and fills it with the information stored in the level 2 data */
706 )
707 {
774 /** returns TRUE iff both level 2 results are equal; two branchings are equal if they branched on the same variables
817 (*data)->branchvar1 = 0;
864 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &data->level2results, data->level2resultssize, newsize) );
919 SCIP_Bool* duplicate /**< pointer to store whether information for the same branching decisions was already stored */
969 BRANCHINGDECISION* olddecision; /**< The previous decision that gets used for the case that in the previous run
971 SCIP_Longint oldnnodelpiterations; /**< node LP iterations when previous branching decision was stored */
974 SCIP_Longint* lastbranchid; /**< The node id at which the var was last branched on (for a given branching
976 SCIP_Longint* lastbranchnlps; /**< The number of (non-probing) LPs that where solved when the var was last
979 BRANCHINGRESULTDATA** lastbranchupres; /**< The result of the last up branching for a given var. */
980 BRANCHINGRESULTDATA** lastbranchdownres; /**< The result of the last down branching for a given var. */
981 int restartindex; /**< The index at which the iteration over the number of candidates starts. */
985 /** The parameter that can be changed by the user/caller and alter the behaviour of the lookahead branching. */
987 {
988 SCIP_Longint reevalage; /**< The number of "normal" (not probing) lps that may have been solved before
990 SCIP_Longint reevalagefsb; /**< The number of "normal" (not probing) lps that may have been solved before
992 int maxnviolatedcons; /**< The number of constraints (domain reductions and binary constraints) we
995 int maxnviolatedbincons;/**< The number of binary constraints we want to gather before restarting the
997 int maxnviolateddomreds;/**< The number of domain reductions we want to gather before restarting the
1000 int maxncands; /**< If abbreviated == TRUE, at most how many candidates should be handled at the base node? */
1001 int maxndeepercands; /**< If abbreviated == TRUE, at most how many candidates should be handled in deeper nodes? */
1002 SCIP_Bool usedomainreduction; /**< indicates whether the data for domain reductions should be gathered and
1004 SCIP_Bool mergedomainreductions; /**< should domain reductions of feasible siblings should be merged? */
1005 SCIP_Bool prefersimplebounds; /**< should domain reductions only be applied if there are simple bound changes? */
1006 SCIP_Bool onlyvioldomreds; /**< Should only domain reductions that violate the LP solution be applied? */
1007 SCIP_Bool usebincons; /**< indicates whether the data for the implied binary constraints should
1011 SCIP_Bool addnonviocons; /**< Should constraints be added, that are not violated by the base LP? */
1013 SCIP_Bool reusebasis; /**< If abbreviated == TRUE, should the solution lp-basis of the FSB run be
1015 SCIP_Bool storeunviolatedsol; /**< Should a solution/decision be stored, to speed up the next iteration
1017 SCIP_Bool abbrevpseudo; /**< If abbreviated == TRUE, should pseudocost values be used, to approximate
1019 SCIP_Bool level2avgscore; /**< should the average score be used for uninitialized scores in level 2? */
1021 SCIP_Bool addclique; /**< add binary constraints with two variables found at the root node also as a clique? */
1023 SCIP_Bool uselevel2data; /**< should branching data generated at depth level 2 be stored for re-using it? */
1025 SCIP_Bool enforcemaxdomreds; /**< should the maximum number of domain reductions maxnviolateddomreds be enforced? */
1026 SCIP_Bool updatebranchingresults; /**< should branching results (and scores) be updated w.r.t. proven dual bounds? */
1034 SCIP_Real worsefactor; /**< if the FSB score is of a candidate is worse than the best by this factor, skip this candidate (-1: disable) */
1035 SCIP_Bool filterbymaxgain; /**< should lookahead branching only be applied if the max gain in level 1 is not uniquely that of the best candidate? */
1046 )
1047 {
1048 assert(result >= 1);
1049 assert(result <= 18);
1104 int* nsinglecutoffs; /**< The number of single cutoffs on a (probing) node per probingdepth. */
1109 SCIP_Longint* nlpiterations; /**< The number of all lp iterations needed for a given probingdepth
1111 SCIP_Longint* nlpiterationsfsb; /**< The number of lp iterations needed to get the FSB scores. */
1116 int* noldbranchusedfsb; /**< The number of times old FSB scoring data is used (see the reevalagefsb
1118 int* chosenfsbcand; /**< If abbreviated, this is the number of times each candidate was finally
1122 int* cutoffafterfsb; /**< If abbreviated, this is the number of times the rule was stopped after
1124 int* domredafterfsb; /**< If abbreviated, this is the number of times the rule was stopped after
1126 int nsinglecandidate; /**< number of times a single candidate was given to the recursion routine */
1130 int nlperrorcalls; /**< number of times an LP error occured and LAB branched without completely
1136 int nbinconstvio; /**< The number of binary constraints added to the base node, that are violated
1141 int ndepthreached; /**< The number of times the branching was aborted due to a too small depth. */
1146 int maxnbestcands; /**< if abbreviated, this is the maximum number of candidates to investigate */
1147 int recursiondepth; /**< The recursiondepth of the LAB. Can be used to access the depth-dependent
1222 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Lookahead Branching was called <%i> times.\n", statistics->ntotalresults);
1228 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Result <%s> was chosen <%i> times\n", getStatusString(currentresult),
1236 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "The %i. variable (w.r.t. the FSB score) was chosen as the final result %i times.\n",
1243 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "In depth <%i>, branching was stopped after the scoring FSB %i times, %i times because of a cutoff and %i times because of a domain reduction\n",
1245 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "In depth <%i>, <%i> fullcutoffs and <%i> single cutoffs were found.\n",
1247 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "In depth <%i>, <%i> LPs were solved, <%i> of them to calculate the FSB score, <%i> were saved for duplicate grandchildren.\n",
1249 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "In depth <%i>, <%" SCIP_LONGINT_FORMAT "> iterations were needed to solve the LPs, <%"
1250 SCIP_LONGINT_FORMAT "> of them to calculate the FSB score.\n", i, statistics->nlpiterations[i],
1252 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "In depth <%i>, a decision was discarded <%i> times due to domain reduction because of"
1254 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "In depth <%i>, old LAB branching results were used in <%i> cases, old FSB scores in <%d> cases.\n",
1258 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "One single branching candidate was given <%i> times, after filtering, a single candidate remained <%i> times.\n",
1260 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "The old branching candidate was used <%i> times.\n",
1262 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "An LP error led to branching before all candidates were evaluated <%i> times.\n",
1264 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "A reached (time) limit led to branching before all candidates were evaluated <%i> times.\n",
1266 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Depth limit was reached <%i> times.\n", statistics->ndepthreached);
1267 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Ignored <%i> binary constraints, that would be domain reductions.\n",
1269 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Added <%i> binary constraints, of which <%i> where violated by the base LP.\n",
1271 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Reduced the domain of <%i> vars, <%i> of them where violated by the base LP.\n",
1273 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Added <%i> cliques found as binary constraint in the root node\n",
1275 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Needed <%i> additional nodes to prove the cutoffs of base nodes\n",
1277 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Needed <%i> additional nodes to prove the domain reductions\n",
1292 LOCALSTATISTICS** localstats /**< pointer to the local statistics to allocate and initialize */
1322 CONFIGURATION* config; /**< the parameter that influence the behaviour of the lookahead branching */
1348 )
1349 {
1352 assert(startsize > 0);
1384 {
1388 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &list->nconsvars, list->memorysize, newmemsize) );
1394 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &list->consvars[list->nelements], consvars, nconsvars) ); /*lint !e866*/
1429 * these variables are used to build the binary constraint in case that a ('binary') branch is cut off
1446 {
1449 assert(startsize > 0);
1456 (*list)->memorysize = startsize;
1478 }
1526 assert(maxdepth > 0);
1527 assert(nstartcons > 0);
1553 {
1555 int ncandidates; /**< the number of actual entries in candidates (without trailing NULLs); this
1560 /** allocates the candidate list on the buffer WITHOUT initializing the contained array of candidates. */
1567 {
1570 assert(ncandidates >= 0);
1577 }
1586 /** allocates the given list and fills it with all fractional candidates of the current LP solution. */
1603 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) );
1631 /** frees the allocated buffer memory of the candidate list and frees the contained candidates. */
1679 {
1697 SCIP_Shortbool* baselpviolated; /**< Indicates whether the base lp solution violates the new bounds of a var.*/
1698 int nviolatedvars; /**< Tracks the number of vars that have a violated (by the base lp) new lower
1700 int nchangedvars; /**< Tracks the number of vars, that have a changed domain. (a change on both,
1704 int* lowerboundnproofs; /**< The number of nodes needed to prove the lower bound for each variable. */
1705 int* upperboundnproofs; /**< The number of nodes needed to prove the upper bound for each variable. */
1715 {
1723 /* The arrays saves the data for all variables in the problem via the ProbIndex. See SCIPvarGetProbindex() */
1751 /** frees the given DOMAINREDUCTIONS and all contained Arrays in the opposite order of allocation */
1782 SCIP_Bool maxnconsreached; /**< was the max number of constraints (bin conss and dom red) reached? */
1790 )
1791 {
1827 CANDIDATE** bestsortedcands; /**< array containing the best sorted variable indices w.r.t. their score */
1837 )
1842 }
1850 )
1860 /* the container saves the score for all variables in the problem via the ProbIndex, see SCIPvarGetProbindex() */
1889 /** Finds the insertion index for the given score in the candidate list. The score of each candidate is taken from the
1890 * scorecontainer. The first elements of the candidate list have to be sorted, as this method uses binary search to find
1898 CANDIDATE** candidates, /**< candidate list where the first nsorted elements are sorted (w.r.t. their
1909 assert(ncandidates >= 0);
1936 /** Inserts the given probindex into the sorted array in the container, moving all indices after it to the right. Then
2003 /* insert the current variable (cand) at the position calculated above, returning the candidate that
2004 * was removed at the end of the list; this candidate can be the given candidate for the case that the score does not
2014 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Stored score <%.9g> for var <%s>.\n", score, SCIPvarGetName(cand->branchvar));
2029 /* don't free the candidates inside the cands array, as those are handled by the candidate list */
2048 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
2060 SCIP_Longint* niterations, /**< pointer to store the total number of iterations for this variable */
2061 int* ndeepestcutoffs, /**< pointer to store the total number of cutoffs on the deepest level */
2063 SCIP_Real* totalgains, /**< pointer to store the sum over all gains that are valid in both children */
2080 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
2086 ,int force /**< should the number of proof nodes be added even if the bound is known already? */
2119 /* if the given lower bound is equal to the old one we take the smaller number of proof nodes */
2126 /* we get the solution value to check whether the domain reduction is violated in the base LP */
2129 /* in case the new lower bound is greater than the base solution val and the base solution val is not violated by a
2130 * previously found bound, we increment the nviolatedvars counter and set the baselpviolated flag */
2145 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
2151 ,int force /**< should the number of proof nodes be added even if the bound is known already? */
2174 /* if the given upper bound is equal to the old one we take the smaller number of proof nodes */
2193 /* We get the solution value to check whether the domain reduction is violated in the base LP */
2196 /* In case the new upper bound is smaller than the base solution val and the base solution val is not violated by a
2197 * previously found bound, we increment the nviolatedvars counter and set the baselpviolated flag. */
2206 /** apply the domain reductions from a single struct to another one; this may be used in case one of the two child
2212 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
2215 DOMAINREDUCTIONS* targetdomreds, /**< The target that should be filled with the merged data. */
2261 * merges the domain reduction data from the two given branching children data into the target parent data
2266 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
2269 DOMAINREDUCTIONS* targetdomreds, /**< The target that should be filled with the merged data. */
2291 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Combining domain reductions from up and down child.\n");
2292 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Previous number of changed variable domains: %d\n",
2295 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Number of changed variable domains in up child: %d\n",
2297 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Number of changed variable domains in down child: %d\n",
2336 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Subsequent number of changed variable domains: %d\n",
2345 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
2347 DOMAINREDUCTIONS* domreds, /**< The domain reductions that should be applied to the current node. */
2348 SCIP_Bool* domredcutoff, /**< pointer to store whether a cutoff was found due to domain reductions */
2417 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Variable <%s>, old lower bound <%g>, proposed lower bound <%g>, new "
2425 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The domain reduction of variable <%s> resulted in an empty "
2436 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The lower bound of variable <%s> was successfully tightened (%d).\n",
2444 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The lower bound of variable <%s> is violated by the base lp "
2468 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Variable <%s>, old upper bound <%g>, proposed upper bound <%g>, new "
2476 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The domain reduction of variable <%s> resulted in an empty "
2487 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The upper bound of variable <%s> was successfully tightened (%d).\n",
2495 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The upper bound of variable <%s> is violated by the base lp "
2510 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Truly changed <%d> domains of the problem, <%d> of them are violated by the "
2532 }
2555 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Effective branching on var <%s> with value <%g(%g)>. Old domain: [%g..%g].\n",
2556 SCIPvarGetName(bestvar), bestval, SCIPgetSolVal(scip, NULL, bestvar), SCIPvarGetLbLocal(bestvar), SCIPvarGetUbLocal(bestvar));
2573 /* update the lower bounds in the children; we must not do this if columns are missing in the LP
2584 SCIP_CALL( SCIPupdateNodeLowerbound(scip, downchild, bestdownvalid ? MAX(bestdown, provedbound) : provedbound) );
2585 SCIP_CALL( SCIPupdateNodeLowerbound(scip, upchild, bestupvalid ? MAX(bestup, provedbound) : provedbound) );
2624 /* update the upper bound of the lower child in case it is better than the current one AND it is not the
2638 /* update the lower bound of the upper child in case it is better than the current one AND it is not the
2660 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, " -> down child's lowerbound: %.9g, estimate: %.9g\n",
2662 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, " -> up child's lowerbound: %.9g, estimate: %.9g\n",
2692 /** Creates a new probing node with a new bound for the given candidate and solves the corresponding LP. */
2699 BRANCHINGRESULTDATA* resultdata, /**< pointer to the result data which gets filled with the status */
2701 DOMAINREDUCTIONS* domreds, /**< struct to store the domain reduction found during propagation */
2742 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "DownBranching: Var=<%s>, Proposed upper bound=<%g>, "
2743 "old bounds=[<%g>..<%g>], new bounds=[<%g>..<%g>]\n", SCIPvarGetName(branchvar), newbound, oldlowerbound,
2748 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "UpBranching: Var=<%s>, Proposed lower bound=<%g>, "
2749 "old bounds=[<%g>..<%g>], new bounds=[<%g>..<%g>]\n", SCIPvarGetName(branchvar), newbound, oldlowerbound,
2794 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Restoring lp information for %s branch of variable <%s>\n",
2804 SCIP_CALL( SCIPpropagateProbing(scip, config->maxproprounds, &resultdata->cutoff, &ndomredsfound) );
2808 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Found %d domain reductions via propagation.\n", ndomredsfound);
2853 /* for us an error occurred, if an error during the solving occurred or the lp could not be solved but was not
2855 status->lperror = status->lperror || (solstat == SCIP_LPSOLSTAT_NOTSOLVED && resultdata->cutoff == FALSE);
2857 /* if we seem to have reached a {time, iteration}-limit or the user cancelled the execution, we want to stop
2859 status->limitreached = (solstat == SCIP_LPSOLSTAT_ITERLIMIT) || (solstat == SCIP_LPSOLSTAT_TIMELIMIT);
2873 /* if we have no error, we save the new objective value and the cutoff decision in the resultdata */
2877 resultdata->cutoff = resultdata->cutoff || SCIPisGE(scip, resultdata->objval, SCIPgetCutoffbound(scip));
2886 /** Creates a logic or constraint based on the given 'consvars'. This array has to consist of the negated
2887 * versions of the variables present on a cutoff "path" (path means all variables from the root directly
2889 * Let x_1, ..., x_n be the variables on a path to a cutoff with the branchings x_i <= 1 for all i.
2928 SCIP_CALL( SCIPcreateConsLogicor(scip, constraint, constraintname, nconsvars, consvars, initial, separate, enforce,
2950 (void) SCIPsnprintf(constraintname, SCIP_MAXSTRLEN, "lookahead_bin_%s", SCIPvarGetName(binaryvars[0]));
2966 * The implied binary bounds were found when two or more consecutive branchings of binary variables were cutoff. Then these
2974 SCIP_SOL* baselpsol /**< the original lp solution, used to check the violation of the constraint */
2987 /* if we only have one var for the constraint, we can ignore it as it is already added as a domain reduction. */
3017 /* the constraint we will be building is a logic or: we have a list of binary variables that were
3020 * is violating this constraint we count this for our number of violated constraints and bounds. */
3047 SCIP_Bool* boundchange /**< pointer to store whether a bound change has been applied by adding the
3068 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "processing %d binary constraints.\n", conslist->nelements);
3132 /* a two-variable logicor constraint x + y >= 1 yields the implication x == 0 -> y == 1, and is represented
3152 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "added %d/%d binary constraints.\n", nconsadded, conslist->nelements);
3183 /* due to roundings the value might have changed slightly without an actual influence on the integral value */
3187 /** Checks whether the branching rule should continue or terminate with the currently gathered data */
3200 /** Checks whether the branching rule should continue or terminate with the currently gathered data. Additionally decrements
3201 * the given loopcounter. This is needed to better emulate the behavior of FSB by LAB with a depth of 1. */
3234 /* an old branching can be reused, if we are still at the same node and just a few LPs were solved in between */
3243 && SCIPgetNLPs(scip) - persistent->lastbranchnlps[SCIPvarGetProbindex(branchvar)] < config->reevalage;
3268 SCIP_CALL( SCIPgetVarStrongbranchLast(scip, branchvar, &downbranchingresult->dualbound, &upbranchingresult->dualbound,
3269 &downbranchingresult->dualboundvalid, &upbranchingresult->dualboundvalid, NULL, oldlpobjval) );
3290 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Lookahead branching on variable <%s> already performed (lpage=%"
3323 SCIP_CALL( SCIPsetVarStrongbranchData(scip, branchvar, lpobjval, branchval, downbranchingresult->dualbound,
3324 upbranchingresult->dualbound, downbranchingresult->dualboundvalid, upbranchingresult->dualboundvalid, niterations,
3346 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
3349 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
3353 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
3456 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
3502 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
3517 downgain = MAX(SCIPsumepsilon(scip), downbranchingresult->dualbound - lpobjval); /*lint !e666*/
3524 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
3558 assert(downbranchingresult->deeperscore >= -0.2 || downbranchingresult->cutoff || SCIPisStopped(scip));
3559 assert(upbranchingresult->deeperscore >= -0.2 || upbranchingresult->cutoff || SCIPisStopped(scip));
3600 assert(downbranchingresult->deeperscore >= -0.2 || downbranchingresult->cutoff || SCIPisStopped(scip));
3601 assert(upbranchingresult->deeperscore >= -0.2 || upbranchingresult->cutoff || SCIPisStopped(scip));
3603 nlowestlevelcutoffs = (1.0 * downbranchingresult->ndeepestcutoffs + upbranchingresult->ndeepestcutoffs)/(MAX(1,downbranchingresult->ndeepestnodes + upbranchingresult->ndeepestnodes));
3667 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
3677 return config->minweight * MIN(downgain, upgain) + (1.0 - config->minweight) * MAX(downgain, upgain);
3680 /** calculates the score as mentioned in the lookahead branching paper by Glankwamdee and Linderoth;
3681 * their score scales the number of cutoffs on the last layer of a 2-level temporary branching tree with the average gain of
3682 * every last level problem; together with the best gain for each branch of a variable we get the final score
3701 nlowestlevelcutoffs = downbranchingresult->ndeepestcutoffs + upbranchingresult->ndeepestcutoffs;
3709 return bestdowngain + bestupgain + (totaldowngains/ntotaldowngains + totalupgains/ntotalupgains)*nlowestlevelcutoffs;
3712 /** calculates the score as mentioned in the lookahead branching paper by Glankwamdee and Linderoth;
3713 * their score scales the number of cutoffs on the last layer of a 2-level temporary branching tree with the average gain of
3714 * every last level problem; together with the best gain for each branch of a variable we get the final score
3734 nlowestlevelcutoffs = (1.0 * downbranchingresult->ndeepestcutoffs + upbranchingresult->ndeepestcutoffs)/(downbranchingresult->ndeepestnodes + upbranchingresult->ndeepestnodes);
3742 return config->minweight*MIN(bestdowngain, bestupgain) + (1.0 - config->minweight)*MAX(bestdowngain, bestupgain) + (totaldowngains/ntotaldowngains + totalupgains/ntotalupgains)*nlowestlevelcutoffs;
3779 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
3823 assert(downbranchingresult->ndeepestnodes + upbranchingresult->ndeepestnodes > 0 || (downbranchingresult->cutoff && upbranchingresult->cutoff));
3825 nlowestlevelcutoffs = (1.0 * downbranchingresult->ndeepestcutoffs + upbranchingresult->ndeepestcutoffs)/(1 + downbranchingresult->ndeepestnodes + upbranchingresult->ndeepestnodes);
3844 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
3904 score = calculateWeightedGain(scip, config, downbranchingresult, upbranchingresult, baselpobjval);
3907 score = calculateScoreFromDeeperscore(scip, branchvar, downbranchingresult, upbranchingresult);
3910 score = calculateScoreFromDeeperscoreAndCutoffs(scip, branchvar, downbranchingresult, upbranchingresult);
3913 score = calculateScoreFromResult2(scip, branchvar, downbranchingresult, upbranchingresult, lpobjval);
3916 score = calculateCutoffScore(scip, branchvar, downbranchingresult, upbranchingresult, lpobjval);
3919 score = calculateRelCutoffScore(scip, branchvar, downbranchingresult, upbranchingresult, lpobjval);
3922 score = calculateScoreFromResult(scip, branchvar, downbranchingresult, upbranchingresult, baselpobjval);
3926 score = calculateScoreFromResult(scip, branchvar, downbranchingresult, upbranchingresult, lpobjval);
3955 /** prints the names of the candidates of the given candidate list with their corresponding scores */
3976 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, " Index %2i: Var %s Score %.9g\n", i, SCIPvarGetName(var), score);
3981 /** sorts the best candidates (w.r.t. the score in the container) of the candidate list to the front of the list */
3987 int nbestcandidates /**< number of candidates that should be kept sorted at the start of the list*/
4013 insertionindex = findInsertionPoint(scip, scorecontainer, movescore, candidatelist->candidates, nsorted);
4040 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "All %i candidates, with the first %i candidates sorted by their FSB score:"
4063 size = MIN(downsize, upsize);
4079 /** Ensures that the scores are present in the scorecontainer for each of the candidates to consider */
4084 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
4087 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
4091 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
4113 /* filter the candidates based on the presence of a score in the 'scorecontainer'. Only those without a score need a
4175 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Calculating the FSB result to get a score for the remaining "
4181 SCIP_CALL( getFSBResult(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, unscoredcandidates,
4184 SCIP_CALL( getFSBResult(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, unscoredcandidates,
4197 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Calculated the scores for the remaining candidates\n");
4210 /** Get the candidates to temporarily branch on. In the LAB case this is the complete list of possible candidates. In the
4216 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
4219 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
4223 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
4243 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Getting the best (at most) %i of the given %i candidates: ",
4249 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "%s", "Ensuring that all candidates have a score.\n");
4251 SCIP_CALL( ensureScoresPresent(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
4254 SCIP_CALL( ensureScoresPresent(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
4281 config->worsefactor * scorecontainer->scores[SCIPvarGetProbindex(candidatelist->candidates[i]->branchvar)] )
4290 SCIP_Real bestmaxgain = MAX(scorecontainer->downgains[SCIPvarGetProbindex(candidatelist->candidates[0]->branchvar)],
4291 scorecontainer->upgains[SCIPvarGetProbindex(candidatelist->candidates[0]->branchvar)]); /*lint !e666*/
4299 maxgain = MAX(scorecontainer->downgains[SCIPvarGetProbindex(candidatelist->candidates[i]->branchvar)],
4300 scorecontainer->upgains[SCIPvarGetProbindex(candidatelist->candidates[i]->branchvar)]); /*lint !e666*/
4317 if( SCIPgetProbingDepth(scip) > 0 && scorecontainer->scores[SCIPvarGetProbindex(candidatelist->candidates[0]->branchvar)] > -0.05)
4321 if( scorecontainer->scores[SCIPvarGetProbindex(candidatelist->candidates[i]->branchvar)] < -0.05 )
4341 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Getting the branching candidates by selecting all candidates.\n");
4347 /** Executes the general branching on a variable in a given direction (up/down) and repeats the algorithm from the new node */
4358 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
4361 BRANCHINGRESULTDATA* branchingresult, /**< container to store the result of the branching in */
4362 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
4364 #ifdef SCIP_STATISTIC
4397 * This list is used to generate a set packing constraint for cutoff branches which were reached by only using
4413 * This list is used to generate a set packing constraint for cutoff branches which were reached by only using
4424 SCIP_Real newbound = downbranching ? SCIPfeasFloor(scip, branchval) : SCIPfeasCeil(scip, branchval);
4464 "Use old %s branching result on var <%s> with 'val > %g' and bounds [<%g>..<%g>]: objval <%.9g>, cutoff <%d> "
4466 downbranching ? "down" : "up", SCIPvarGetName(branchvar), branchval, SCIPvarGetLbLocal(branchvar),
4467 SCIPvarGetUbLocal(branchvar), branchingresult->objval, branchingresult->cutoff, localbaselpsolval);
4474 SCIP_CALL( executeBranching(scip, config, downbranching, candidate, branchingresult, baselpsol, domainreductions,
4483 SCIP_CALL( level2dataStoreResult(scip, level2data, branchingresult->objval, branchingresult->cutoff, branchingresult->dualboundvalid, &duplicate) );
4497 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Solving the LP took %" SCIP_LONGINT_FORMAT " iterations (status %d).\n",
4507 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The solved LP was infeasible and as such is cutoff\n");
4511 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The solved LP was feasible and has an objval <%.9g> (the parent objval was "
4536 /* store the warm start information in the candidate, so that it can be reused in a later branching */
4539 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Storing warm start information for %s branching on var <%s>\n",
4552 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "%sbranching has <%i> candidates.\n", downbranching ? "Down" : "Up",
4571 SCIP_CALL( filterCandidates(scip, deeperstatus, deeperpersistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
4575 SCIP_CALL( filterCandidates(scip, deeperstatus, deeperpersistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
4592 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Now the objval is <%.9g>\n", branchingresult->objval);
4596 SCIP_CALL( selectVarRecursive(scip, deeperstatus, deeperpersistent, config, baselpsol, domainreductions,
4598 deeperlpobjval, baselpobjval, &branchingresult->niterations, &branchingresult->ndeepestcutoffs,
4603 SCIP_CALL( selectVarRecursive(scip, deeperstatus, deeperpersistent, config, baselpsol, domainreductions,
4605 deeperlpobjval, baselpobjval, &branchingresult->niterations, &branchingresult->ndeepestcutoffs,
4615 /* the proved dual bound of the deeper branching cannot be less than the current dual bound, as every deeper
4646 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Both deeper children were cutoff, so the %s branch is "
4658 branchingresult->deeperscore = (branchingresult->dualbound - baselpobjval) * (branchingresult->dualbound - baselpobjval) * 10;
4676 /* the current branching child is infeasible and we only branched on binary variables in lookahead branching */
4701 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
4704 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
4708 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
4713 SCIP_Longint* niterations, /**< pointer to store the total number of iterations for this variable; or NULL*/
4714 int* ndeepestcutoffs, /**< pointer to store the total number of cutoffs on the deepest level; or NULL */
4715 SCIP_Real* bestgain, /**< pointer to store the best gain found with these candidates; or NULL */
4716 SCIP_Real* totalgains, /**< pointer to store the sum over all gains that are valid in both children;
4800 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Started selectVarRecursive with <%i> candidates: ", nlpcands);
4806 /* iterate over all current branching candidates and evaluate their two potential child nodes by:
4809 * - potentially evaluating branching candidates at the potential child node again by applying this method recursively
4812 * - results obtained for a candidate in a previous lookahead branching call at this node may be re-used
4813 * - while i counts the number of candidates evaluated in this call, we do not always start at the front
4814 * of the candidate array, but rather store at which index we stopped last time (e.g., because a domain reduction was
4815 * found and applied) and start from that index next time. Even though the set of branching candidates is probably different
4848 * this may happen if domain propagation on other candidates finds better bounds for the current candidate
4854 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Domain Propagation changed the bounds of a branching candidate."
4862 /* Reset the cutoffproofnodes, as the number of proof nodes from previous branching vars (which where not
4872 if( persistent != NULL && (config->inscoring || probingdepth == 0) && isUseOldBranching(scip, persistent, config, branchvar) )
4874 SCIP_CALL( getOldBranching(scip, persistent, config, branchvar, downbranchingresult, upbranchingresult,
4889 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, "Started branching on var <%s> with val <%g> and bounds "
4913 SCIP_CALL( executeBranchingRecursive(scip, status, config, baselpsol, candidate, lpobjval, baselpobjval,
4914 recursiondepth, localdomainreductions, binconsdata, level2data, localbranchingresult, scorecontainer,
4918 SCIP_CALL( executeBranchingRecursive(scip, status, config, baselpsol, candidate, lpobjval, baselpobjval,
4919 recursiondepth, localdomainreductions, binconsdata, level2data, localbranchingresult, scorecontainer,
4941 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, "-> down=%.9g (gain=%.9g, valid=%u, inf=%u), up=%.9g "
4944 downbranchingresult->cutoff, upbranchingresult->dualbound, upbranchingresult->dualbound - lpobjval,
4951 if( persistent != NULL && !upbranchingresult->cutoff && !downbranchingresult->cutoff && (config->inscoring || probingdepth == 0) )
4953 SCIP_CALL( updateOldBranching(scip, persistent, config, branchvar, branchval, downbranchingresult,
4967 SCIP_Real score = calculateScore(scip, config, branchvar, downbranchingresult, upbranchingresult,
4975 if( bestgain != NULL && !config->inscoring && SCIPgetProbingDepth(scip) == 1 && !useoldbranching )
4992 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, " -> variable <%s> is infeasible in both directions\n",
5005 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, " -> variable <%s> is infeasible in upward branch\n",
5008 /* apply down branching bound change at current node if we proved that this node is really infeasible and
5035 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, " -> variable <%s> is infeasible in downward branch\n",
5038 /* apply up branching bound change at current node if we proved that this node is really infeasible and
5065 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Neither branch is cut off and no limit reached.\n");
5085 if( !upbranchingresult->cutoff && !downbranchingresult->cutoff && config->mergedomainreductions )
5086 applyDeeperDomainReductions(scip, baselpsol, maxstoredomreds, domainreductions, downdomainreductions,
5089 applySingleDeeperDomainReductions(scip, baselpsol, maxstoredomreds, domainreductions, downdomainreductions);
5091 applySingleDeeperDomainReductions(scip, baselpsol, maxstoredomreds, domainreductions, updomainreductions);
5100 bestdownbranchingresult->dualbound = MAX(bestdownbranchingresult->dualbound, decision->proveddb);
5103 newscore = calculateScore(scip, config, decision->branchvar, bestdownbranchingresult, bestupbranchingresult,
5120 /* the current candidate variable has a better score than the best candidate investigated so far */
5125 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Old best var <%s> with bounds [<%g>..<%g>] and score %.9g\n",
5168 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "New best var <%s> with bounds [<%g>..<%g>] and score %.9g\n",
5173 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, " -> cand %d/%d var <%s> (solval=%.9g, downgain=%.9g->%.9g, upgain=%.9g->%.9g,"
5175 MAX(downbranchingresult->objval - scoringlpobjval, 0), MAX(downbranchingresult->dualbound - scoringlpobjval, 0),
5176 MAX(upbranchingresult->objval - scoringlpobjval, 0), MAX(upbranchingresult->dualbound - scoringlpobjval, 0),
5183 /* only for abbreviated lookahead branching: we are in the FSB filtering step and store the score for this
5184 * variable and the warm starting basis to reuse it in the subsequent lookahead evaluation of the best
5188 downbranchingresult->dualbound - scoringlpobjval, upbranchingresult->dualbound - scoringlpobjval) );
5192 && (config->maxnviolatedcons >= 0 || config->maxnviolatedbincons >= 0 || config->maxnviolateddomreds >= 0 ) )
5201 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Found %d binary constraints (%d violated by the LP solution)\n",
5206 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The max number of violated binary constraints <%i> is "
5219 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Found %d bound changes (%d violated by the LP solution)\n",
5232 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The max number of violated binary constraints and bound "
5239 if( !(status->domred && decision->branchvar == candidate->branchvar) && areBoundsChanged(scip, decision->branchvar, bestscorelowerbound, bestscoreupperbound) )
5241 /* in case the bounds of the current highest scored solution have changed due to domain propagation during
5242 * the lookahead branching we can/should not branch on this variable but instead report the domain
5248 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Domain Propagation changed the bounds of a branching candidate."
5276 /** checks whether the current decision should be stored. This is the case if we found domain reductions
5278 * Then our current decision still holds true for the next call and can be reused without further calculations
5284 DOMAINREDUCTIONS* domainreductions /**< container collecting all domain reductions found; or NULL */
5310 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
5313 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */