branch_lookahead.c
Go to the documentation of this file.
32 * The (multi-level) lookahead branching rule applies strong branching to every fractional value of the LP solution
33 * at the current node of the branch-and-bound tree, as well as recursivly to every temporary child problem created by this
43 * For a more mathematical description and a comparison between lookahead branching and other branching rules
57 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
90 #define DEFAULT_USEBINARYCONSTRAINTS FALSE /**< should binary constraints be collected and applied? */
91 #define DEFAULT_ADDCLIQUE FALSE /**< add binary constraints with two variables found at the root node also as a clique? */
94 #define DEFAULT_USEDOMAINREDUCTION TRUE /**< Should domain reductions be collected and applied? */
95 #define DEFAULT_MERGEDOMAINREDUCTIONS FALSE /**< should domain reductions of feasible siblings should be merged? */
96 #define DEFAULT_PREFERSIMPLEBOUNDS FALSE /**< should domain reductions only be applied if there are simple bound changes? */
97 #define DEFAULT_ONLYVIOLDOMREDS FALSE /**< Should only domain reductions that violate the LP solution be applied? */
98 #define DEFAULT_MAXNVIOLATEDCONS 1 /**< How many constraints that are violated by the base lp solution
100 #define DEFAULT_MAXNVIOLATEDBINCONS 0 /**< How many binary constraints that are violated by the base lp
103 #define DEFAULT_MAXNVIOLATEDDOMREDS 1 /**< How many domain reductions that are violated by the base lp solution
105 #define DEFAULT_STOREUNVIOLATEDSOL TRUE /**< If only non violating constraints are added, should the branching
107 #define DEFAULT_REEVALAGE 10LL /**< Max number of LPs solved after which a previous prob branching
109 #define DEFAULT_REEVALAGEFSB 10LL /**< Max number of LPs solved after which a previous FSB scoring
112 #define DEFAULT_ADDNONVIOCONS FALSE /**< Should binary constraints, that are not violated by the base LP, be
114 #define DEFAULT_PROPAGATE TRUE /**< Should domain propagation be executed before each temporary node is
116 #define DEFAULT_USELEVEL2DATA TRUE /**< should branching data generated at depth level 2 be stored for re-using it? */
118 #define DEFAULT_ENFORCEMAXDOMREDS FALSE /**< should the maximum number of domain reductions maxnviolateddomreds be enforced? */
119 #define DEFAULT_UPDATEBRANCHINGRESULTS FALSE /**< should branching results (and scores) be updated w.r.t. proven dual bounds? */
120 #define DEFAULT_MAXPROPROUNDS 0 /**< maximum number of propagation rounds to perform at temporary
123 #define DEFAULT_MAXNCANDS 4 /**< If abbreviated: The max number of candidates to consider at the base node */
124 #define DEFAULT_MAXNDEEPERCANDS 2 /**< If abbreviated: The max number of candidates to consider per deeper node
126 #define DEFAULT_REUSEBASIS TRUE /**< If abbreviated: Should the information gathered to obtain the best
128 #define DEFAULT_ABBREVPSEUDO FALSE /**< If abbreviated: Use pseudo costs to estimate the score of a
130 #define DEFAULT_LEVEL2AVGSCORE FALSE /**< should the average score be used for uninitialized scores in level 2? */
135 #define DEFAULT_MINWEIGHT 0.8 /**< default value for the weight of the minimum in the convex combination of two
137 #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) */
138 #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? */
168 /* Writes a debug message without the leading information. Can be used to append something to an output of LABdebugMessage*/
183 /** A struct holding information to speed up the solving time for solving a problem again. This is filled by the FSB
184 * scoring routine that is run to get the best candidates. It is then read by the actual ALAB routine. */
187 SCIP_LPISTATE* lpistate; /**< the basis information that may be set before another solve lp call */
193 /** Allocates the warm start information on the buffer and initializes it with default values. */
239 {
259 WARMSTARTINFO* downwarmstartinfo; /**< the warm start info containing the lp data from a previous down branch */
260 WARMSTARTINFO* upwarmstartinfo; /**< the warm start info containing the lp data from a previous up branch */
269 {
280 }
292 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "freeing warmstart info of candidate <%s>(%u/%u)...\n",
299 }
309 /** Frees the allocated buffer memory of the candidate and clears the contained lpi memories. */
378 /** returns whether the candidate has stored warm starting information for the given direction */
387 return warmStartInfoIsAvailable(down ? candidate->downwarmstartinfo : candidate->upwarmstartinfo);
411 /* 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
413 * Some iterations may occur, as the conflict analysis may have added some constraints in the meantime. */
414 SCIP_CALL( SCIPsetProbingLPState(scip, &(warmstartinfo->lpistate), &(warmstartinfo->lpinorms), warmstartinfo->primalfeas,
417 /* The state and norms will be freed later by the SCIP framework. Therefore they are set to NULL to enforce that we won't
439 SCIP_Bool downdbvalid; /**< Indicator for the validity of the downdb value. Is FALSE, if no actual
454 )
494 * this is used to store the most important information (i.e., the dual bounds obtained) so that it can be used in a
495 * subsequent call in case the LP solution did not change because we only added bound changes that did not forbid the
497 * however, we do not want to store all the domain changes for the two potential child nodes for this rare case, they
534 /* a branching decision is deemed valid, if the var pointer is not on the default NULL value (see the allocate method) */
555 }
592 SCIP_Real dualbound; /**< The best dual bound for this branching, may be changed by deeper level
596 SCIP_Bool dualboundvalid; /**< Is the value of the dual bound valid? That means, was the according LP
600 SCIP_Real bestgain; /**< best gain (w.r.t. to the base lp) on the lowest level below this child */
611 )
683 SCIP_Real lpobjval; /**< the objective value of the solved lp; only contains meaningful data, if
689 unsigned int branchdir1:1; /**< branching direction for first branching variable (0:down, 1:up) */
690 unsigned int branchdir2:1; /**< branching direction for second branching variable (0:down, 1:up) */
705 unsigned int branchdir1:1; /**< branching direction for first branching variable (0:down, 1:up) */
706 unsigned int branchdir2:1; /**< branching direction for second branching variable (0:down, 1:up) */
709 /** allocates a double branching result in the memory and fills it with the information stored in the level 2 data */
715 )
716 {
783 /** returns TRUE iff both level 2 results are equal; two branchings are equal if they branched on the same variables
826 (*data)->branchvar1 = 0;
873 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &data->level2results, data->level2resultssize, newsize) );
928 SCIP_Bool* duplicate /**< pointer to store whether information for the same branching decisions was already stored */
978 BRANCHINGDECISION* olddecision; /**< The previous decision that gets used for the case that in the previous run
980 SCIP_Longint oldnnodelpiterations; /**< node LP iterations when previous branching decision was stored */
983 SCIP_Longint* lastbranchid; /**< The node id at which the var was last branched on (for a given branching
985 SCIP_Longint* lastbranchnlps; /**< The number of (non-probing) LPs that where solved when the var was last
988 BRANCHINGRESULTDATA** lastbranchupres; /**< The result of the last up branching for a given var. */
989 BRANCHINGRESULTDATA** lastbranchdownres; /**< The result of the last down branching for a given var. */
990 int restartindex; /**< The index at which the iteration over the number of candidates starts. */
994 /** The parameter that can be changed by the user/caller and alter the behaviour of the lookahead branching. */
996 {
997 SCIP_Longint reevalage; /**< The number of "normal" (not probing) lps that may have been solved before
999 SCIP_Longint reevalagefsb; /**< The number of "normal" (not probing) lps that may have been solved before
1001 int maxnviolatedcons; /**< The number of constraints (domain reductions and binary constraints) we
1004 int maxnviolatedbincons;/**< The number of binary constraints we want to gather before restarting the
1006 int maxnviolateddomreds;/**< The number of domain reductions we want to gather before restarting the
1009 int maxncands; /**< If abbreviated == TRUE, at most how many candidates should be handled at the base node? */
1010 int maxndeepercands; /**< If abbreviated == TRUE, at most how many candidates should be handled in deeper nodes? */
1011 SCIP_Bool usedomainreduction; /**< indicates whether the data for domain reductions should be gathered and
1013 SCIP_Bool mergedomainreductions; /**< should domain reductions of feasible siblings should be merged? */
1014 SCIP_Bool prefersimplebounds; /**< should domain reductions only be applied if there are simple bound changes? */
1015 SCIP_Bool onlyvioldomreds; /**< Should only domain reductions that violate the LP solution be applied? */
1016 SCIP_Bool usebincons; /**< indicates whether the data for the implied binary constraints should
1020 SCIP_Bool addnonviocons; /**< Should constraints be added, that are not violated by the base LP? */
1022 SCIP_Bool reusebasis; /**< If abbreviated == TRUE, should the solution lp-basis of the FSB run be
1024 SCIP_Bool storeunviolatedsol; /**< Should a solution/decision be stored, to speed up the next iteration
1026 SCIP_Bool abbrevpseudo; /**< If abbreviated == TRUE, should pseudocost values be used, to approximate
1028 SCIP_Bool level2avgscore; /**< should the average score be used for uninitialized scores in level 2? */
1030 SCIP_Bool addclique; /**< add binary constraints with two variables found at the root node also as a clique? */
1032 SCIP_Bool uselevel2data; /**< should branching data generated at depth level 2 be stored for re-using it? */
1034 SCIP_Bool enforcemaxdomreds; /**< should the maximum number of domain reductions maxnviolateddomreds be enforced? */
1035 SCIP_Bool updatebranchingresults; /**< should branching results (and scores) be updated w.r.t. proven dual bounds? */
1043 SCIP_Real worsefactor; /**< if the FSB score is of a candidate is worse than the best by this factor, skip this candidate (-1: disable) */
1044 SCIP_Bool filterbymaxgain; /**< should lookahead branching only be applied if the max gain in level 1 is not uniquely that of the best candidate? */
1055 )
1056 {
1057 assert(result >= 1);
1058 assert(result <= 18);
1113 int* nsinglecutoffs; /**< The number of single cutoffs on a (probing) node per probingdepth. */
1118 SCIP_Longint* nlpiterations; /**< The number of all lp iterations needed for a given probingdepth
1120 SCIP_Longint* nlpiterationsfsb; /**< The number of lp iterations needed to get the FSB scores. */
1125 int* noldbranchusedfsb; /**< The number of times old FSB scoring data is used (see the reevalagefsb
1127 int* chosenfsbcand; /**< If abbreviated, this is the number of times each candidate was finally
1131 int* cutoffafterfsb; /**< If abbreviated, this is the number of times the rule was stopped after
1133 int* domredafterfsb; /**< If abbreviated, this is the number of times the rule was stopped after
1135 int nsinglecandidate; /**< number of times a single candidate was given to the recursion routine */
1139 int nlperrorcalls; /**< number of times an LP error occured and LAB branched without completely
1145 int nbinconstvio; /**< The number of binary constraints added to the base node, that are violated
1150 int ndepthreached; /**< The number of times the branching was aborted due to a too small depth. */
1155 int maxnbestcands; /**< if abbreviated, this is the maximum number of candidates to investigate */
1156 int recursiondepth; /**< The recursiondepth of the LAB. Can be used to access the depth-dependent
1231 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Lookahead Branching was called <%i> times.\n", statistics->ntotalresults);
1237 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Result <%s> was chosen <%i> times\n", getStatusString(currentresult),
1245 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "The %i. variable (w.r.t. the FSB score) was chosen as the final result %i times.\n",
1252 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",
1254 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "In depth <%i>, <%i> fullcutoffs and <%i> single cutoffs were found.\n",
1256 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",
1258 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "In depth <%i>, <%" SCIP_LONGINT_FORMAT "> iterations were needed to solve the LPs, <%"
1259 SCIP_LONGINT_FORMAT "> of them to calculate the FSB score.\n", i, statistics->nlpiterations[i],
1261 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "In depth <%i>, a decision was discarded <%i> times due to domain reduction because of"
1263 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",
1267 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "One single branching candidate was given <%i> times, after filtering, a single candidate remained <%i> times.\n",
1269 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "The old branching candidate was used <%i> times.\n",
1271 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "An LP error led to branching before all candidates were evaluated <%i> times.\n",
1273 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "A reached (time) limit led to branching before all candidates were evaluated <%i> times.\n",
1275 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Depth limit was reached <%i> times.\n", statistics->ndepthreached);
1276 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Ignored <%i> binary constraints, that would be domain reductions.\n",
1278 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Added <%i> binary constraints, of which <%i> where violated by the base LP.\n",
1280 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Reduced the domain of <%i> vars, <%i> of them where violated by the base LP.\n",
1282 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Added <%i> cliques found as binary constraint in the root node\n",
1284 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Needed <%i> additional nodes to prove the cutoffs of base nodes\n",
1286 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Needed <%i> additional nodes to prove the domain reductions\n",
1301 LOCALSTATISTICS** localstats /**< pointer to the local statistics to allocate and initialize */
1331 CONFIGURATION* config; /**< the parameter that influence the behaviour of the lookahead branching */
1357 )
1358 {
1361 assert(startsize > 0);
1393 {
1397 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &list->nconsvars, list->memorysize, newmemsize) );
1403 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &list->consvars[list->nelements], consvars, nconsvars) ); /*lint !e866*/
1438 * these variables are used to build the binary constraint in case that a ('binary') branch is cut off
1455 {
1458 assert(startsize > 0);
1465 (*list)->memorysize = startsize;
1487 }
1535 assert(maxdepth > 0);
1536 assert(nstartcons > 0);
1562 {
1564 int ncandidates; /**< the number of actual entries in candidates (without trailing NULLs); this
1569 /** allocates the candidate list on the buffer WITHOUT initializing the contained array of candidates. */
1576 {
1579 assert(ncandidates >= 0);
1586 }
1595 /** allocates the given list and fills it with all fractional candidates of the current LP solution. */
1612 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) );
1640 /** frees the allocated buffer memory of the candidate list and frees the contained candidates. */
1688 {
1706 SCIP_Shortbool* baselpviolated; /**< Indicates whether the base lp solution violates the new bounds of a var.*/
1707 int nviolatedvars; /**< Tracks the number of vars that have a violated (by the base lp) new lower
1709 int nchangedvars; /**< Tracks the number of vars, that have a changed domain. (a change on both,
1713 int* lowerboundnproofs; /**< The number of nodes needed to prove the lower bound for each variable. */
1714 int* upperboundnproofs; /**< The number of nodes needed to prove the upper bound for each variable. */
1724 {
1732 /* The arrays saves the data for all variables in the problem via the ProbIndex. See SCIPvarGetProbindex() */
1760 /** frees the given DOMAINREDUCTIONS and all contained Arrays in the opposite order of allocation */
1791 SCIP_Bool maxnconsreached; /**< was the max number of constraints (bin conss and dom red) reached? */
1799 )
1800 {
1836 CANDIDATE** bestsortedcands; /**< array containing the best sorted variable indices w.r.t. their score */
1846 )
1851 }
1859 )
1869 /* the container saves the score for all variables in the problem via the ProbIndex, see SCIPvarGetProbindex() */
1898 /** Finds the insertion index for the given score in the candidate list. The score of each candidate is taken from the
1899 * scorecontainer. The first elements of the candidate list have to be sorted, as this method uses binary search to find
1907 CANDIDATE** candidates, /**< candidate list where the first nsorted elements are sorted (w.r.t. their
1918 assert(ncandidates >= 0);
1945 /** Inserts the given probindex into the sorted array in the container, moving all indices after it to the right. Then
2012 /* insert the current variable (cand) at the position calculated above, returning the candidate that
2013 * was removed at the end of the list; this candidate can be the given candidate for the case that the score does not
2023 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Stored score <%.9g> for var <%s>.\n", score, SCIPvarGetName(cand->branchvar));
2038 /* don't free the candidates inside the cands array, as those are handled by the candidate list */
2057 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
2069 SCIP_Longint* niterations, /**< pointer to store the total number of iterations for this variable */
2070 int* ndeepestcutoffs, /**< pointer to store the total number of cutoffs on the deepest level */
2072 SCIP_Real* totalgains, /**< pointer to store the sum over all gains that are valid in both children */
2089 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
2095 ,int force /**< should the number of proof nodes be added even if the bound is known already? */
2128 /* if the given lower bound is equal to the old one we take the smaller number of proof nodes */
2135 /* we get the solution value to check whether the domain reduction is violated in the base LP */
2138 /* in case the new lower bound is greater than the base solution val and the base solution val is not violated by a
2139 * previously found bound, we increment the nviolatedvars counter and set the baselpviolated flag */
2154 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
2160 ,int force /**< should the number of proof nodes be added even if the bound is known already? */
2183 /* if the given upper bound is equal to the old one we take the smaller number of proof nodes */
2202 /* We get the solution value to check whether the domain reduction is violated in the base LP */
2205 /* In case the new upper bound is smaller than the base solution val and the base solution val is not violated by a
2206 * previously found bound, we increment the nviolatedvars counter and set the baselpviolated flag. */
2215 /** apply the domain reductions from a single struct to another one; this may be used in case one of the two child
2221 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
2224 DOMAINREDUCTIONS* targetdomreds, /**< The target that should be filled with the merged data. */
2270 * merges the domain reduction data from the two given branching children data into the target parent data
2275 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
2278 DOMAINREDUCTIONS* targetdomreds, /**< The target that should be filled with the merged data. */
2300 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Combining domain reductions from up and down child.\n");
2301 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Previous number of changed variable domains: %d\n",
2304 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Number of changed variable domains in up child: %d\n",
2306 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Number of changed variable domains in down child: %d\n",
2345 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Subsequent number of changed variable domains: %d\n",
2354 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
2356 DOMAINREDUCTIONS* domreds, /**< The domain reductions that should be applied to the current node. */
2357 SCIP_Bool* domredcutoff, /**< pointer to store whether a cutoff was found due to domain reductions */
2426 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Variable <%s>, old lower bound <%g>, proposed lower bound <%g>, new "
2434 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The domain reduction of variable <%s> resulted in an empty "
2445 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The lower bound of variable <%s> was successfully tightened (%d).\n",
2453 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The lower bound of variable <%s> is violated by the base lp "
2477 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Variable <%s>, old upper bound <%g>, proposed upper bound <%g>, new "
2485 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The domain reduction of variable <%s> resulted in an empty "
2496 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The upper bound of variable <%s> was successfully tightened (%d).\n",
2504 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The upper bound of variable <%s> is violated by the base lp "
2519 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Truly changed <%d> domains of the problem, <%d> of them are violated by the "
2541 }
2564 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Effective branching on var <%s> with value <%g(%g)>. Old domain: [%g..%g].\n",
2565 SCIPvarGetName(bestvar), bestval, SCIPgetSolVal(scip, NULL, bestvar), SCIPvarGetLbLocal(bestvar), SCIPvarGetUbLocal(bestvar));
2574 SCIPdebugMsg(scip, "down child (node %" SCIP_LONGINT_FORMAT "): branching bound change <%s> <= %g\n",
2576 SCIPdebugMsg(scip, "up child (node %" SCIP_LONGINT_FORMAT "): branching bound change <%s> >= %g\n",
2582 /* update the lower bounds in the children; we must not do this if columns are missing in the LP
2593 SCIP_CALL( SCIPupdateNodeLowerbound(scip, downchild, bestdownvalid ? MAX(bestdown, provedbound) : provedbound) );
2594 SCIP_CALL( SCIPupdateNodeLowerbound(scip, upchild, bestupvalid ? MAX(bestup, provedbound) : provedbound) );
2629 SCIPdebugMsg(scip, "down child (node %" SCIP_LONGINT_FORMAT "): add bound change <%s> >= %g\n",
2633 /* update the upper bound of the lower child in case it is better than the current one AND it is not the
2640 SCIPdebugMsg(scip, "down child (node %" SCIP_LONGINT_FORMAT "): add bound change <%s> <= %g\n",
2647 /* update the lower bound of the upper child in case it is better than the current one AND it is not the
2669 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, " -> down child's lowerbound: %.9g, estimate: %.9g\n",
2671 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, " -> up child's lowerbound: %.9g, estimate: %.9g\n",
2701 /** Creates a new probing node with a new bound for the given candidate and solves the corresponding LP. */
2708 BRANCHINGRESULTDATA* resultdata, /**< pointer to the result data which gets filled with the status */
2710 DOMAINREDUCTIONS* domreds, /**< struct to store the domain reduction found during propagation */
2751 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "DownBranching: Var=<%s>, Proposed upper bound=<%g>, "
2752 "old bounds=[<%g>..<%g>], new bounds=[<%g>..<%g>]\n", SCIPvarGetName(branchvar), newbound, oldlowerbound,
2757 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "UpBranching: Var=<%s>, Proposed lower bound=<%g>, "
2758 "old bounds=[<%g>..<%g>], new bounds=[<%g>..<%g>]\n", SCIPvarGetName(branchvar), newbound, oldlowerbound,
2803 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Restoring lp information for %s branch of variable <%s>\n",
2813 SCIP_CALL( SCIPpropagateProbing(scip, config->maxproprounds, &resultdata->cutoff, &ndomredsfound) );
2817 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Found %" SCIP_LONGINT_FORMAT " domain reductions via propagation.\n", ndomredsfound);
2862 /* for us an error occurred, if an error during the solving occurred or the lp could not be solved but was not
2864 status->lperror = status->lperror || (solstat == SCIP_LPSOLSTAT_NOTSOLVED && resultdata->cutoff == FALSE);
2866 /* if we seem to have reached a {time, iteration}-limit or the user cancelled the execution, we want to stop
2868 status->limitreached = (solstat == SCIP_LPSOLSTAT_ITERLIMIT) || (solstat == SCIP_LPSOLSTAT_TIMELIMIT);
2882 /* if we have no error, we save the new objective value and the cutoff decision in the resultdata */
2886 resultdata->cutoff = resultdata->cutoff || SCIPisGE(scip, resultdata->objval, SCIPgetCutoffbound(scip));
2895 /** Creates a logic or constraint based on the given 'consvars'. This array has to consist of the negated
2896 * versions of the variables present on a cutoff "path" (path means all variables from the root directly
2898 * Let x_1, ..., x_n be the variables on a path to a cutoff with the branchings x_i <= 1 for all i.
2937 SCIP_CALL( SCIPcreateConsLogicor(scip, constraint, constraintname, nconsvars, consvars, initial, separate, enforce,
2959 (void) SCIPsnprintf(constraintname, SCIP_MAXSTRLEN, "lookahead_bin_%s", SCIPvarGetName(binaryvars[0]));
2975 * The implied binary bounds were found when two or more consecutive branchings of binary variables were cutoff. Then these
2983 SCIP_SOL* baselpsol /**< the original lp solution, used to check the violation of the constraint */
2996 /* if we only have one var for the constraint, we can ignore it as it is already added as a domain reduction. */
3026 /* the constraint we will be building is a logic or: we have a list of binary variables that were
3029 * is violating this constraint we count this for our number of violated constraints and bounds. */
3056 SCIP_Bool* boundchange /**< pointer to store whether a bound change has been applied by adding the
3077 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "processing %d binary constraints.\n", conslist->nelements);
3141 /* a two-variable logicor constraint x + y >= 1 yields the implication x == 0 -> y == 1, and is represented
3161 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "added %d/%d binary constraints.\n", nconsadded, conslist->nelements);
3192 /* due to roundings the value might have changed slightly without an actual influence on the integral value */
3196 /** Checks whether the branching rule should continue or terminate with the currently gathered data */
3209 /** Checks whether the branching rule should continue or terminate with the currently gathered data. Additionally decrements
3210 * the given loopcounter. This is needed to better emulate the behavior of FSB by LAB with a depth of 1. */
3243 /* an old branching can be reused, if we are still at the same node and just a few LPs were solved in between */
3252 && SCIPgetNLPs(scip) - persistent->lastbranchnlps[SCIPvarGetProbindex(branchvar)] < config->reevalage;
3277 SCIP_CALL( SCIPgetVarStrongbranchLast(scip, branchvar, &downbranchingresult->dualbound, &upbranchingresult->dualbound,
3278 &downbranchingresult->dualboundvalid, &upbranchingresult->dualboundvalid, NULL, oldlpobjval) );
3299 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Lookahead branching on variable <%s> already performed (lpage=%"
3332 SCIP_CALL( SCIPsetVarStrongbranchData(scip, branchvar, lpobjval, branchval, downbranchingresult->dualbound,
3333 upbranchingresult->dualbound, downbranchingresult->dualboundvalid, upbranchingresult->dualboundvalid, niterations,
3355 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
3358 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
3362 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
3465 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
3511 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
3526 downgain = MAX(SCIPsumepsilon(scip), downbranchingresult->dualbound - lpobjval); /*lint !e666*/
3533 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
3567 assert(downbranchingresult->deeperscore >= -0.2 || downbranchingresult->cutoff || SCIPisStopped(scip));
3568 assert(upbranchingresult->deeperscore >= -0.2 || upbranchingresult->cutoff || SCIPisStopped(scip));
3609 assert(downbranchingresult->deeperscore >= -0.2 || downbranchingresult->cutoff || SCIPisStopped(scip));
3610 assert(upbranchingresult->deeperscore >= -0.2 || upbranchingresult->cutoff || SCIPisStopped(scip));
3612 nlowestlevelcutoffs = (1.0 * downbranchingresult->ndeepestcutoffs + upbranchingresult->ndeepestcutoffs)/(MAX(1,downbranchingresult->ndeepestnodes + upbranchingresult->ndeepestnodes));
3676 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
3686 return config->minweight * MIN(downgain, upgain) + (1.0 - config->minweight) * MAX(downgain, upgain);
3689 /** calculates the score as mentioned in the lookahead branching paper by Glankwamdee and Linderoth;
3690 * their score scales the number of cutoffs on the last layer of a 2-level temporary branching tree with the average gain of
3691 * every last level problem; together with the best gain for each branch of a variable we get the final score
3710 nlowestlevelcutoffs = downbranchingresult->ndeepestcutoffs + upbranchingresult->ndeepestcutoffs;
3718 return bestdowngain + bestupgain + (totaldowngains/ntotaldowngains + totalupgains/ntotalupgains)*nlowestlevelcutoffs;
3721 /** calculates the score as mentioned in the lookahead branching paper by Glankwamdee and Linderoth;
3722 * their score scales the number of cutoffs on the last layer of a 2-level temporary branching tree with the average gain of
3723 * every last level problem; together with the best gain for each branch of a variable we get the final score
3743 nlowestlevelcutoffs = (1.0 * downbranchingresult->ndeepestcutoffs + upbranchingresult->ndeepestcutoffs)/(downbranchingresult->ndeepestnodes + upbranchingresult->ndeepestnodes);
3751 return config->minweight*MIN(bestdowngain, bestupgain) + (1.0 - config->minweight)*MAX(bestdowngain, bestupgain) + (totaldowngains/ntotaldowngains + totalupgains/ntotalupgains)*nlowestlevelcutoffs;
3788 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
3832 assert(downbranchingresult->ndeepestnodes + upbranchingresult->ndeepestnodes > 0 || (downbranchingresult->cutoff && upbranchingresult->cutoff));
3834 nlowestlevelcutoffs = (1.0 * downbranchingresult->ndeepestcutoffs + upbranchingresult->ndeepestcutoffs)/(1 + downbranchingresult->ndeepestnodes + upbranchingresult->ndeepestnodes);
3853 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
3913 score = calculateWeightedGain(scip, config, downbranchingresult, upbranchingresult, baselpobjval);
3916 score = calculateScoreFromDeeperscore(scip, branchvar, downbranchingresult, upbranchingresult);
3919 score = calculateScoreFromDeeperscoreAndCutoffs(scip, branchvar, downbranchingresult, upbranchingresult);
3922 score = calculateScoreFromResult2(scip, branchvar, downbranchingresult, upbranchingresult, lpobjval);
3925 score = calculateCutoffScore(scip, branchvar, downbranchingresult, upbranchingresult, lpobjval);
3928 score = calculateRelCutoffScore(scip, branchvar, downbranchingresult, upbranchingresult, lpobjval);
3931 score = calculateScoreFromResult(scip, branchvar, downbranchingresult, upbranchingresult, baselpobjval);
3935 score = calculateScoreFromResult(scip, branchvar, downbranchingresult, upbranchingresult, lpobjval);
3964 /** prints the names of the candidates of the given candidate list with their corresponding scores */
3985 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, " Index %2i: Var %s Score %.9g\n", i, SCIPvarGetName(var), score);
3990 /** sorts the best candidates (w.r.t. the score in the container) of the candidate list to the front of the list */
3996 int nbestcandidates /**< number of candidates that should be kept sorted at the start of the list*/
4022 insertionindex = findInsertionPoint(scip, scorecontainer, movescore, candidatelist->candidates, nsorted);
4049 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "All %i candidates, with the first %i candidates sorted by their FSB score:"
4072 size = MIN(downsize, upsize);
4088 /** Ensures that the scores are present in the scorecontainer for each of the candidates to consider */
4093 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
4096 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
4100 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
4122 /* filter the candidates based on the presence of a score in the 'scorecontainer'. Only those without a score need a
4184 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Calculating the FSB result to get a score for the remaining "
4190 SCIP_CALL( getFSBResult(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, unscoredcandidates,
4193 SCIP_CALL( getFSBResult(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, unscoredcandidates,
4206 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Calculated the scores for the remaining candidates\n");
4219 /** Get the candidates to temporarily branch on. In the LAB case this is the complete list of possible candidates. In the
4225 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
4228 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
4232 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
4252 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Getting the best (at most) %i of the given %i candidates: ",
4258 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "%s", "Ensuring that all candidates have a score.\n");
4260 SCIP_CALL( ensureScoresPresent(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
4263 SCIP_CALL( ensureScoresPresent(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
4290 config->worsefactor * scorecontainer->scores[SCIPvarGetProbindex(candidatelist->candidates[i]->branchvar)] )
4299 SCIP_Real bestmaxgain = MAX(scorecontainer->downgains[SCIPvarGetProbindex(candidatelist->candidates[0]->branchvar)],
4300 scorecontainer->upgains[SCIPvarGetProbindex(candidatelist->candidates[0]->branchvar)]); /*lint !e666*/
4308 maxgain = MAX(scorecontainer->downgains[SCIPvarGetProbindex(candidatelist->candidates[i]->branchvar)],
4309 scorecontainer->upgains[SCIPvarGetProbindex(candidatelist->candidates[i]->branchvar)]); /*lint !e666*/
4326 if( SCIPgetProbingDepth(scip) > 0 && scorecontainer->scores[SCIPvarGetProbindex(candidatelist->candidates[0]->branchvar)] > -0.05)
4330 if( scorecontainer->scores[SCIPvarGetProbindex(candidatelist->candidates[i]->branchvar)] < -0.05 )
4350 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Getting the branching candidates by selecting all candidates.\n");
4356 /** Executes the general branching on a variable in a given direction (up/down) and repeats the algorithm from the new node */
4367 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
4370 BRANCHINGRESULTDATA* branchingresult, /**< container to store the result of the branching in */
4371 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
4373 #ifdef SCIP_STATISTIC
4406 * This list is used to generate a set packing constraint for cutoff branches which were reached by only using
4422 * This list is used to generate a set packing constraint for cutoff branches which were reached by only using
4433 SCIP_Real newbound = downbranching ? SCIPfeasFloor(scip, branchval) : SCIPfeasCeil(scip, branchval);
4473 "Use old %s branching result on var <%s> with 'val > %g' and bounds [<%g>..<%g>]: objval <%.9g>, cutoff <%d> "
4475 downbranching ? "down" : "up", SCIPvarGetName(branchvar), branchval, SCIPvarGetLbLocal(branchvar),
4476 SCIPvarGetUbLocal(branchvar), branchingresult->objval, branchingresult->cutoff, localbaselpsolval);
4483 SCIP_CALL( executeBranching(scip, config, downbranching, candidate, branchingresult, baselpsol, domainreductions,
4492 SCIP_CALL( level2dataStoreResult(scip, level2data, branchingresult->objval, branchingresult->cutoff, branchingresult->dualboundvalid, &duplicate) );
4506 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Solving the LP took %" SCIP_LONGINT_FORMAT " iterations (status %d).\n",
4516 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The solved LP was infeasible and as such is cutoff\n");
4520 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The solved LP was feasible and has an objval <%.9g> (the parent objval was "
4545 /* store the warm start information in the candidate, so that it can be reused in a later branching */
4548 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Storing warm start information for %s branching on var <%s>\n",
4561 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "%sbranching has <%i> candidates.\n", downbranching ? "Down" : "Up",
4580 SCIP_CALL( filterCandidates(scip, deeperstatus, deeperpersistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
4584 SCIP_CALL( filterCandidates(scip, deeperstatus, deeperpersistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
4601 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Now the objval is <%.9g>\n", branchingresult->objval);
4605 SCIP_CALL( selectVarRecursive(scip, deeperstatus, deeperpersistent, config, baselpsol, domainreductions,
4607 deeperlpobjval, baselpobjval, &branchingresult->niterations, &branchingresult->ndeepestcutoffs,
4612 SCIP_CALL( selectVarRecursive(scip, deeperstatus, deeperpersistent, config, baselpsol, domainreductions,
4614 deeperlpobjval, baselpobjval, &branchingresult->niterations, &branchingresult->ndeepestcutoffs,
4624 /* the proved dual bound of the deeper branching cannot be less than the current dual bound, as every deeper
4655 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Both deeper children were cutoff, so the %s branch is "
4667 branchingresult->deeperscore = (branchingresult->dualbound - baselpobjval) * (branchingresult->dualbound - baselpobjval) * 10;
4685 /* the current branching child is infeasible and we only branched on binary variables in lookahead branching */
4710 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
4713 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
4717 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
4722 SCIP_Longint* niterations, /**< pointer to store the total number of iterations for this variable; or NULL*/
4723 int* ndeepestcutoffs, /**< pointer to store the total number of cutoffs on the deepest level; or NULL */
4724 SCIP_Real* bestgain, /**< pointer to store the best gain found with these candidates; or NULL */
4725 SCIP_Real* totalgains, /**< pointer to store the sum over all gains that are valid in both children;
4809 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Started selectVarRecursive with <%i> candidates: ", nlpcands);
4815 /* iterate over all current branching candidates and evaluate their two potential child nodes by:
4818 * - potentially evaluating branching candidates at the potential child node again by applying this method recursively
4821 * - results obtained for a candidate in a previous lookahead branching call at this node may be re-used
4822 * - while i counts the number of candidates evaluated in this call, we do not always start at the front
4823 * of the candidate array, but rather store at which index we stopped last time (e.g., because a domain reduction was
4824 * found and applied) and start from that index next time. Even though the set of branching candidates is probably different
4857 * this may happen if domain propagation on other candidates finds better bounds for the current candidate
4863 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Domain Propagation changed the bounds of a branching candidate."
4871 /* Reset the cutoffproofnodes, as the number of proof nodes from previous branching vars (which where not
4881 if( persistent != NULL && (config->inscoring || probingdepth == 0) && isUseOldBranching(scip, persistent, config, branchvar) )
4883 SCIP_CALL( getOldBranching(scip, persistent, config, branchvar, downbranchingresult, upbranchingresult,
4898 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, "Started branching on var <%s> with val <%g> and bounds "
4922 SCIP_CALL( executeBranchingRecursive(scip, status, config, baselpsol, candidate, lpobjval, baselpobjval,
4923 recursiondepth, localdomainreductions, binconsdata, level2data, localbranchingresult, scorecontainer,
4927 SCIP_CALL( executeBranchingRecursive(scip, status, config, baselpsol, candidate, lpobjval, baselpobjval,
4928 recursiondepth, localdomainreductions, binconsdata, level2data, localbranchingresult, scorecontainer,
4950 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, "-> down=%.9g (gain=%.9g, valid=%u, inf=%u), up=%.9g "
4953 downbranchingresult->cutoff, upbranchingresult->dualbound, upbranchingresult->dualbound - lpobjval,
4960 if( persistent != NULL && !upbranchingresult->cutoff && !downbranchingresult->cutoff && (config->inscoring || probingdepth == 0) )
4962 SCIP_CALL( updateOldBranching(scip, persistent, config, branchvar, branchval, downbranchingresult,
4976 SCIP_Real score = calculateScore(scip, config, branchvar, downbranchingresult, upbranchingresult,
4984 if( bestgain != NULL && !config->inscoring && SCIPgetProbingDepth(scip) == 1 && !useoldbranching )
5001 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, " -> variable <%s> is infeasible in both directions\n",
5014 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, " -> variable <%s> is infeasible in upward branch\n",
5017 /* apply down branching bound change at current node if we proved that this node is really infeasible and
5044 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, " -> variable <%s> is infeasible in downward branch\n",
5047 /* apply up branching bound change at current node if we proved that this node is really infeasible and
5074 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Neither branch is cut off and no limit reached.\n");
5094 if( !upbranchingresult->cutoff && !downbranchingresult->cutoff && config->mergedomainreductions )
5095 applyDeeperDomainReductions(scip, baselpsol, maxstoredomreds, domainreductions, downdomainreductions,
5098 applySingleDeeperDomainReductions(scip, baselpsol, maxstoredomreds, domainreductions, downdomainreductions);
5100 applySingleDeeperDomainReductions(scip, baselpsol, maxstoredomreds, domainreductions, updomainreductions);
5109 bestdownbranchingresult->dualbound = MAX(bestdownbranchingresult->dualbound, decision->proveddb);
5112 newscore = calculateScore(scip, config, decision->branchvar, bestdownbranchingresult, bestupbranchingresult,
5129 /* the current candidate variable has a better score than the best candidate investigated so far */
5134 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Old best var <%s> with bounds [<%g>..<%g>] and score %.9g\n",
5177 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "New best var <%s> with bounds [<%g>..<%g>] and score %.9g\n",
5182 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, " -> cand %d/%d var <%s> (solval=%.9g, downgain=%.9g->%.9g, upgain=%.9g->%.9g,"
5184 MAX(downbranchingresult->objval - scoringlpobjval, 0), MAX(downbranchingresult->dualbound - scoringlpobjval, 0),
5185 MAX(upbranchingresult->objval - scoringlpobjval, 0), MAX(upbranchingresult->dualbound - scoringlpobjval, 0),
5192 /* only for abbreviated lookahead branching: we are in the FSB filtering step and store the score for this
5193 * variable and the warm starting basis to reuse it in the subsequent lookahead evaluation of the best
5197 downbranchingresult->dualbound - scoringlpobjval, upbranchingresult->dualbound - scoringlpobjval) );
5201 && (config->maxnviolatedcons >= 0 || config->maxnviolatedbincons >= 0 || config->maxnviolateddomreds >= 0 ) )
5210 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Found %d binary constraints (%d violated by the LP solution)\n",
5215 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The max number of violated binary constraints <%i> is "
5228 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Found %d bound changes (%d violated by the LP solution)\n",
5241 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The max number of violated binary constraints and bound "
5248 if( !(status->domred && decision->branchvar == candidate->branchvar) && areBoundsChanged(scip, decision->branchvar, bestscorelowerbound, bestscoreupperbound) )
5250 /* in case the bounds of the current highest scored solution have changed due to domain propagation during
5251 * the lookahead branching we can/should not branch on this variable but instead report the domain
5257 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Domain Propagation changed the bounds of a branching candidate."
5285 /** checks whether the current decision should be stored. This is the case if we found domain reductions
5287 * Then our current decision still holds true for the next call and can be reused without further calculations
5293 DOMAINREDUCTIONS* domainreductions /**< container collecting all domain reductions found; or NULL */