Scippy

    SCIP

    Solving Constraint Integer Programs

    branch_lookahead.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file branch_lookahead.c
    26 * @ingroup DEFPLUGINS_BRANCH
    27 * @ingroup BRANCHINGRULES
    28 * @brief lookahead LP branching rule
    29 * @author Christoph Schubert
    30 * @author Gerald Gamrath
    31 *
    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
    34 * strong branching. The rule selects the candidate with the best proven dual bound.
    35 *
    36 * The branching rule was motivated by the following technical report:
    37 *
    38 * @par
    39 * Wasu Glankwamdee and Jeff Linderoth@n
    40 * Lookahead Branching for Mixed Integer Programming@n
    41 * Technical Report 06T-004, Department of Industrial and Systems Engineering, Lehigh University.
    42 *
    43 * For a more mathematical description and a comparison between lookahead branching and other branching rules
    44 * in SCIP, we refer to
    45 *
    46 * @par
    47 * Christoph Schubert@n
    48 * Multi-Level Lookahead Branching@n
    49 * Master Thesis, Technische Universität Berlin, 2017@n
    50 */
    51
    52/* Supported defines:
    53 * PRINTNODECONS: prints the binary constraints added
    54 * SCIP_DEBUG: prints detailed execution information
    55 * SCIP_STATISTIC: prints some statistics after the branching rule is freed */
    56
    57/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    58
    60#include "lpi/lpi.h"
    62#include "scip/cons_logicor.h"
    63#include "scip/pub_branch.h"
    64#include "scip/pub_message.h"
    65#include "scip/pub_misc.h"
    66#include "scip/pub_tree.h"
    67#include "scip/pub_var.h"
    68#include "scip/scip_branch.h"
    69#include "scip/scip_cons.h"
    70#include "scip/scip_exact.h"
    71#include "scip/scip_general.h"
    72#include "scip/scip_lp.h"
    73#include "scip/scip_mem.h"
    74#include "scip/scip_message.h"
    75#include "scip/scip_numerics.h"
    76#include "scip/scip_param.h"
    77#include "scip/scip_prob.h"
    78#include "scip/scip_probing.h"
    79#include "scip/scip_sol.h"
    81#include "scip/scip_tree.h"
    82#include "scip/scip_var.h"
    83#include <string.h>
    84
    85#define BRANCHRULE_NAME "lookahead"
    86#define BRANCHRULE_DESC "full strong branching over multiple levels"
    87#define BRANCHRULE_PRIORITY 0
    88#define BRANCHRULE_MAXDEPTH -1
    89#define BRANCHRULE_MAXBOUNDDIST 1.0
    90
    91#define DEFAULT_USEBINARYCONSTRAINTS FALSE /**< should binary constraints be collected and applied? */
    92#define DEFAULT_ADDCLIQUE FALSE /**< add binary constraints with two variables found at the root node also as a clique? */
    93#define DEFAULT_ADDBINCONSROW 0 /**< should binary constraints be added as rows to the base LP?
    94 * (0: no, 1: separate, 2: as initial rows) */
    95#define DEFAULT_USEDOMAINREDUCTION TRUE /**< Should domain reductions be collected and applied? */
    96#define DEFAULT_MERGEDOMAINREDUCTIONS FALSE /**< should domain reductions of feasible siblings should be merged? */
    97#define DEFAULT_PREFERSIMPLEBOUNDS FALSE /**< should domain reductions only be applied if there are simple bound changes? */
    98#define DEFAULT_ONLYVIOLDOMREDS FALSE /**< Should only domain reductions that violate the LP solution be applied? */
    99#define DEFAULT_MAXNVIOLATEDCONS 1 /**< How many constraints that are violated by the base lp solution
    100 * should be gathered until the rule is stopped and they are added? */
    101#define DEFAULT_MAXNVIOLATEDBINCONS 0 /**< How many binary constraints that are violated by the base lp
    102 * solution should be gathered until the rule is stopped and they are
    103 * added? */
    104#define DEFAULT_MAXNVIOLATEDDOMREDS 1 /**< How many domain reductions that are violated by the base lp solution
    105 * should be gathered until the rule is stopped and they are added? */
    106#define DEFAULT_STOREUNVIOLATEDSOL TRUE /**< If only non violating constraints are added, should the branching
    107 * decision be stored till the next call? */
    108#define DEFAULT_REEVALAGE 10LL /**< Max number of LPs solved after which a previous prob branching
    109 * result is recalculated. */
    110#define DEFAULT_REEVALAGEFSB 10LL /**< Max number of LPs solved after which a previous FSB scoring
    111 * result is recalculated. */
    112#define DEFAULT_RECURSIONDEPTH 2 /**< The max depth of LAB. */
    113#define DEFAULT_ADDNONVIOCONS FALSE /**< Should binary constraints, that are not violated by the base LP, be
    114 * collected and added? */
    115#define DEFAULT_PROPAGATE TRUE /**< Should domain propagation be executed before each temporary node is
    116 * solved? */
    117#define DEFAULT_USELEVEL2DATA TRUE /**< should branching data generated at depth level 2 be stored for re-using it? */
    118#define DEFAULT_APPLYCHILDBOUNDS FALSE /**< should bounds known for child nodes be applied? */
    119#define DEFAULT_ENFORCEMAXDOMREDS FALSE /**< should the maximum number of domain reductions maxnviolateddomreds be enforced? */
    120#define DEFAULT_UPDATEBRANCHINGRESULTS FALSE /**< should branching results (and scores) be updated w.r.t. proven dual bounds? */
    121#define DEFAULT_MAXPROPROUNDS 0 /**< maximum number of propagation rounds to perform at temporary
    122 * nodes (-1: unlimited, 0: SCIP default) */
    123#define DEFAULT_ABBREVIATED TRUE /**< Toggles the abbreviated LAB. */
    124#define DEFAULT_MAXNCANDS 4 /**< If abbreviated: The max number of candidates to consider at the base node */
    125#define DEFAULT_MAXNDEEPERCANDS 2 /**< If abbreviated: The max number of candidates to consider per deeper node
    126 * (0: same as base node) */
    127#define DEFAULT_REUSEBASIS TRUE /**< If abbreviated: Should the information gathered to obtain the best
    128 * candidates be reused? */
    129#define DEFAULT_ABBREVPSEUDO FALSE /**< If abbreviated: Use pseudo costs to estimate the score of a
    130 * candidate. */
    131#define DEFAULT_LEVEL2AVGSCORE FALSE /**< should the average score be used for uninitialized scores in level 2? */
    132#define DEFAULT_LEVEL2ZEROSCORE FALSE /**< should uninitialized scores be set to 0? */
    133#define DEFAULT_SCORINGFUNCTION 'a' /**< scoring function to be used at the base level */
    134#define DEFAULT_DEEPERSCORINGFUNCTION 'x' /**< scoring function to be used at deeper levels */
    135#define DEFAULT_SCORINGSCORINGFUNCTION 'd' /**< scoring function to be used for FSB scoring */
    136#define DEFAULT_MINWEIGHT 0.8 /**< default value for the weight of the minimum in the convex combination of two
    137 * child gains (taken from the paper) */
    138#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) */
    139#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? */
    140
    141#ifdef SCIP_DEBUG
    142/* Adjusted debug message that also prints the current probing depth. */
    143#define LABdebugMessage(scip,lvl,...) do \
    144 { \
    145 SCIP_STAGE stage; \
    146 SCIPverbMessage(scip, lvl, NULL, "[%s:%-4d] ", __FILE__, __LINE__); \
    147 stage = SCIPgetStage(scip); \
    148 if( stage == SCIP_STAGE_INIT ) \
    149 { \
    150 SCIPverbMessage(scip, lvl, NULL, "Init : "); \
    151 } \
    152 else if( stage == SCIP_STAGE_FREE ) \
    153 { \
    154 SCIPverbMessage(scip, lvl, NULL, "Free : "); \
    155 } \
    156 else if( SCIPinProbing(scip) ) \
    157 { \
    158 SCIPverbMessage(scip, lvl, NULL, "%*sDepth %i: ", \
    159 2 * SCIPgetProbingDepth(scip), "", SCIPgetProbingDepth(scip)); \
    160 } \
    161 else \
    162 { \
    163 SCIPverbMessage(scip, lvl, NULL, "Base : "); \
    164 } \
    165 SCIPverbMessage(scip, lvl, NULL, __VA_ARGS__); \
    166 } \
    167 while( FALSE )
    168
    169/* Writes a debug message without the leading information. Can be used to append something to an output of LABdebugMessage*/
    170#define LABdebugMessagePrint(scip,lvl,...) do \
    171 { \
    172 SCIPverbMessage(scip, lvl, NULL, __VA_ARGS__); \
    173 } \
    174 while( FALSE )
    175#else
    176#define LABdebugMessage(scip,lvl,...) /**/
    177/*#define LABdebugMessagePrint(scip,lvl,...) only used with SCIP_DEBUG defined */
    178#endif
    179
    180/*
    181 * Data structures
    182 */
    183
    184/** A struct holding information to speed up the solving time for solving a problem again. This is filled by the FSB
    185 * scoring routine that is run to get the best candidates. It is then read by the actual ALAB routine. */
    186typedef struct
    187{
    188 SCIP_LPISTATE* lpistate; /**< the basis information that may be set before another solve lp call */
    189 SCIP_LPINORMS* lpinorms; /**< the norms that may be set before another solve lp call */
    190 SCIP_Bool primalfeas; /**< indicates whether the solution was primal feasible */
    191 SCIP_Bool dualfeas; /**< indicates whether the solution was dual feasible */
    193
    194/** Allocates the warm start information on the buffer and initializes it with default values. */
    195static
    197 SCIP* scip, /**< SCIP data structure */
    198 WARMSTARTINFO** warmstartinfo /**< the warmstartinfo to allocate and initialize */
    199 )
    200{
    201 assert(scip != NULL);
    202 assert(warmstartinfo != NULL);
    203
    204 SCIP_CALL( SCIPallocBlockMemory(scip, warmstartinfo) );
    205
    206 (*warmstartinfo)->lpistate = NULL;
    207 (*warmstartinfo)->lpinorms = NULL;
    208 (*warmstartinfo)->primalfeas = FALSE;
    209 (*warmstartinfo)->dualfeas = FALSE;
    210
    211 return SCIP_OKAY;
    212}
    213
    214/** checks that the warm start info can be read into the lp solver. */
    215static
    217 WARMSTARTINFO* warmstartinfo /**< the warm start info to check (may be NULL) */
    218 )
    219{
    220 return warmstartinfo != NULL && warmstartinfo->lpistate != NULL;
    221}
    222
    223/** Frees the allocated buffer memory of the warm start info. */
    224static
    226 SCIP* scip, /**< SCIP data structure */
    227 WARMSTARTINFO** warmstartinfo /**< the warm start info to free */
    228 )
    229{
    230 SCIP_LPI* lpi;
    231 BMS_BLKMEM* blkmem;
    232
    233 assert(scip != NULL);
    234 assert(warmstartinfo != NULL);
    235
    236 SCIP_CALL( SCIPgetLPI(scip, &lpi) );
    237 blkmem = SCIPblkmem(scip);
    238
    239 if( (*warmstartinfo)->lpistate != NULL )
    240 {
    241 SCIP_CALL( SCIPlpiFreeState(lpi, blkmem, &(*warmstartinfo)->lpistate) );
    242 }
    243
    244 if( (*warmstartinfo)->lpinorms != NULL )
    245 {
    246 SCIP_CALL( SCIPlpiFreeNorms(lpi, blkmem, &(*warmstartinfo)->lpinorms) );
    247 }
    248
    249 SCIPfreeBlockMemory(scip, warmstartinfo);
    250
    251 return SCIP_OKAY;
    252}
    253
    254/** A struct containing all information needed to branch on a variable. */
    255typedef struct
    256{
    257 SCIP_VAR* branchvar; /**< the variable to branch on */
    258 SCIP_Real branchval; /**< the fractional value to branch on */
    259 SCIP_Real fracval; /**< the fractional part of the value to branch on (val - floor(val)) */
    260 WARMSTARTINFO* downwarmstartinfo; /**< the warm start info containing the lp data from a previous down branch */
    261 WARMSTARTINFO* upwarmstartinfo; /**< the warm start info containing the lp data from a previous up branch */
    262} CANDIDATE;
    263
    264/** Allocates the candidate on the buffer and initializes it with default values. */
    265static
    267 SCIP* scip, /**< SCIP data structure */
    268 CANDIDATE** candidate /**< the candidate to allocate and initialize */
    269 )
    270{
    271 assert(scip != NULL);
    272 assert(candidate != NULL);
    273
    274 SCIP_CALL( SCIPallocBlockMemory(scip, candidate) );
    275
    276 (*candidate)->downwarmstartinfo = NULL;
    277 (*candidate)->upwarmstartinfo = NULL;
    278 (*candidate)->branchvar = NULL;
    279
    280 return SCIP_OKAY;
    281}
    282
    283/** free the warm starting information for the given candidate */
    284static
    286 SCIP* scip, /**< SCIP data structure */
    287 CANDIDATE* candidate /**< the candidate to free the warm starting information for */
    288 )
    289{
    290 assert(scip != NULL);
    291 assert(candidate != NULL);
    292
    293 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "freeing warmstart info of candidate <%s>(%u/%u)...\n",
    294 SCIPvarGetName(candidate->branchvar),
    295 candidate->upwarmstartinfo != NULL, candidate->downwarmstartinfo != NULL);
    296
    297 if( candidate->upwarmstartinfo != NULL )
    298 {
    300 }
    301 if( candidate->downwarmstartinfo != NULL )
    302 {
    304 }
    305
    306 return SCIP_OKAY;
    307}
    308
    309
    310/** Frees the allocated buffer memory of the candidate and clears the contained lpi memories. */
    311static
    313 SCIP* scip, /**< SCIP data structure */
    314 CANDIDATE** candidate /**< the candidate to free */
    315 )
    316{
    317 assert(scip != NULL);
    318 assert(candidate != NULL);
    319
    320 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "freeing candidate <%s>(%u/%u)...\n",
    321 (*candidate) != NULL ? SCIPvarGetName((*candidate)->branchvar) : "none",
    322 (*candidate)->upwarmstartinfo != NULL, (*candidate)->downwarmstartinfo != NULL);
    323
    324 /* if a candidate is freed, we no longer need the content of the warm start info */
    326
    327 SCIPfreeBlockMemory(scip, candidate);
    328 return SCIP_OKAY;
    329}
    330
    331/** Store the current lp solution in the warm start info for further usage. */
    332static
    334 SCIP* scip, /**< SCIP data structure */
    335 CANDIDATE* candidate, /**< the branching candidate */
    336 SCIP_Bool down /**< is the info for down branching? */
    337 )
    338{
    339 SCIP_LPI* lpi;
    340 BMS_BLKMEM* blkmem;
    341 WARMSTARTINFO* warmstartinfo;
    342
    343 assert(scip != NULL);
    344 assert(candidate != NULL);
    345
    346 SCIP_CALL( SCIPgetLPI(scip, &lpi) );
    347 blkmem = SCIPblkmem(scip);
    348
    349 if( down )
    350 {
    351 if( candidate->downwarmstartinfo == NULL )
    352 {
    354 }
    355 warmstartinfo = candidate->downwarmstartinfo;
    356 }
    357 else
    358 {
    359 if( candidate->upwarmstartinfo == NULL )
    360 {
    362 }
    363 warmstartinfo = candidate->upwarmstartinfo;
    364 }
    365
    366 SCIP_CALL( SCIPlpiGetState(lpi, blkmem, &warmstartinfo->lpistate) );
    367
    368 SCIP_CALL( SCIPlpiGetNorms(lpi, blkmem, &warmstartinfo->lpinorms) );
    369
    370 warmstartinfo->primalfeas = SCIPlpiIsPrimalFeasible(lpi);
    371 warmstartinfo->dualfeas = SCIPlpiIsDualFeasible(lpi);
    372
    373 assert(warmstartinfo->lpistate != NULL);
    374 /* warmstartinfo->lpinorms may be NULL */
    375
    376 return SCIP_OKAY;
    377}
    378
    379/** returns whether the candidate has stored warm starting information for the given direction */
    380static
    382 CANDIDATE* candidate, /**< the branching candidate */
    383 SCIP_Bool down /**< is the info for down branching? */
    384 )
    385{
    386 assert(candidate != NULL);
    387
    388 return warmStartInfoIsAvailable(down ? candidate->downwarmstartinfo : candidate->upwarmstartinfo);
    389}
    390
    391
    392/** loads the warm starting information of the candidate for the given direction */
    393static
    395 SCIP* scip, /**< SCIP data structure */
    396 CANDIDATE* candidate, /**< the branching candidate */
    397 SCIP_Bool down /**< is the info for down branching? */
    398 )
    399{
    400 WARMSTARTINFO* warmstartinfo;
    401
    402 assert(scip != NULL);
    403 assert(candidate != NULL);
    404
    405 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "loading basis...\n");
    406
    407 if( down )
    408 warmstartinfo = candidate->downwarmstartinfo;
    409 else
    410 warmstartinfo = candidate->upwarmstartinfo;
    411
    412 /* 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 * the LP solver, such that the solution does not (in best case) need any further calculation.
    414 * Some iterations may occur, as the conflict analysis may have added some constraints in the meantime. */
    415 SCIP_CALL( SCIPsetProbingLPState(scip, &(warmstartinfo->lpistate), &(warmstartinfo->lpinorms), warmstartinfo->primalfeas,
    416 warmstartinfo->dualfeas) );
    417
    418 /* The state and norms will be freed later by the SCIP framework. Therefore they are set to NULL to enforce that we won't
    419 * free them on our own. */
    420 assert(warmstartinfo->lpistate == NULL);
    421 assert(warmstartinfo->lpinorms == NULL);
    422
    423 return SCIP_OKAY;
    424}
    425
    426
    427/** Holds the information needed for branching on a variable. */
    428typedef struct
    429{
    430 SCIP_VAR* branchvar; /**< the variable to branch on, may be NULL */
    431 SCIP_Real branchval; /**< the fractional value to branch on */
    432 SCIP_Real* downlowerbounds; /**< variable lower bounds for down child */
    433 SCIP_Real* downupperbounds; /**< variable upper bounds for down child */
    434 SCIP_Real* uplowerbounds; /**< variable lower bounds for up child */
    435 SCIP_Real* upupperbounds; /**< variable upper bounds for up child */
    436 SCIP_Real downdb; /**< dual bound for down branch */
    437 SCIP_Real updb; /**< dual bound for the up branch */
    438 SCIP_Real proveddb; /**< proven dual bound for the current node */
    439 SCIP_Real score; /**< score of the branching decision */
    440 SCIP_Bool downdbvalid; /**< Indicator for the validity of the downdb value. Is FALSE, if no actual
    441 * branching occurred or the value was determined by an LP not solved to
    442 * optimality. */
    443 SCIP_Bool updbvalid; /**< Indicator for the validity of the updb value. Is FALSE, if no actual
    444 * branching occurred or the value was determined by an LP not solved to
    445 * optimality. */
    446 SCIP_Bool boundsvalid; /**< are variable bounds for down and up child valid? */
    447 int boundssize; /**< size of bounds arrays */
    449
    450/** initialize a branching decsion with default values */
    451static
    453 SCIP* scip, /**< SCIP data structure */
    454 BRANCHINGDECISION* decision /**< the decision to initialize */
    455 )
    456{
    457 assert(scip != NULL);
    458 assert(decision != NULL);
    459
    460 decision->branchvar = NULL;
    461 decision->branchval = SCIP_INVALID;
    462 decision->downlowerbounds = NULL;
    463 decision->downupperbounds = NULL;
    464 decision->uplowerbounds = NULL;
    465 decision->upupperbounds = NULL;
    466 decision->downdb = -SCIPinfinity(scip);
    467 decision->downdbvalid = FALSE;
    468 decision->updb = -SCIPinfinity(scip);
    469 decision->updbvalid = FALSE;
    470 decision->boundsvalid = FALSE;
    471 decision->proveddb = -SCIPinfinity(scip);
    472 decision->score = -SCIPinfinity(scip);
    473 decision->boundssize = 0;
    474}
    475
    476
    477/** allocates a branching decision in the buffer and initializes it with default values. */
    478static
    480 SCIP* scip, /**< SCIP data structure */
    481 BRANCHINGDECISION** decision /**< pointer to the decision to allocate and initialize */
    482 )
    483{
    484 assert(scip != NULL);
    485 assert(decision != NULL);
    486
    487 SCIP_CALL( SCIPallocBuffer(scip, decision) );
    488
    489 branchingDecisionInit(scip, *decision);
    490
    491 return SCIP_OKAY;
    492}
    493
    494/** copies the data from the source branching decision storage to the target storage;
    495 * this is used to store the most important information (i.e., the dual bounds obtained) so that it can be used in a
    496 * subsequent call in case the LP solution did not change because we only added bound changes that did not forbid the
    497 * current LP solution;
    498 * however, we do not want to store all the domain changes for the two potential child nodes for this rare case, they
    499 * will be identified when processing the child nodes anyway
    500 */
    501static
    503 BRANCHINGDECISION* sourcedecision, /**< the source branching decision */
    504 BRANCHINGDECISION* targetdecision /**< the target branching decision */
    505 )
    506{
    507 assert(sourcedecision != NULL);
    508 assert(targetdecision != NULL);
    509
    510 targetdecision->branchvar = sourcedecision->branchvar;
    511 targetdecision->branchval = sourcedecision->branchval;
    512 targetdecision->downdb = sourcedecision->downdb;
    513 targetdecision->downdbvalid = sourcedecision->downdbvalid;
    514 targetdecision->updb = sourcedecision->updb;
    515 targetdecision->updbvalid = sourcedecision->updbvalid;
    516 targetdecision->proveddb = sourcedecision->proveddb;
    517 targetdecision->score = sourcedecision->score;
    518
    519 assert(targetdecision->downlowerbounds == NULL);
    520 assert(targetdecision->downupperbounds == NULL);
    521 assert(targetdecision->uplowerbounds == NULL);
    522 assert(targetdecision->upupperbounds == NULL);
    523 assert(targetdecision->boundsvalid == FALSE);
    524 assert(targetdecision->boundssize == 0);
    525}
    526
    527/** Checks whether the given branching decision can be used to branch on. */
    528static
    530 BRANCHINGDECISION* decision /**< the branching decision to check */
    531 )
    532{
    533 assert(decision != NULL);
    534
    535 /* a branching decision is deemed valid, if the var pointer is not on the default NULL value (see the allocate method) */
    536 return decision->branchvar != NULL;
    537}
    538
    539/* ensure that the array that stores the bounds for both child nodes is large enough */
    540static
    542 SCIP* scip, /**< SCIP data structure */
    543 BRANCHINGDECISION* decision, /**< branching decision */
    544 int nvars /**< number of problem variables */
    545 )
    546{
    547 assert(decision != NULL);
    548
    549 if( decision->boundssize == 0 )
    550 {
    551 decision->boundssize = nvars;
    556 }
    557 assert(decision->boundssize == nvars);
    558
    559 return SCIP_OKAY;
    560}
    561
    562/** Frees the allocated memory of the branching decision. */
    563static
    565 SCIP* scip, /**< SCIP data structure */
    566 BRANCHINGDECISION** decision /**< pointer to the decision to be freed */
    567 )
    568{
    569 assert(scip != NULL);
    570 assert(decision != NULL);
    571
    572 if( (*decision)->boundssize != 0 )
    573 {
    574 assert((*decision)->downlowerbounds != NULL);
    575 assert((*decision)->downupperbounds != NULL);
    576 assert((*decision)->uplowerbounds != NULL);
    577 assert((*decision)->upupperbounds != NULL);
    578
    579 SCIPfreeBlockMemoryArray(scip, &(*decision)->downlowerbounds, (*decision)->boundssize);
    580 SCIPfreeBlockMemoryArray(scip, &(*decision)->downupperbounds, (*decision)->boundssize);
    581 SCIPfreeBlockMemoryArray(scip, &(*decision)->uplowerbounds, (*decision)->boundssize);
    582 SCIPfreeBlockMemoryArray(scip, &(*decision)->upupperbounds, (*decision)->boundssize);
    583 }
    584
    585 SCIPfreeBuffer(scip, decision);
    586}
    587
    588/** A container to hold the result of a branching. */
    589typedef struct
    590{
    591 SCIP_Real objval; /**< The objective value of the solved lp. Only contains meaningful data, if
    592 * cutoff == FALSE. */
    593 SCIP_Real dualbound; /**< The best dual bound for this branching, may be changed by deeper level
    594 * branchings. */
    595 SCIP_Longint niterations; /**< The number of probing iterations needed in sub branch. */
    596 SCIP_Bool cutoff; /**< Indicates whether the node was infeasible and was cutoff. */
    597 SCIP_Bool dualboundvalid; /**< Is the value of the dual bound valid? That means, was the according LP
    598 * or the sub problems solved to optimality? */
    599 int ndeepestcutoffs; /**< number of cutoffs on the lowest level below this child */
    600 SCIP_Real deeperscore; /**< best score computed for the deeper lookahead level */
    601 SCIP_Real bestgain; /**< best gain (w.r.t. to the base lp) on the lowest level below this child */
    602 SCIP_Real totalgains; /**< sum over all gains that are valid in both children */
    603 int ntotalgains; /**< number of gains summed in totalgains */
    604 int ndeepestnodes; /**< number of nodes processed in the deepest level */
    606
    607/** Allocates a branching result in the buffer. */
    608static
    610 SCIP* scip, /**< SCIP data structure */
    611 BRANCHINGRESULTDATA** resultdata /**< pointer to the result to be allocated */
    612 )
    613{
    614 assert(scip != NULL);
    615 assert(resultdata != NULL);
    616
    617 SCIP_CALL( SCIPallocBuffer(scip, resultdata) );
    618
    619 return SCIP_OKAY;
    620}
    621
    622/** Initiates the branching result with default values. */
    623static
    625 SCIP* scip, /**< SCIP data structure */
    626 BRANCHINGRESULTDATA* resultdata /**< pointer to the result to be initialized */
    627 )
    628{
    629 assert(scip != NULL);
    630 assert(resultdata != NULL);
    631
    632 resultdata->objval = -SCIPinfinity(scip);
    633 resultdata->dualbound = -SCIPinfinity(scip);
    634 resultdata->cutoff = FALSE;
    635 resultdata->dualboundvalid = FALSE;
    636 resultdata->niterations = 0;
    637 resultdata->ndeepestcutoffs = 0;
    638 resultdata->deeperscore = -SCIPinfinity(scip);
    639 resultdata->bestgain = 0.;
    640 resultdata->totalgains = 0.;
    641 resultdata->ntotalgains = 0;
    642 resultdata->ndeepestnodes = 0;
    643}
    644
    645/** Copies the data from the source to the target. */
    646static
    648 BRANCHINGRESULTDATA* sourcedata, /**< the source branching result */
    649 BRANCHINGRESULTDATA* targetdata /**< the target branching result */
    650 )
    651{
    652 assert(sourcedata != NULL);
    653 assert(targetdata != NULL);
    654
    655 targetdata->cutoff = sourcedata->cutoff;
    656 targetdata->objval = sourcedata->objval;
    657 targetdata->dualbound = sourcedata->dualbound;
    658 targetdata->dualboundvalid = sourcedata->dualboundvalid;
    659 targetdata->niterations = sourcedata->niterations;
    660 targetdata->ndeepestcutoffs = sourcedata->ndeepestcutoffs;
    661 targetdata->deeperscore = sourcedata->deeperscore;
    662 targetdata->bestgain = sourcedata->bestgain;
    663 targetdata->totalgains = sourcedata->totalgains;
    664 targetdata->ntotalgains = sourcedata->ntotalgains;
    665 targetdata->ndeepestnodes = sourcedata->ndeepestnodes;
    666}
    667
    668/** Frees the allocated buffer memory of the branching result. */
    669static
    671 SCIP* scip, /**< SCIP data structure */
    672 BRANCHINGRESULTDATA** resultdata /**< pointer to the result to be freed */
    673 )
    674{
    675 assert(scip != NULL);
    676 assert(resultdata != NULL);
    677
    678 SCIPfreeBuffer(scip, resultdata);
    679}
    680
    681/** a container to hold the result of a second-level LP */
    682typedef struct
    683{
    684 SCIP_Real lpobjval; /**< the objective value of the solved lp; only contains meaningful data, if
    685 * cutoff == FALSE. */
    686 SCIP_Real branchval1; /**< new bound for first branching variable */
    687 SCIP_Real branchval2; /**< new bound for second branching variable */
    688 unsigned int branchvar1:30; /**< problem index of first branching variable */
    689 unsigned int branchvar2:30; /**< problem index of second branching variable */
    690 unsigned int branchdir1:1; /**< branching direction for first branching variable (0:down, 1:up) */
    691 unsigned int branchdir2:1; /**< branching direction for second branching variable (0:down, 1:up) */
    692 unsigned int cutoff:1; /**< indicates whether the node was infeasible and was cut off. */
    693 unsigned int valid:1; /**< is the lpobjval a valid dual bound? */
    695
    696/** a container to hold the results of all second-level LPs */
    697typedef struct
    698{
    699 LEVEL2RESULT** level2results; /**< array with all level2 results */
    700 SCIP_Real branchval1; /**< new bound for first branching variable */
    701 SCIP_Real branchval2; /**< new bound for second branching variable */
    702 int nlevel2results; /**< number of level2 results stored */
    703 int level2resultssize; /**< size of level2results array */
    704 unsigned int branchvar1:30; /**< problem index of first branching variable */
    705 unsigned int branchvar2:30; /**< problem index of second branching variable */
    706 unsigned int branchdir1:1; /**< branching direction for first branching variable (0:down, 1:up) */
    707 unsigned int branchdir2:1; /**< branching direction for second branching variable (0:down, 1:up) */
    708} LEVEL2DATA;
    709
    710/** allocates a double branching result in the memory and fills it with the information stored in the level 2 data */
    711static
    713 SCIP* scip, /**< SCIP data structure */
    714 LEVEL2DATA* data, /**< level2 data */
    715 LEVEL2RESULT** result /**< pointer to the result to be allocated */
    716 )
    717{
    718 assert(scip != NULL);
    719 assert(data != NULL);
    720 assert(result != NULL);
    721
    723
    724 if( data->branchvar1 < data->branchvar2 )
    725 {
    726 (*result)->branchval1 = data->branchval1;
    727 (*result)->branchval2 = data->branchval2;
    728 (*result)->branchvar1 = data->branchvar1; /*lint !e732*/
    729 (*result)->branchvar2 = data->branchvar2; /*lint !e732*/
    730 (*result)->branchdir1 = data->branchdir1;
    731 (*result)->branchdir2 = data->branchdir2;
    732 }
    733 else
    734 {
    735 (*result)->branchval1 = data->branchval2;
    736 (*result)->branchval2 = data->branchval1;
    737 (*result)->branchvar1 = data->branchvar2; /*lint !e732*/
    738 (*result)->branchvar2 = data->branchvar1; /*lint !e732*/
    739 (*result)->branchdir1 = data->branchdir2;
    740 (*result)->branchdir2 = data->branchdir1;
    741 }
    742
    743 return SCIP_OKAY;
    744}
    745
    746
    747#ifdef SCIP_DEBUG
    748/** prints the double branching result */
    749static
    751 SCIP* scip, /**< SCIP data structure */
    752 LEVEL2RESULT* result /**< pointer to the result to be initialized */
    753 )
    754{
    755 SCIP_VAR** vars;
    756
    757 assert(result != NULL);
    758
    759 vars = SCIPgetVars(scip);
    760
    762 "level 2 result: <%s> %s %g + <%s> %s %g: lpval: %.9g, inf: %d, valid: %d\n",
    763 SCIPvarGetName(vars[result->branchvar1]), result->branchdir1 ? ">=" : "<=", result->branchval1,
    764 SCIPvarGetName(vars[result->branchvar2]), result->branchdir2 ? ">=" : "<=", result->branchval2,
    765 result->lpobjval, result->cutoff, result->valid);
    766}
    767#else
    768#define level2resultPrint(scip,result) /**/
    769#endif
    770
    771/** frees the allocated memory of the double branching result */
    772static
    774 SCIP* scip, /**< SCIP data structure */
    775 LEVEL2RESULT** result /**< pointer to the result to be freed */
    776 )
    777{
    778 assert(scip != NULL);
    779 assert(result != NULL);
    780
    781 SCIPfreeBlockMemory(scip, result);
    782}
    783
    784/** returns TRUE iff both level 2 results are equal; two branchings are equal if they branched on the same variables
    785 * with the same values
    786 */
    787static
    789 LEVEL2RESULT* result1, /**< first level 2 result */
    790 LEVEL2RESULT* result2 /**< second level 2 result */
    791 )
    792{
    793 assert(result1->branchvar1 < result1->branchvar2);
    794 assert(result2->branchvar1 < result2->branchvar2);
    795
    796 /* check all cases */
    797 if( result1->branchvar1 != result2->branchvar1
    798 || result1->branchvar2 != result2->branchvar2
    799 || result1->branchdir1 != result2->branchdir1
    800 || result1->branchdir2 != result2->branchdir2
    801 || result1->branchval1 > result2->branchval1 + 0.5
    802 || result1->branchval1 < result2->branchval1 - 0.5
    803 || result1->branchval2 > result2->branchval2 + 0.5
    804 || result1->branchval2 < result2->branchval2 - 0.5)
    805 return FALSE;
    806
    807 return TRUE;
    808}
    809
    810/** allocates the level2 data */
    811static
    813 SCIP* scip, /**< SCIP data structure */
    814 LEVEL2DATA** data /**< pointer to the data to be allocated */
    815 )
    816{
    817 assert(scip != NULL);
    818 assert(data != NULL);
    819
    821
    822 (*data)->level2results = NULL;
    823 (*data)->branchval1 = -SCIPinfinity(scip);
    824 (*data)->branchval2 = -SCIPinfinity(scip);
    825 (*data)->nlevel2results = 0;
    826 (*data)->level2resultssize = 0;
    827 (*data)->branchvar1 = 0;
    828 (*data)->branchvar2 = 0;
    829 (*data)->branchdir1 = 0;
    830 (*data)->branchdir2 = 0;
    831
    832 return SCIP_OKAY;
    833}
    834
    835/** frees the allocated memory of the level2 data */
    836static
    838 SCIP* scip, /**< SCIP data structure */
    839 LEVEL2DATA** data /**< pointer to the data to be freed */
    840 )
    841{
    842 assert(scip != NULL);
    843 assert(data != NULL);
    844
    845 while( (*data)->nlevel2results > 0 )
    846 {
    847 --(*data)->nlevel2results;
    848 level2resultFree(scip, &((*data)->level2results[(*data)->nlevel2results]));
    849 }
    850 assert((*data)->nlevel2results == 0);
    851
    852 if( (*data)->level2results != NULL )
    853 {
    854 SCIPfreeBlockMemoryArray(scip, &(*data)->level2results, (*data)->level2resultssize);
    855 }
    856
    858}
    859
    860/** ensures that level2results can store at least one more element */
    861static
    863 SCIP* scip, /**< SCIP data structure */
    864 LEVEL2DATA* data /**< level2 data */
    865 )
    866{
    867 assert(scip != NULL);
    868 assert(data != NULL);
    869
    870 if( data->nlevel2results >= data->level2resultssize )
    871 {
    872 int newsize = SCIPcalcMemGrowSize(scip, data->level2resultssize + 1);
    873
    875 data->level2resultssize = newsize;
    876 }
    877
    878 return SCIP_OKAY;
    879}
    880
    881/** get a result from the level 2 data */
    882static
    884 SCIP* scip, /**< SCIP data structure */
    885 LEVEL2DATA* data, /**< level2 data */
    886 LEVEL2RESULT** result /**< pointer to store result */
    887 )
    888{
    889 LEVEL2RESULT* tmpresult;
    890 int i;
    891
    892 assert(data != NULL);
    893 assert(result != NULL);
    894
    895 *result = NULL;
    896
    897 /* we branched twice on the same variable; the result cannot be stored already */
    898 if( data->branchvar1 == data->branchvar2 )
    899 {
    902 return SCIP_OKAY;
    903 }
    904
    905 SCIP_CALL( level2resultCreateFromData(scip, data, &tmpresult) );
    906
    907 /* search for a level 2 result with the same branching decisions */
    908 for( i = 0; i < data->nlevel2results; ++i )
    909 {
    910 if( level2resultEqual(data->level2results[i], tmpresult) )
    911 {
    912 *result = data->level2results[i];
    913 }
    914 }
    915
    916 level2resultFree(scip, &tmpresult);
    917
    918 return SCIP_OKAY;
    919}
    920
    921
    922/** store a new result in the level 2 data */
    923static
    925 SCIP* scip, /**< SCIP data structure */
    926 LEVEL2DATA* data, /**< level2 data */
    927 SCIP_Real lpobjval, /**< LP objective value */
    928 SCIP_Bool cutoff, /**< was the LP infeasible? */
    929 SCIP_Bool valid, /**< is the LP value a valid dual bound? */
    930 SCIP_Bool* duplicate /**< pointer to store whether information for the same branching decisions was already stored */
    931 )
    932{
    933 LEVEL2RESULT* result;
    934 int i;
    935
    936 assert(scip != NULL);
    937 assert(data != NULL);
    938 assert(duplicate != NULL);
    939
    940 *duplicate = FALSE;
    941
    942 /* we branched twice on the same variable; the result cannot be re-used lated */
    943 if( data->branchvar1 == data->branchvar2 )
    944 {
    947 return SCIP_OKAY;
    948 }
    949
    951
    952 SCIP_CALL( level2resultCreateFromData(scip, data, &result) );
    953
    954 result->lpobjval = lpobjval;
    955 result->cutoff = cutoff;
    956 result->valid = valid;
    957
    958 /* search for a level 2 result with the same branching decisions*/
    959 for( i = 0; i < data->nlevel2results; ++i )
    960 {
    961 if( level2resultEqual( data->level2results[i], result) )
    962 {
    963 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "same level2 node already processed:\n");
    965 level2resultPrint(scip, result);
    966 *duplicate = TRUE;
    967 }
    968 }
    969
    970 data->level2results[data->nlevel2results] = result;
    971 ++data->nlevel2results;
    972 assert(data->nlevel2results <= data->level2resultssize);
    973
    974 return SCIP_OKAY;
    975}
    976
    977
    978/** The data that is preserved over multiple runs of the branching rule. */
    979typedef struct
    980{
    981 BRANCHINGDECISION* olddecision; /**< The previous decision that gets used for the case that in the previous run
    982 * only non-violating implicit binary constraints were added.*/
    983 SCIP_Longint oldnnodelpiterations; /**< node LP iterations when previous branching decision was stored */
    984 SCIP_Longint oldnnodelps; /**< node LPs when previous branching decision was stored */
    985 SCIP_Longint oldntotalnodes; /**< node at which previous branching decision was stored */
    986 SCIP_Longint* lastbranchid; /**< The node id at which the var was last branched on (for a given branching
    987 * var). */
    988 SCIP_Longint* lastbranchnlps; /**< The number of (non-probing) LPs that where solved when the var was last
    989 * branched on. */
    990 SCIP_Real* lastbranchlpobjval; /**< The lp objval at which var was last branched on. */
    991 BRANCHINGRESULTDATA** lastbranchupres; /**< The result of the last up branching for a given var. */
    992 BRANCHINGRESULTDATA** lastbranchdownres; /**< The result of the last down branching for a given var. */
    993 int restartindex; /**< The index at which the iteration over the number of candidates starts. */
    994 int nvars; /**< The number of variables that can be stored in the arrays. */
    996
    997/** The parameter that can be changed by the user/caller and alter the behaviour of the lookahead branching. */
    998typedef struct
    999{
    1000 SCIP_Longint reevalage; /**< The number of "normal" (not probing) lps that may have been solved before
    1001 * we stop using old data and start recalculating new first level data. */
    1002 SCIP_Longint reevalagefsb; /**< The number of "normal" (not probing) lps that may have been solved before
    1003 * we stop using old FSB data and start recalculating new first level data. */
    1004 int maxnviolatedcons; /**< The number of constraints (domain reductions and binary constraints) we
    1005 * want to gather before restarting the run. Set to -1 for an unbounded
    1006 * number of constraints. */
    1007 int maxnviolatedbincons;/**< The number of binary constraints we want to gather before restarting the
    1008 * run. Set to -1 for an undbounded number of binary constraints. */
    1009 int maxnviolateddomreds;/**< The number of domain reductions we want to gather before restarting the
    1010 * run. Set to -1 for an undbounded number of domain reductions. */
    1011 int recursiondepth; /**< How deep should the recursion go? Default for Lookahead: 2 */
    1012 int maxncands; /**< If abbreviated == TRUE, at most how many candidates should be handled at the base node? */
    1013 int maxndeepercands; /**< If abbreviated == TRUE, at most how many candidates should be handled in deeper nodes? */
    1014 SCIP_Bool usedomainreduction; /**< indicates whether the data for domain reductions should be gathered and
    1015 * used. */
    1016 SCIP_Bool mergedomainreductions; /**< should domain reductions of feasible siblings should be merged? */
    1017 SCIP_Bool prefersimplebounds; /**< should domain reductions only be applied if there are simple bound changes? */
    1018 SCIP_Bool onlyvioldomreds; /**< Should only domain reductions that violate the LP solution be applied? */
    1019 SCIP_Bool usebincons; /**< indicates whether the data for the implicit binary constraints should
    1020 * be gathered and used */
    1021 int addbinconsrow; /**< should binary constraints be added as rows to the base LP?
    1022 * (0: no, 1: separate, 2: as initial rows) */
    1023 SCIP_Bool addnonviocons; /**< Should constraints be added, that are not violated by the base LP? */
    1024 SCIP_Bool abbreviated; /**< Should the abbreviated version be used? */
    1025 SCIP_Bool reusebasis; /**< If abbreviated == TRUE, should the solution lp-basis of the FSB run be
    1026 * used in the first abbreviated level? */
    1027 SCIP_Bool storeunviolatedsol; /**< Should a solution/decision be stored, to speed up the next iteration
    1028 * after adding the constraints/domreds? */
    1029 SCIP_Bool abbrevpseudo; /**< If abbreviated == TRUE, should pseudocost values be used, to approximate
    1030 * the scoring? */
    1031 SCIP_Bool level2avgscore; /**< should the average score be used for uninitialized scores in level 2? */
    1032 SCIP_Bool level2zeroscore; /**< should uninitialized scores in level 2 be set to zero? */
    1033 SCIP_Bool addclique; /**< add binary constraints with two variables found at the root node also as a clique? */
    1034 SCIP_Bool propagate; /**< Should the problem be propagated before solving each inner node? */
    1035 SCIP_Bool uselevel2data; /**< should branching data generated at depth level 2 be stored for re-using it? */
    1036 SCIP_Bool applychildbounds; /**< should bounds known for child nodes be applied? */
    1037 SCIP_Bool enforcemaxdomreds; /**< should the maximum number of domain reductions maxnviolateddomreds be enforced? */
    1038 SCIP_Bool updatebranchingresults; /**< should branching results (and scores) be updated w.r.t. proven dual bounds? */
    1039 SCIP_Bool inscoring; /**< are we currently in FSB-scoring (only used internally) */
    1040 int maxproprounds; /**< maximum number of propagation rounds to perform at temporary nodes
    1041 * (-1: unlimited, 0: SCIP default) */
    1042 char scoringfunction; /**< scoring function at base level */
    1043 char deeperscoringfunction; /**< scoring function at deeper levels */
    1044 char scoringscoringfunction;/**< scoring function for FSB scoring */
    1045 SCIP_Real minweight; /**< weight of the min gain of two child problems */
    1046 SCIP_Real worsefactor; /**< if the FSB score is of a candidate is worse than the best by this factor, skip this candidate (-1: disable) */
    1047 SCIP_Bool filterbymaxgain; /**< should lookahead branching only be applied if the max gain in level 1 is not uniquely that of the best candidate? */
    1049
    1050
    1051#if defined(SCIP_DEBUG) || defined(SCIP_STATISTIC)
    1052#define MAXRESULT SCIP_DELAYNODE
    1053
    1054/** returns a human readable name for the given result enum value */
    1055static
    1056const char* getStatusString(
    1057 SCIP_RESULT result /**< enum value to get the string representation for */
    1058 )
    1059{
    1060 assert(result >= 1);
    1061 assert(result <= 18);
    1062
    1063 switch( result )
    1064 {
    1065 case SCIP_DIDNOTRUN:
    1066 return "SCIP_DIDNOTRUN";
    1067 case SCIP_DELAYED:
    1068 return "SCIP_DELAYED";
    1069 case SCIP_DIDNOTFIND:
    1070 return "SCIP_DIDNOTFIND";
    1071 case SCIP_FEASIBLE:
    1072 return "SCIP_FEASIBLE";
    1073 case SCIP_INFEASIBLE:
    1074 return "SCIP_INFEASIBLE";
    1075 case SCIP_UNBOUNDED:
    1076 return "SCIP_UNBOUNDED";
    1077 case SCIP_CUTOFF:
    1078 return "SCIP_CUTOFF";
    1079 case SCIP_SEPARATED:
    1080 return "SCIP_SEPARATED";
    1081 case SCIP_NEWROUND:
    1082 return "SCIP_NEWROUND";
    1083 case SCIP_REDUCEDDOM:
    1084 return "SCIP_REDUCEDDOM";
    1085 case SCIP_CONSADDED:
    1086 return "SCIP_CONSADDED";
    1087 case SCIP_CONSCHANGED:
    1088 return "SCIP_CONSCHANGED";
    1089 case SCIP_BRANCHED:
    1090 return "SCIP_BRANCHED";
    1091 case SCIP_SOLVELP:
    1092 return "SCIP_SOLVELP";
    1093 case SCIP_FOUNDSOL:
    1094 return "SCIP_FOUNDSOL";
    1095 case SCIP_SUSPENDED:
    1096 return "SCIP_SUSPENDED";
    1097 case SCIP_SUCCESS:
    1098 return "SCIP_SUCCESS";
    1099 case SCIP_DELAYNODE:
    1100 return "SCIP_DELAYNODE";
    1101 default:
    1102 SCIPerrorMessage("result code %d not treated in lookahead branching rule\n", result);
    1103 SCIPABORT();
    1104 return "UNKNOWN";
    1105 }
    1106}
    1107#endif
    1108
    1109#ifdef SCIP_STATISTIC
    1110/** The data used for some statistical analysis. */
    1111typedef struct
    1112{
    1113 int* nresults; /**< Array of counters for each result state the lookahead branching finished.
    1114 * The first (0) entry is unused, as the result states are indexed 1-based
    1115 * and we use this index as our array index. */
    1116 int* nsinglecutoffs; /**< The number of single cutoffs on a (probing) node per probingdepth. */
    1117 int* nfullcutoffs; /**< The number of double cutoffs on a (probing) node per probingdepth. */
    1118 int* nlpssolved; /**< The number of all lps solved for a given probingdepth (incl. FSB). */
    1119 int* nlpssolvedfsb; /**< The number of lps solved by the initial FSB to get the FSB scores. */
    1120 int* nduplicatelps; /**< The number of lps solved for duplicate grand-child nodes. */
    1121 SCIP_Longint* nlpiterations; /**< The number of all lp iterations needed for a given probingdepth
    1122 * (incl. FSB). */
    1123 SCIP_Longint* nlpiterationsfsb; /**< The number of lp iterations needed to get the FSB scores. */
    1124 int* npropdomred; /**< The number of domain reductions based on domain propagation per
    1125 * progingdepth. */
    1126 int* noldbranchused; /**< The number of times old branching data is used (see the reevalage
    1127 * parameter in the CONFIGURATION struct) */
    1128 int* noldbranchusedfsb; /**< The number of times old FSB scoring data is used (see the reevalagefsb
    1129 * parameter in the CONFIGURATION struct) */
    1130 int* chosenfsbcand; /**< If abbreviated, this is the number of times each candidate was finally
    1131 * chosen by the following LAB */
    1132 int* stopafterfsb; /**< If abbreviated, this is the number of times the rule was stopped after
    1133 * scoring candidates by FSB, e.g., by adding constraints or domreds. */
    1134 int* cutoffafterfsb; /**< If abbreviated, this is the number of times the rule was stopped after
    1135 * scoring candidates by FSB because of a found cutoff. */
    1136 int* domredafterfsb; /**< If abbreviated, this is the number of times the rule was stopped after
    1137 * scoring candidates by FSB because of a found domain reduction. */
    1138 int nsinglecandidate; /**< number of times a single candidate was given to the recursion routine */
    1139 int nsingleafterfilter; /**< number of times a single candidate remained after filtering */
    1140 int noldcandidate; /**< number of times the old candidate from last call with nonviolating
    1141 * reductions was branched on */
    1142 int nlperrorcalls; /**< number of times an LP error occured and LAB branched without completely
    1143 * evaluating all candidates */
    1144 int nlimitcalls; /**< number of times a time limit was reached and LAB branched without
    1145 * completely evaluating all candidates */
    1146 int ntotalresults; /**< The total sum of the entries in nresults. */
    1147 int nbinconst; /**< The number of binary constraints added to the base node. */
    1148 int nbinconstvio; /**< The number of binary constraints added to the base node, that are violated
    1149 * by the LP at that node. */
    1150 int ndomred; /**< The number of domain reductions added to the base node. */
    1151 int ndomredvio; /**< The number of domain reductions added to the base node, that are violated
    1152 * by the LP at that node. */
    1153 int ndepthreached; /**< The number of times the branching was aborted due to a too small depth. */
    1154 int ndomredcons; /**< The number of binary constraints ignored, as they would be dom reds. */
    1155 int ncutoffproofnodes; /**< The number of nodes needed to prove all found cutoffs. */
    1156 int ndomredproofnodes; /**< The number of nodes needed to prove all found domreds. */
    1157 int ncliquesadded; /**< The number of cliques added in the root node. */
    1158 int maxnbestcands; /**< if abbreviated, this is the maximum number of candidates to investigate */
    1159 int recursiondepth; /**< The recursiondepth of the LAB. Can be used to access the depth-dependent
    1160 * arrays contained in the statistics. */
    1161} STATISTICS;
    1162
    1163/** Initializes the statistics with the start values. */
    1164static
    1165void statisticsInit(
    1166 STATISTICS* statistics /**< the statistics to be initialized */
    1167 )
    1168{
    1169 int i;
    1170
    1171 assert(statistics != NULL);
    1172 assert(statistics->recursiondepth > 0);
    1173
    1174 statistics->nsinglecandidate = 0;
    1175 statistics->nsingleafterfilter = 0;
    1176 statistics->noldcandidate = 0;
    1177 statistics->nlperrorcalls = 0;
    1178 statistics->nlimitcalls = 0;
    1179 statistics->ntotalresults = 0;
    1180 statistics->nbinconst = 0;
    1181 statistics->nbinconstvio = 0;
    1182 statistics->ndomredvio = 0;
    1183 statistics->ndepthreached = 0;
    1184 statistics->ndomred = 0;
    1185 statistics->ndomredcons = 0;
    1186 statistics->ncutoffproofnodes = 0;
    1187 statistics->ndomredproofnodes = 0;
    1188 statistics->ncliquesadded = 0;
    1189
    1190 for( i = 0; i <= MAXRESULT; i++)
    1191 {
    1192 statistics->nresults[i] = 0;
    1193 }
    1194
    1195 for( i = 0; i < statistics->recursiondepth; i++ )
    1196 {
    1197 statistics->noldbranchused[i] = 0;
    1198 statistics->noldbranchusedfsb[i] = 0;
    1199 statistics->npropdomred[i] = 0;
    1200 statistics->nfullcutoffs[i] = 0;
    1201 statistics->nlpssolved[i] = 0;
    1202 statistics->nlpssolvedfsb[i] = 0;
    1203 statistics->nduplicatelps[i] = 0;
    1204 statistics->nlpiterations[i] = 0;
    1205 statistics->nlpiterationsfsb[i] = 0;
    1206 statistics->nsinglecutoffs[i] = 0;
    1207 statistics->stopafterfsb[i] = 0;
    1208 statistics->cutoffafterfsb[i] = 0;
    1209 statistics->domredafterfsb[i] = 0;
    1210 }
    1211
    1212 for( i = 0; i < statistics->maxnbestcands; i++ )
    1213 {
    1214 statistics->chosenfsbcand[i] = 0;
    1215 }
    1216}
    1217
    1218/** Prints the content of the statistics to stdout. */
    1219static
    1220void statisticsPrint(
    1221 SCIP* scip, /**< SCIP data structure */
    1222 STATISTICS* statistics /**< the statistics to print */
    1223 )
    1224{
    1225 assert(scip != NULL);
    1226 assert(statistics != NULL);
    1227 assert(statistics->recursiondepth > 0);
    1228
    1229 /* only print something, if we have any statistics */
    1230 if( statistics->ntotalresults > 0 )
    1231 {
    1232 int i;
    1233
    1234 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Lookahead Branching was called <%i> times.\n", statistics->ntotalresults);
    1235
    1236 for( i = 1; i <= MAXRESULT; i++ )
    1237 {
    1238 SCIP_RESULT currentresult = (SCIP_RESULT)i;
    1239 /* see type_result.h for the id <-> enum mapping */
    1240 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Result <%s> was chosen <%i> times\n", getStatusString(currentresult),
    1241 statistics->nresults[i]);
    1242 }
    1243
    1244 for( i = 0; i < statistics->maxnbestcands; i++ )
    1245 {
    1246 if( statistics->chosenfsbcand[i] > 0 )
    1247 {
    1248 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "The %i. variable (w.r.t. the FSB score) was chosen as the final result %i times.\n",
    1249 i+1, statistics->chosenfsbcand[i]);
    1250 }
    1251 }
    1252
    1253 for( i = 0; i < statistics->recursiondepth; i++ )
    1254 {
    1255 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",
    1256 i, statistics->stopafterfsb[i], statistics->cutoffafterfsb[i], statistics->domredafterfsb[i]);
    1257 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "In depth <%i>, <%i> fullcutoffs and <%i> single cutoffs were found.\n",
    1258 i, statistics->nfullcutoffs[i], statistics->nsinglecutoffs[i]);
    1259 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",
    1260 i, statistics->nlpssolved[i], statistics->nlpssolvedfsb[i], statistics->nduplicatelps[i]);
    1261 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "In depth <%i>, <%" SCIP_LONGINT_FORMAT "> iterations were needed to solve the LPs, <%"
    1262 SCIP_LONGINT_FORMAT "> of them to calculate the FSB score.\n", i, statistics->nlpiterations[i],
    1263 statistics->nlpiterationsfsb[i]);
    1264 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "In depth <%i>, a decision was discarded <%i> times due to domain reduction because of"
    1265 " propagation.\n", i, statistics->npropdomred[i]);
    1266 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 i, statistics->noldbranchused[i], statistics->noldbranchusedfsb[i]);
    1268 }
    1269
    1270 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "One single branching candidate was given <%i> times, after filtering, a single candidate remained <%i> times.\n",
    1271 statistics->nsinglecandidate, statistics->nsingleafterfilter);
    1272 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "The old branching candidate was used <%i> times.\n",
    1273 statistics->noldcandidate);
    1274 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "An LP error led to branching before all candidates were evaluated <%i> times.\n",
    1275 statistics->nlperrorcalls);
    1276 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "A reached (time) limit led to branching before all candidates were evaluated <%i> times.\n",
    1277 statistics->nlimitcalls);
    1278 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Depth limit was reached <%i> times.\n", statistics->ndepthreached);
    1279 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Ignored <%i> binary constraints, that would be domain reductions.\n",
    1280 statistics->ndomredcons);
    1281 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Added <%i> binary constraints, of which <%i> where violated by the base LP.\n",
    1282 statistics->nbinconst, statistics->nbinconstvio);
    1283 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Reduced the domain of <%i> vars, <%i> of them where violated by the base LP.\n",
    1284 statistics->ndomred, statistics->ndomredvio);
    1285 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Added <%i> cliques found as binary constraint in the root node\n",
    1286 statistics->ncliquesadded);
    1287 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Needed <%i> additional nodes to prove the cutoffs of base nodes\n",
    1288 statistics->ncutoffproofnodes);
    1289 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Needed <%i> additional nodes to prove the domain reductions\n",
    1290 statistics->ndomredproofnodes);
    1291 }
    1292}
    1293
    1294/** Helper struct to store the statistical data needed in a single run. */
    1295typedef struct
    1296{
    1297 int ncutoffproofnodes; /**< The number of nodes needed to prove the current cutoff. */
    1298} LOCALSTATISTICS;
    1299
    1300/** Allocates the local statistics in buffer memory and initializes it with default values. */
    1301static
    1302SCIP_RETCODE localStatisticsAllocate(
    1303 SCIP* scip, /**< SCIP data structure */
    1304 LOCALSTATISTICS** localstats /**< pointer to the local statistics to allocate and initialize */
    1305 )
    1306{
    1307 assert(scip != NULL);
    1308 assert(localstats != NULL);
    1309
    1310 SCIP_CALL( SCIPallocBuffer(scip, localstats) );
    1311
    1312 (*localstats)->ncutoffproofnodes = 0;
    1313
    1314 return SCIP_OKAY;
    1315}
    1316
    1317/** Frees the allocated buffer memory of the local statistics. */
    1318static
    1319void localStatisticsFree(
    1320 SCIP* scip, /**< SCIP data structure */
    1321 LOCALSTATISTICS** localstats /**< pointer to the local statistics to be freed */
    1322 )
    1323{
    1324 assert(scip != NULL);
    1325 assert(localstats != NULL);
    1326
    1327 SCIPfreeBuffer(scip, localstats);
    1328}
    1329#endif
    1330
    1331/** branching rule data */
    1332struct SCIP_BranchruleData
    1333{
    1334 CONFIGURATION* config; /**< the parameter that influence the behaviour of the lookahead branching */
    1335 PERSISTENTDATA* persistent; /**< the data that persists over multiple branching decisions */
    1336 SCIP_Bool isinitialized; /**< indicates whether the fields in this struct are initialized */
    1337#ifdef SCIP_STATISTIC
    1338 STATISTICS* statistics; /**< statistical data container */
    1339#endif
    1340};
    1341
    1342/** all constraints that were created and may be added to the base node */
    1343typedef struct
    1344{
    1345 SCIP_VAR*** consvars; /**< array containing the variables for each constraint to be created */
    1346 int* nconsvars; /**< number of vars in each element of 'consvars' */
    1347 SCIP_Bool* violated; /**< indicating whether a constraint is violated by the base solution */
    1348 int nelements; /**< number of elements in 'consvars' and 'nconsvars' */
    1349 int memorysize; /**< number of entries that the array 'consvars' may hold before the
    1350 * array is reallocated. */
    1351 int nviolatedcons; /**< number of constraints that are violated by the base LP solution. */
    1353
    1354/** Allocate and initialize the list holding the constraints. */
    1355static
    1357 SCIP* scip, /**< SCIP data structure */
    1358 CONSTRAINTLIST** conslist, /**< Pointer to the list to be allocated and initialized. */
    1359 int startsize /**< The number of entries the list initially can hold. */
    1360 )
    1361{
    1362 assert(scip != NULL);
    1363 assert(conslist != NULL);
    1364 assert(startsize > 0);
    1365
    1366 SCIP_CALL( SCIPallocBuffer(scip, conslist) );
    1367 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*conslist)->consvars, startsize) );
    1368 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*conslist)->nconsvars, startsize) );
    1369 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*conslist)->violated, startsize) );
    1370
    1371 /* We start without any constraints */
    1372 (*conslist)->nelements = 0;
    1373 (*conslist)->memorysize = startsize;
    1374 (*conslist)->nviolatedcons = 0;
    1375
    1376 return SCIP_OKAY;
    1377}
    1378
    1379/** Append an element to the end of the list of constraints. */
    1380static
    1382 SCIP* scip, /**< SCIP data structure */
    1383 CONSTRAINTLIST* list, /**< list to add the consvars to */
    1384 SCIP_VAR** consvars, /**< array of variables for the constraint to be created later */
    1385 int nconsvars, /**< number of elements in 'consvars' */
    1386 SCIP_Bool violated /**< indicates whether the constraint is violated by the base lp */
    1387 )
    1388{
    1389 assert(scip != NULL);
    1390 assert(list != NULL);
    1391 assert(consvars != NULL);
    1392 assert(nconsvars > 0);
    1393
    1394 /* In case the list tries to hold more elements than it has space, reallocate */
    1395 if( list->memorysize == list->nelements )
    1396 {
    1397 /* resize the array, such that it can hold the new element */
    1398 int newmemsize = SCIPcalcMemGrowSize(scip, list->memorysize + 1);
    1399 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &list->consvars, list->memorysize, newmemsize) );
    1400 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &list->nconsvars, list->memorysize, newmemsize) );
    1401 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &list->violated, list->memorysize, newmemsize) );
    1402 list->memorysize = newmemsize;
    1403 }
    1404
    1405 /* Set the new vars at the first unused place, which is the length used as index */
    1406 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &list->consvars[list->nelements], consvars, nconsvars) ); /*lint !e866*/
    1407 list->nconsvars[list->nelements] = nconsvars;
    1408 list->violated[list->nelements] = violated;
    1409 list->nelements++;
    1410
    1411 return SCIP_OKAY;
    1412}
    1413
    1414/** Free all resources of a constraint list in opposite order to the allocation. */
    1415static
    1417 SCIP* scip, /**< SCIP data structure */
    1418 CONSTRAINTLIST** conslist /**< Pointer to the list to be freed. */
    1419 )
    1420{
    1421 int i;
    1422
    1423 assert(scip != NULL);
    1424 assert(conslist != NULL);
    1425
    1426 for( i = 0; i < (*conslist)->nelements; i++ )
    1427 {
    1428 SCIPfreeBlockMemoryArray(scip, &(*conslist)->consvars[i], (*conslist)->nconsvars[i]);
    1429 }
    1430
    1431 SCIPfreeBlockMemoryArray(scip, &(*conslist)->violated, (*conslist)->memorysize);
    1432 SCIPfreeBlockMemoryArray(scip, &(*conslist)->nconsvars, (*conslist)->memorysize);
    1433 SCIPfreeBlockMemoryArray(scip, &(*conslist)->consvars, (*conslist)->memorysize);
    1434 SCIPfreeBuffer(scip, conslist);
    1435}
    1436
    1437/**
    1438 * list of binary variables currently branched on
    1439 * a down branching (x <= 0) is saved as the negated variable (1-x)
    1440 * an up branching (x >= 1) is saved as the original variable (x)
    1441 * these variables are used to build the binary constraint in case that a ('binary') branch is cut off
    1442 */
    1443typedef struct
    1444{
    1445 SCIP_VAR** binaryvars; /**< The binary variables currently branched on. */
    1446 int nbinaryvars; /**< The number of entries in 'nbinaryvars'. */
    1447 int memorysize; /**< The number of entries that the array 'binaryvars' may hold before the
    1448 * array is reallocated. */
    1450
    1451/** Allocates and initializes the BINARYVARLIST struct. */
    1452static
    1454 SCIP* scip, /**< SCIP data structure */
    1455 BINARYVARLIST** list, /**< Pointer to the list to be allocated and initialized. */
    1456 int startsize /**< The number of entries the list initially can hold. */
    1457 )
    1458{
    1459 assert(scip != NULL);
    1460 assert(list != NULL);
    1461 assert(startsize > 0);
    1462
    1463 SCIP_CALL( SCIPallocBuffer(scip, list) );
    1464 SCIP_CALL( SCIPallocBufferArray(scip, &(*list)->binaryvars, startsize) );
    1465
    1466 /* We start with no entries and the (current) max length */
    1467 (*list)->nbinaryvars = 0;
    1468 (*list)->memorysize = startsize;
    1469
    1470 return SCIP_OKAY;
    1471}
    1472
    1473/** Appends a binary variable to the list, reallocating the list if necessary. */
    1474static
    1476 SCIP* scip, /**< SCIP data structure */
    1477 BINARYVARLIST* list, /**< The list to add the var to. */
    1478 SCIP_VAR* vartoadd /**< The binary var to add to the list. */
    1479 )
    1480{
    1481 assert(scip != NULL);
    1482 assert(list != NULL);
    1483 assert(vartoadd != NULL);
    1484 assert(SCIPvarIsBinary(vartoadd));
    1485 assert(list->nbinaryvars < list->memorysize);
    1486
    1487 /* Set the new var at the first unused place, which is the length used as index */
    1488 list->binaryvars[list->nbinaryvars] = vartoadd;
    1489 list->nbinaryvars++;
    1490}
    1491
    1492/** Remove the last element from the list. */
    1493static
    1495 BINARYVARLIST* list /**< The list to remove the last element from. */
    1496 )
    1497{
    1498 assert(list != NULL);
    1499 assert(list->nbinaryvars > 0);
    1500 assert(list->binaryvars[list->nbinaryvars-1] != NULL);
    1501
    1502 /* decrement the number of entries in the actual list */
    1503 list->nbinaryvars--;
    1504}
    1505
    1506/** Frees all resources allocated by a BINARYVARLIST in opposite order of allocation. */
    1507static
    1509 SCIP* scip, /**< SCIP data structure */
    1510 BINARYVARLIST** list /**< Pointer to the list to free */
    1511 )
    1512{
    1513 assert(scip != NULL);
    1514 assert(list != NULL);
    1515
    1516 SCIPfreeBufferArray(scip, &(*list)->binaryvars);
    1517 SCIPfreeBuffer(scip, list);
    1518}
    1519
    1520/** struct holding the relevant data for handling binary constraints */
    1521typedef struct
    1522{
    1523 BINARYVARLIST* binaryvars; /**< current binary vars, used to fill the conslist */
    1524 CONSTRAINTLIST* conslist; /**< list of constraints to be created */
    1525} BINCONSDATA;
    1526
    1527/** Allocate and initialize the BINCONSDATA struct. */
    1528static
    1530 SCIP* scip, /**< SCIP data structure */
    1531 BINCONSDATA** consdata, /**< Pointer to the struct to be allocated and initialized. */
    1532 int maxdepth, /**< The depth of the recursion as an upper bound of branch vars to hold. */
    1533 int nstartcons /**< The start size of the array containing the constraints. */
    1534 )
    1535{
    1536 assert(scip != NULL);
    1537 assert(consdata != NULL);
    1538 assert(maxdepth > 0);
    1539 assert(nstartcons > 0);
    1540
    1541 SCIP_CALL( SCIPallocBuffer(scip, consdata) );
    1542 SCIP_CALL( binaryVarListCreate(scip, &(*consdata)->binaryvars, maxdepth) );
    1543 SCIP_CALL( constraintListCreate(scip, &(*consdata)->conslist, nstartcons) );
    1544
    1545 return SCIP_OKAY;
    1546}
    1547
    1548/** Free all resources in a BINCONSDATA in opposite order of allocation. */
    1549static
    1551 SCIP* scip, /**< SCIP data structure */
    1552 BINCONSDATA** consdata /**< Pointer to the struct to be freed. */
    1553 )
    1554{
    1555 assert(scip != NULL);
    1556 assert(consdata != NULL);
    1557
    1558 constraintListFree(scip, &(*consdata)->conslist);
    1559 binaryVarListFree(scip, &(*consdata)->binaryvars);
    1560 SCIPfreeBuffer(scip, consdata);
    1561}
    1562
    1563/** A struct acting as a fixed list of candidates */
    1564typedef struct
    1565{
    1566 CANDIDATE** candidates; /**< the array of candidates */
    1567 int ncandidates; /**< the number of actual entries in candidates (without trailing NULLs); this
    1568 * is NOT the length of the candidates array, but the number of candidates in
    1569 * it */
    1571
    1572/** allocates the candidate list on the buffer WITHOUT initializing the contained array of candidates. */
    1573static
    1575 SCIP* scip, /**< SCIP data structure */
    1576 CANDIDATELIST** candidatelist, /**< the candidate list to allocate */
    1577 int ncandidates /**< the number of candidates the list must hold */
    1578 )
    1579{
    1580 assert(scip != NULL);
    1581 assert(candidatelist != NULL);
    1582 assert(ncandidates >= 0);
    1583
    1584 SCIP_CALL( SCIPallocBuffer(scip, candidatelist) );
    1585
    1586 if( ncandidates > 0 )
    1587 {
    1588 SCIP_CALL( SCIPallocBufferArray(scip, &(*candidatelist)->candidates, ncandidates) );
    1589 }
    1590 else
    1591 (*candidatelist)->candidates = NULL;
    1592
    1593 (*candidatelist)->ncandidates = ncandidates;
    1594
    1595 return SCIP_OKAY;
    1596}
    1597
    1598/** allocates the given list and fills it with all fractional candidates of the current LP solution. */
    1599static
    1601 SCIP* scip, /**< SCIP data structure */
    1602 CANDIDATELIST** candidatelist /**< the list to allocate and fill */
    1603 )
    1604{
    1605 SCIP_VAR** lpcands;
    1606 SCIP_Real* lpcandssol;
    1607 SCIP_Real* lpcandsfrac;
    1608 int nlpcands;
    1609 int i;
    1610
    1611 assert(scip != NULL);
    1612 assert(candidatelist != NULL);
    1613
    1614 /* get all fractional candidates */
    1615 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) );
    1616
    1617 assert(lpcands != NULL);
    1618 assert(lpcandssol != NULL);
    1619 assert(lpcandsfrac != NULL);
    1620
    1621 SCIP_CALL( candidateListCreate(scip, candidatelist, nlpcands) );
    1622
    1623 for( i = 0; i < nlpcands; i++ )
    1624 {
    1625 CANDIDATE* candidate;
    1626
    1627 SCIP_CALL( candidateCreate(scip, &candidate) );
    1628 assert(candidate != NULL);
    1629
    1630 candidate->branchvar = lpcands[i];
    1631 candidate->branchval = lpcandssol[i];
    1632 candidate->fracval = lpcandsfrac[i];
    1633
    1634 (*candidatelist)->candidates[i] = candidate;
    1635
    1636 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "created candidate <%s>...\n",
    1637 SCIPvarGetName(candidate->branchvar));
    1638 }
    1639
    1640 return SCIP_OKAY;
    1641}
    1642
    1643/** frees the allocated buffer memory of the candidate list and frees the contained candidates. */
    1644static
    1646 SCIP* scip, /**< SCIP data structure */
    1647 CANDIDATELIST** candidatelist /**< the list to be freed */
    1648 )
    1649{
    1650 int i;
    1651
    1652 assert(scip != NULL);
    1653 assert(candidatelist != NULL);
    1654 assert((*candidatelist)->ncandidates > 0 || (*candidatelist)->candidates == NULL);
    1655
    1656 if( (*candidatelist)->candidates != NULL )
    1657 {
    1658 for( i = (*candidatelist)->ncandidates - 1; i >= 0; i-- )
    1659 {
    1660 CANDIDATE* cand = (*candidatelist)->candidates[i];
    1661 if( cand != NULL )
    1662 {
    1663 SCIP_CALL( candidateFree(scip, &cand) );
    1664 }
    1665 }
    1666
    1667 SCIPfreeBufferArray(scip, &(*candidatelist)->candidates);
    1668 }
    1669 SCIPfreeBuffer(scip, candidatelist);
    1670
    1671 return SCIP_OKAY;
    1672}
    1673
    1674/** keeps only the first candidates and frees the remaining ones */
    1675static
    1677 SCIP* scip, /**< SCIP data structure */
    1678 CANDIDATELIST* candidatelist, /**< the list to allocate and fill */
    1679 int nindices /**< the number of candidates to keep (starting from 0) */
    1680 )
    1681{
    1682 int i;
    1683
    1684 assert(scip != NULL);
    1685 assert(candidatelist != NULL);
    1686 assert(0 < nindices);
    1687 assert(nindices <= candidatelist->ncandidates);
    1688
    1689 /* only keep the first nindices candidates and free the remaining ones */
    1690 for( i = nindices; i < candidatelist->ncandidates; i++ )
    1691 {
    1692 CANDIDATE* cand = candidatelist->candidates[i];
    1693 if( cand != NULL )
    1694 {
    1695 SCIP_CALL( candidateFree(scip, &cand) );
    1696 candidatelist->candidates[i] = NULL;
    1697 }
    1698 }
    1699 candidatelist->ncandidates = nindices;
    1700
    1701 return SCIP_OKAY;
    1702}
    1703
    1704/** all domain reductions found through cutoff of branches */
    1705typedef struct
    1706{
    1707 SCIP_Real* lowerbounds; /**< The new lower bounds found for each variable in the problem. */
    1708 SCIP_Real* upperbounds; /**< The new upper bounds found for each variable in the problem. */
    1709 SCIP_Shortbool* baselpviolated; /**< Indicates whether the base lp solution violates the new bounds of a var.*/
    1710 int nviolatedvars; /**< Tracks the number of vars that have a violated (by the base lp) new lower
    1711 * or upper bound. */
    1712 int nchangedvars; /**< Tracks the number of vars, that have a changed domain. (a change on both,
    1713 * upper and lower bound, counts as one.) */
    1714 int nsimplebounds; /**< number of changed bounds resulting from infeasible child nodes */
    1715#ifdef SCIP_STATISTIC
    1716 int* lowerboundnproofs; /**< The number of nodes needed to prove the lower bound for each variable. */
    1717 int* upperboundnproofs; /**< The number of nodes needed to prove the upper bound for each variable. */
    1718#endif
    1720
    1721/** allocate the struct on the buffer and initialize it with the default values */
    1722static
    1724 SCIP* scip, /**< SCIP data structure */
    1725 DOMAINREDUCTIONS** domreds /**< The struct that has to be allocated and initialized. */
    1726 )
    1727{
    1728 SCIP_VAR** vars;
    1729 int ntotalvars;
    1730 int v;
    1731
    1732 assert(scip != NULL);
    1733 assert(domreds != NULL);
    1734
    1735 /* The arrays saves the data for all variables in the problem via the ProbIndex. See SCIPvarGetProbindex() */
    1736 vars = SCIPgetVars(scip);
    1737 ntotalvars = SCIPgetNVars(scip);
    1738
    1739 /* Allocate the struct and the contained arrays; initialize flags to FALSE */
    1740 SCIP_CALL( SCIPallocBuffer(scip, domreds) );
    1741 SCIP_CALL( SCIPallocBufferArray(scip, &(*domreds)->lowerbounds, ntotalvars) );
    1742 SCIP_CALL( SCIPallocBufferArray(scip, &(*domreds)->upperbounds, ntotalvars) );
    1743 SCIP_CALL( SCIPallocClearBufferArray(scip, &(*domreds)->baselpviolated, ntotalvars) );
    1744#ifdef SCIP_STATISTIC
    1745 SCIP_CALL( SCIPallocClearBufferArray(scip, &(*domreds)->lowerboundnproofs, ntotalvars) );
    1746 SCIP_CALL( SCIPallocClearBufferArray(scip, &(*domreds)->upperboundnproofs, ntotalvars) );
    1747#endif
    1748
    1749 for( v = 0; v < ntotalvars; ++v )
    1750 {
    1751 (*domreds)->lowerbounds[v] = SCIPvarGetLbLocal(vars[v]);
    1752 (*domreds)->upperbounds[v] = SCIPvarGetUbLocal(vars[v]);
    1753 }
    1754
    1755 /* At the start we have no domain reductions for any variable. */
    1756 (*domreds)->nviolatedvars = 0;
    1757 (*domreds)->nchangedvars = 0;
    1758 (*domreds)->nsimplebounds = 0;
    1759
    1760 return SCIP_OKAY;
    1761}
    1762
    1763/** frees the given DOMAINREDUCTIONS and all contained Arrays in the opposite order of allocation */
    1764static
    1766 SCIP* scip, /**< SCIP data structure */
    1767 DOMAINREDUCTIONS** domreds /**< Pointer to the struct to be freed. */
    1768 )
    1769{
    1770 assert(scip != NULL);
    1771 assert(domreds != NULL);
    1772
    1773#ifdef SCIP_STATISTIC
    1774 SCIPfreeBufferArray(scip, &(*domreds)->upperboundnproofs);
    1775 SCIPfreeBufferArray(scip, &(*domreds)->lowerboundnproofs);
    1776#endif
    1777 SCIPfreeBufferArray(scip, &(*domreds)->baselpviolated);
    1778 SCIPfreeBufferArray(scip, &(*domreds)->upperbounds);
    1779 SCIPfreeBufferArray(scip, &(*domreds)->lowerbounds);
    1780 SCIPfreeBuffer(scip, domreds);
    1781}
    1782
    1783/** information about the current status of the branching */
    1784typedef struct
    1785{
    1786 SCIP_Bool addedbinconss; /**< were binary constraints added? */
    1787 SCIP_Bool depthtoosmall; /**< was the remaining depth too small to branch on? */
    1788 SCIP_Bool lperror; /**< did an error occur while solving an LP */
    1789 SCIP_Bool cutoff; /**< was the current node cut off? */
    1790 SCIP_Bool domredcutoff; /**< was the current node cut off due to domain reductions? */
    1791 SCIP_Bool domred; /**< were domain reductions added due to information obtained through
    1792 * branching? */
    1793 SCIP_Bool limitreached; /**< was a limit (time, node, user, ...) reached? */
    1794 SCIP_Bool maxnconsreached; /**< was the max number of constraints (bin conss and dom red) reached? */
    1795} STATUS;
    1796
    1797/** Allocates the status on the buffer memory and initializes it with default values. */
    1798static
    1800 SCIP* scip, /**< SCIP data structure */
    1801 STATUS** status /**< the status to be allocated */
    1802 )
    1803{
    1804 assert(scip != NULL);
    1805 assert(status != NULL);
    1806
    1807 SCIP_CALL( SCIPallocBuffer(scip, status) );
    1808
    1809 (*status)->addedbinconss = FALSE;
    1810 (*status)->depthtoosmall = FALSE;
    1811 (*status)->lperror = FALSE;
    1812 (*status)->cutoff = FALSE;
    1813 (*status)->domred = FALSE;
    1814 (*status)->domredcutoff = FALSE;
    1815 (*status)->limitreached = FALSE;
    1816 (*status)->maxnconsreached = FALSE;
    1817
    1818 return SCIP_OKAY;
    1819}
    1820
    1821/** frees the allocated buffer memory of the status */
    1822static
    1824 SCIP* scip, /**< SCIP data structure */
    1825 STATUS** status /**< the status to be freed */
    1826 )
    1827{
    1828 assert(scip != NULL);
    1829 assert(status != NULL);
    1830 SCIPfreeBuffer(scip, status);
    1831}
    1832
    1833/** container struct to keep the calculated score for each variable */
    1834typedef struct
    1835{
    1836 SCIP_Real* scores; /**< the scores for each problem variable */
    1837 SCIP_Real* downgains; /**< the downgains for each problem variable */
    1838 SCIP_Real* upgains; /**< the upgains for each problem variable */
    1839 CANDIDATE** bestsortedcands; /**< array containing the best sorted variable indices w.r.t. their score */
    1840 int nbestsortedcands; /**< number of elements in bestsortedcands */
    1841 SCIP_Real scoresum; /**< sum of set scores */
    1842 int nsetscores; /**< number of set scores */
    1844
    1845/** resets the array containing the sorted indices w.r.t. their score. */
    1846static
    1848 SCORECONTAINER* scorecontainer /**< the score container to reset */
    1849 )
    1850{
    1851 assert(scorecontainer != NULL);
    1852
    1853 BMSclearMemoryArray(scorecontainer->bestsortedcands, scorecontainer->nbestsortedcands);
    1854}
    1855
    1856/** allocates the score container and inits it with default values */
    1857static
    1859 SCIP* scip, /**< SCIP data structure */
    1860 SCORECONTAINER** scorecontainer, /**< pointer to the score container to init */
    1861 CONFIGURATION* config /**< config struct with the user configuration */
    1862 )
    1863{
    1864 int ntotalvars;
    1865 int maxncands;
    1866 int i;
    1867
    1868 assert(scip != NULL);
    1869 assert(scorecontainer != NULL);
    1870 assert(config != NULL);
    1871
    1872 /* the container saves the score for all variables in the problem via the ProbIndex, see SCIPvarGetProbindex() */
    1873 ntotalvars = SCIPgetNVars(scip);
    1874 maxncands = ntotalvars - SCIPgetNContVars(scip) - SCIPgetNContImplVars(scip);
    1875 if( maxncands > config->maxncands )
    1876 maxncands = config->maxncands;
    1877
    1878 SCIP_CALL( SCIPallocBuffer(scip, scorecontainer) );
    1879 SCIP_CALL( SCIPallocBufferArray(scip, &(*scorecontainer)->scores, ntotalvars) );
    1880 SCIP_CALL( SCIPallocBufferArray(scip, &(*scorecontainer)->downgains, ntotalvars) );
    1881 SCIP_CALL( SCIPallocBufferArray(scip, &(*scorecontainer)->upgains, ntotalvars) );
    1882 SCIP_CALL( SCIPallocBufferArray(scip, &(*scorecontainer)->bestsortedcands, maxncands) );
    1883
    1884 (*scorecontainer)->nbestsortedcands = maxncands;
    1885 (*scorecontainer)->scoresum = 0.0;
    1886 (*scorecontainer)->nsetscores = 0;
    1887
    1888 scoreContainterResetBestSortedCands(*scorecontainer);
    1889
    1890 /* init the scores to something negative, as scores are always non negative */
    1891 for( i = 0; i < ntotalvars; i++ )
    1892 {
    1893 (*scorecontainer)->scores[i] = -1.0;
    1894 (*scorecontainer)->downgains[i] = -1.0;
    1895 (*scorecontainer)->upgains[i] = -1.0;
    1896 }
    1897
    1898 return SCIP_OKAY;
    1899}
    1900
    1901/** Finds the insertion index for the given score in the candidate list. The score of each candidate is taken from the
    1902 * scorecontainer. The first elements of the candidate list have to be sorted, as this method uses binary search to find
    1903 * the correct insertion point
    1904 */
    1905static
    1907 SCIP* scip, /**< SCIP data structure */
    1908 SCORECONTAINER* scorecontainer, /**< container with all the scores for each candidate */
    1909 SCIP_Real scoretoinsert, /**< score to find the insertion index for */
    1910 CANDIDATE** candidates, /**< candidate list where the first nsorted elements are sorted (w.r.t. their
    1911 * score) */
    1912 int ncandidates /**< number of elements in candidates to consider, starting from 0 */
    1913 )
    1914{
    1915 int left = 0;
    1916 int right = ncandidates - 1;
    1917
    1918 assert(scip != NULL);
    1919 assert(scorecontainer != NULL);
    1920 assert(candidates != NULL);
    1921 assert(ncandidates >= 0);
    1922
    1923 while( left <= right )
    1924 {
    1925 int mid = left + ((right - left) / 2);
    1926 SCIP_Real midscore = -SCIPinfinity(scip);
    1927 CANDIDATE *midcand = candidates[mid];
    1928
    1929 if( midcand != NULL)
    1930 {
    1931 SCIP_VAR* midvar;
    1932 int midindex;
    1933
    1934 midvar = midcand->branchvar;
    1935 midindex = SCIPvarGetProbindex(midvar);
    1936 midscore = scorecontainer->scores[midindex];
    1937 }
    1938
    1939 if( SCIPisGT(scip, scoretoinsert, midscore) )
    1940 right = mid - 1;
    1941 else
    1942 left = mid + 1;
    1943 }
    1944
    1945 return right + 1;
    1946}
    1947
    1948/** Inserts the given probindex into the sorted array in the container, moving all indices after it to the right. Then
    1949 * returns the element that does not fit into the array any longer. */
    1950static
    1952 SCORECONTAINER* scorecontainer, /**< container to insert the index into */
    1953 CANDIDATE* candidate, /**< the probindex of a variable to store */
    1954 int insertpoint /**< point to store the index at */
    1955 )
    1956{
    1957 int i;
    1958 CANDIDATE* movecand = candidate;
    1959
    1960 assert(scorecontainer != NULL);
    1961 assert(candidate != NULL);
    1962 assert(insertpoint >= 0);
    1963
    1964 for( i = insertpoint; i < scorecontainer->nbestsortedcands; i++ )
    1965 {
    1966 CANDIDATE* oldcand = scorecontainer->bestsortedcands[i];
    1967 scorecontainer->bestsortedcands[i] = movecand;
    1968 movecand = oldcand;
    1969 }
    1970
    1971 return movecand;
    1972}
    1973
    1974/** sets the score for the variable in the score container */
    1975static
    1977 SCIP* scip, /**< SCIP data structure */
    1978 SCORECONTAINER* scorecontainer, /**< the container to write into */
    1979 CANDIDATE* cand, /**< candidate to add the score for */
    1980 SCIP_Real score, /**< score to add */
    1981 SCIP_Real downgain, /**< LP gain in down child */
    1982 SCIP_Real upgain /**< LP gain in up child */
    1983 )
    1984{
    1985 CANDIDATE* droppedcandidate;
    1986 int probindex;
    1987 int insertpoint;
    1988
    1989 assert(scip != NULL);
    1990 assert(scorecontainer != NULL);
    1991 assert(cand != NULL);
    1992 assert(SCIPisGE(scip, score, -0.2));
    1993
    1994 probindex = SCIPvarGetProbindex(cand->branchvar);
    1995 assert(probindex >= 0);
    1996
    1997 if( scorecontainer->scores[probindex] < -0.5 )
    1998 {
    1999 ++scorecontainer->nsetscores;
    2000 scorecontainer->scoresum += score;
    2001 }
    2002 else
    2003 {
    2004 scorecontainer->scoresum += (score - scorecontainer->scores[probindex]);
    2005 }
    2006
    2007 scorecontainer->scores[probindex] = score;
    2008 scorecontainer->downgains[probindex] = downgain;
    2009 scorecontainer->upgains[probindex] = upgain;
    2010
    2011 /* find the point in the sorted array where the new score should be inserted */
    2012 insertpoint = findInsertionPoint(scip, scorecontainer, score, scorecontainer->bestsortedcands,
    2013 scorecontainer->nbestsortedcands);
    2014
    2015 /* insert the current variable (cand) at the position calculated above, returning the candidate that
    2016 * was removed at the end of the list; this candidate can be the given candidate for the case that the score does not
    2017 * belong to the best ones */
    2018 droppedcandidate = scoreContainerUpdateSortOrder(scorecontainer, cand, insertpoint);
    2019
    2020 /* remove the warm start info from the dropped candidate */
    2021 if( droppedcandidate != NULL )
    2022 {
    2023 SCIP_CALL( candidateFreeWarmStartInfo(scip, droppedcandidate) );
    2024 }
    2025
    2026 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Stored score <%.9g> for var <%s>.\n", score, SCIPvarGetName(cand->branchvar));
    2027
    2028 return SCIP_OKAY;
    2029}
    2030
    2031/** Frees the score container and all of its contained arrays. */
    2032static
    2034 SCIP* scip, /**< SCIP data structure */
    2035 SCORECONTAINER** scorecontainer /**< score container to free */
    2036 )
    2037{
    2038 assert(scip != NULL);
    2039 assert(scorecontainer != NULL);
    2040
    2041 /* don't free the candidates inside the cands array, as those are handled by the candidate list */
    2042 SCIPfreeBufferArray(scip, &(*scorecontainer)->bestsortedcands);
    2043 SCIPfreeBufferArray(scip, &(*scorecontainer)->upgains);
    2044 SCIPfreeBufferArray(scip, &(*scorecontainer)->downgains);
    2045 SCIPfreeBufferArray(scip, &(*scorecontainer)->scores);
    2046 SCIPfreeBuffer(scip, scorecontainer);
    2047
    2048 return SCIP_OKAY;
    2049}
    2050
    2051/*
    2052 * Local methods for the logic
    2053 */
    2054
    2055/** branches recursively on all given candidates */
    2056static
    2058 SCIP* scip, /**< SCIP data structure */
    2059 STATUS* status, /**< current status */
    2060 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
    2061 CONFIGURATION* config, /**< the configuration of the branching rule */
    2062 SCIP_SOL* baselpsol, /**< base lp solution */
    2063 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found */
    2064 BINCONSDATA* binconsdata, /**< container collecting all binary constraints */
    2065 CANDIDATELIST* candidatelist, /**< list of candidates to branch on */
    2066 BRANCHINGDECISION* decision, /**< struct to store the final decision */
    2067 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores */
    2068 LEVEL2DATA* level2data, /**< level 2 LP results data */
    2069 int recursiondepth, /**< remaining recursion depth */
    2070 SCIP_Real lpobjval, /**< LP objective value of current probing node*/
    2071 SCIP_Real baselpobjval, /**< LP objective value of focus node (not probing) */
    2072 SCIP_Longint* niterations, /**< pointer to store the total number of iterations for this variable */
    2073 int* ndeepestcutoffs, /**< pointer to store the total number of cutoffs on the deepest level */
    2074 SCIP_Real* bestgain, /**< pointer to store the best gain found with these candidates */
    2075 SCIP_Real* totalgains, /**< pointer to store the sum over all gains that are valid in both children */
    2076 int* ntotalgains, /**< pointer to store the number of gains summed in totalgains */
    2077 int* ndeepestnodes /**< pointer to store the number of nodes processed in the deepest level */
    2078#ifdef SCIP_STATISTIC
    2079 ,STATISTICS* statistics /**< general statistical data */
    2080 ,LOCALSTATISTICS* localstats /**< local statistics, may be disregarded */
    2081 ,SCIP_Real* firstscoreptr /**< pointer to store score of first candidate, or NULL */
    2082 ,SCIP_Real* bestscoreptr /**< pointer to store best score, or NULL */
    2083#endif
    2084 );
    2085
    2086/** Adds the given lower bound to the DOMAINREDUCTIONS struct. */
    2087static
    2089 SCIP* scip, /**< SCIP data structure */
    2090 SCIP_VAR* var, /**< The variable the bound should be added for. */
    2091 SCIP_Real lowerbound, /**< The new lower bound for the variable. */
    2092 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
    2093 * reduction is violated by it. */
    2094 SCIP_Bool simplechange, /**< does the change result from an infeasible child node? */
    2095 DOMAINREDUCTIONS* domainreductions /**< The struct the domain reduction should be added to. */
    2096#ifdef SCIP_STATISTIC
    2097 ,int nproofnodes /**< The number of nodes needed to prove the new lower bound. */
    2098 ,int force /**< should the number of proof nodes be added even if the bound is known already? */
    2099#endif
    2100 )
    2101{
    2102 int varindex;
    2103 SCIP_Real basesolutionval;
    2104
    2105 assert(scip != NULL);
    2106 assert(var != NULL);
    2107 assert(baselpsol != NULL);
    2108 assert(domainreductions != NULL);
    2109#ifdef SCIP_STATISTIC
    2110 assert(nproofnodes >= 0);
    2111#endif
    2112
    2113 /* The arrays inside DOMAINREDUCTIONS are indexed via the problem index. */
    2114 varindex = SCIPvarGetProbindex(var);
    2115
    2116 lowerbound = SCIPadjustedVarLb(scip, var, lowerbound);
    2117
    2118 if( SCIPisLT(scip, domainreductions->lowerbounds[varindex], lowerbound) )
    2119 {
    2120 /* the new lower bound is stronger (greater) than the old one,
    2121 * so we update the bound and number of proof nodes */
    2122 domainreductions->lowerbounds[varindex] = lowerbound;
    2123 domainreductions->nchangedvars++;
    2124 if( simplechange )
    2125 domainreductions->nsimplebounds++;
    2126#ifdef SCIP_STATISTIC
    2127 domainreductions->lowerboundnproofs[varindex] = nproofnodes;
    2128 }
    2129 else
    2130 {
    2131 /* if the given lower bound is equal to the old one we take the smaller number of proof nodes */
    2132 if( SCIPisEQ(scip, domainreductions->lowerbounds[varindex], lowerbound) &&
    2133 (force || domainreductions->lowerboundnproofs[varindex] > nproofnodes) )
    2134 domainreductions->lowerboundnproofs[varindex] = nproofnodes;
    2135#endif
    2136 }
    2137
    2138 /* we get the solution value to check whether the domain reduction is violated in the base LP */
    2139 basesolutionval = SCIPgetSolVal(scip, baselpsol, var);
    2140
    2141 /* in case the new lower bound is greater than the base solution val and the base solution val is not violated by a
    2142 * previously found bound, we increment the nviolatedvars counter and set the baselpviolated flag */
    2143 if( SCIPisFeasGT(scip, domainreductions->lowerbounds[varindex], basesolutionval)
    2144 && !domainreductions->baselpviolated[varindex] )
    2145 {
    2146 domainreductions->baselpviolated[varindex] = TRUE;
    2147 domainreductions->nviolatedvars++;
    2148 }
    2149}
    2150
    2151/** Adds the given upper bound to the DOMAINREDUCTIONS struct. */
    2152static
    2154 SCIP* scip, /**< SCIP data structure */
    2155 SCIP_VAR* var, /**< The variable the bound should be added for. */
    2156 SCIP_Real upperbound, /**< The new upper bound for the variable. */
    2157 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
    2158 * reduction is violated by it. */
    2159 SCIP_Bool simplechange, /**< does the change result from an infeasible child node? */
    2160 DOMAINREDUCTIONS* domainreductions /**< The struct the domain reduction should be added to. */
    2161#ifdef SCIP_STATISTIC
    2162 ,int nproofnodes /**< The number of nodes needed to prove the new lower bound. */
    2163 ,int force /**< should the number of proof nodes be added even if the bound is known already? */
    2164#endif
    2165 )
    2166{
    2167 int varindex;
    2168 SCIP_Real basesolutionval;
    2169
    2170 assert(scip != NULL);
    2171 assert(var != NULL);
    2172 assert(baselpsol != NULL);
    2173 assert(domainreductions != NULL);
    2174#ifdef SCIP_STATISTIC
    2175 assert(nproofnodes >= 0);
    2176#endif
    2177
    2178 /* The arrays inside DOMAINREDUCTIONS are indexed via the problem index. */
    2179 varindex = SCIPvarGetProbindex(var);
    2180
    2181 upperbound = SCIPadjustedVarUb(scip, var, upperbound);
    2182
    2183 if( SCIPisLE(scip, domainreductions->upperbounds[varindex], upperbound) )
    2184 {
    2185#ifdef SCIP_STATISTIC
    2186 /* if the given upper bound is equal to the old one we take the smaller number of proof nodes */
    2187 if( SCIPisEQ(scip, domainreductions->upperbounds[varindex], upperbound) &&
    2188 (force || domainreductions->upperboundnproofs[varindex] > nproofnodes) )
    2189 domainreductions->upperboundnproofs[varindex] = nproofnodes;
    2190#endif
    2191 }
    2192 else
    2193 {
    2194 /* the new upper bound is stronger (smaller) than the old one,
    2195 * so we update the bound and number of proof nodes */
    2196 domainreductions->upperbounds[varindex] = upperbound;
    2197 domainreductions->nchangedvars++;
    2198 if( simplechange )
    2199 domainreductions->nsimplebounds++;
    2200#ifdef SCIP_STATISTIC
    2201 domainreductions->upperboundnproofs[varindex] = nproofnodes;
    2202#endif
    2203 }
    2204
    2205 /* We get the solution value to check whether the domain reduction is violated in the base LP */
    2206 basesolutionval = SCIPgetSolVal(scip, baselpsol, var);
    2207
    2208 /* In case the new upper bound is smaller than the base solution val and the base solution val is not violated by a
    2209 * previously found bound, we increment the nviolatedvars counter and set the baselpviolated flag. */
    2210 if( SCIPisFeasLT(scip, domainreductions->upperbounds[varindex], basesolutionval)
    2211 && !domainreductions->baselpviolated[varindex] )
    2212 {
    2213 domainreductions->baselpviolated[varindex] = TRUE;
    2214 domainreductions->nviolatedvars++;
    2215 }
    2216}
    2217
    2218/** apply the domain reductions from a single struct to another one; this may be used in case one of the two child
    2219 * problems of a variable is infeasible
    2220 */
    2221static
    2223 SCIP* scip, /**< SCIP data structure */
    2224 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
    2225 * reduction is violated by it. */
    2226 int maxstoredomreds, /**< maximum number of domain reductions to store */
    2227 DOMAINREDUCTIONS* targetdomreds, /**< The target that should be filled with the merged data. */
    2228 DOMAINREDUCTIONS* domreds /**< source domain reductions */
    2229 )
    2230{
    2231 SCIP_VAR** vars;
    2232 int nvars;
    2233 int i;
    2234
    2235 assert(scip != NULL);
    2236 assert(baselpsol != NULL);
    2237 assert(targetdomreds != NULL);
    2238 assert(domreds != NULL);
    2239
    2240 /* as the bounds are tracked for all vars we have to iterate over all vars */
    2241 vars = SCIPgetVars(scip);
    2242 nvars = SCIPgetNVars(scip);
    2243
    2244 assert(vars != NULL);
    2245 assert(nvars > 0);
    2246
    2247 for( i = 0; i < nvars; i++ )
    2248 {
    2249 if( targetdomreds->nviolatedvars >= maxstoredomreds )
    2250 return;
    2251
    2252#ifdef SCIP_STATISTIC
    2253 /* adjust the proof nodes */
    2254 addLowerBound(scip, vars[i], domreds->lowerbounds[i], baselpsol, TRUE, targetdomreds,
    2255 domreds->lowerboundnproofs[i], FALSE);
    2256#else
    2257 addLowerBound(scip, vars[i], domreds->lowerbounds[i], baselpsol, TRUE, targetdomreds);
    2258#endif
    2259
    2260 if( targetdomreds->nviolatedvars >= maxstoredomreds )
    2261 return;
    2262
    2263#ifdef SCIP_STATISTIC
    2264 addUpperBound(scip, vars[i], domreds->upperbounds[i], baselpsol, TRUE, targetdomreds,
    2265 domreds->upperboundnproofs[i], FALSE);
    2266#else
    2267 addUpperBound(scip, vars[i], domreds->upperbounds[i], baselpsol, TRUE, targetdomreds);
    2268#endif
    2269 }
    2270}
    2271
    2272/**
    2273 * merges the domain reduction data from the two given branching children data into the target parent data
    2274 */
    2275static
    2277 SCIP* scip, /**< SCIP data structure */
    2278 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
    2279 * reduction is violated by it. */
    2280 int maxstoredomreds, /**< maximum number of domain reductions to store */
    2281 DOMAINREDUCTIONS* targetdomreds, /**< The target that should be filled with the merged data. */
    2282 DOMAINREDUCTIONS* downdomreds, /**< One of the source DOMAINREDUCTIONS. */
    2283 DOMAINREDUCTIONS* updomreds /**< The other source DOMAINREDUCTIONS. */
    2284 )
    2285{
    2286 SCIP_VAR** vars;
    2287 int nvars;
    2288 int i;
    2289
    2290 assert(scip != NULL);
    2291 assert(baselpsol != NULL);
    2292 assert(targetdomreds != NULL);
    2293 assert(downdomreds != NULL);
    2294 assert(updomreds != NULL);
    2295
    2296 /* as the bounds are tracked for all vars we have to iterate over all vars */
    2297 vars = SCIPgetVars(scip);
    2298 nvars = SCIPgetNVars(scip);
    2299
    2300 assert(vars != NULL);
    2301 assert(nvars > 0);
    2302
    2303 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Combining domain reductions from up and down child.\n");
    2304 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Previous number of changed variable domains: %d\n",
    2305 targetdomreds->nchangedvars);
    2306
    2307 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Number of changed variable domains in up child: %d\n",
    2308 updomreds->nchangedvars);
    2309 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Number of changed variable domains in down child: %d\n",
    2310 downdomreds->nchangedvars);
    2311
    2312 for( i = 0; i < nvars; i++ )
    2313 {
    2314 SCIP_Real newlowerbound;
    2315 SCIP_Real newupperbound;
    2316
    2317 assert(vars[i] != NULL);
    2318
    2319 if( targetdomreds->nviolatedvars >= maxstoredomreds )
    2320 return;
    2321
    2322 /* the MIN of both lower bounds represents a valid lower bound at the parent node */
    2323 newlowerbound = MIN(downdomreds->lowerbounds[i], updomreds->lowerbounds[i]);
    2324
    2325 /* This MIN can now be added via the default add method */
    2326#ifdef SCIP_STATISTIC
    2327 addLowerBound(scip, vars[i], newlowerbound, baselpsol, FALSE, targetdomreds,
    2328 MIN(4, downdomreds->lowerboundnproofs[i] + updomreds->lowerboundnproofs[i] + 2), FALSE);
    2329#else
    2330 addLowerBound(scip, vars[i], newlowerbound, baselpsol, FALSE, targetdomreds);
    2331#endif
    2332
    2333 if( targetdomreds->nviolatedvars >= maxstoredomreds )
    2334 return;
    2335
    2336 /* the MAX of both upper bounds represents a valid upper bound at the parent node */
    2337 newupperbound = MAX(downdomreds->upperbounds[i], updomreds->upperbounds[i]);
    2338
    2339 /* This MAX can now be added via the default add method */
    2340#ifdef SCIP_STATISTIC
    2341 addUpperBound(scip, vars[i], newupperbound, baselpsol, FALSE, targetdomreds,
    2342 MIN(4, downdomreds->upperboundnproofs[i] + updomreds->upperboundnproofs[i] + 2), FALSE);
    2343#else
    2344 addUpperBound(scip, vars[i], newupperbound, baselpsol, FALSE, targetdomreds);
    2345#endif
    2346 }
    2347
    2348 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Subsequent number of changed variable domains: %d\n",
    2349 targetdomreds->nchangedvars);
    2350}
    2351
    2352/** Applies the domain reductions to the current node. */
    2353static
    2355 SCIP* scip, /**< SCIP data structure */
    2356 CONFIGURATION* config, /**< the configuration of the branching rule */
    2357 SCIP_SOL* baselpsol, /**< The LP solution of the base problem. Used to check whether the domain
    2358 * reduction is violated by it. */
    2359 DOMAINREDUCTIONS* domreds, /**< The domain reductions that should be applied to the current node. */
    2360 SCIP_Bool* domredcutoff, /**< pointer to store whether a cutoff was found due to domain reductions */
    2361 SCIP_Bool* domred /**< pointer to store whether a domain change was added */
    2362#ifdef SCIP_STATISTIC
    2363 ,STATISTICS* statistics /**< The statistics container. */
    2364#endif
    2365 )
    2366{
    2367 int i;
    2368 SCIP_VAR** probvars;
    2369 int nprobvars;
    2370#if defined(SCIP_DEBUG) || defined(SCIP_STATISTIC)
    2371 int nboundsadded = 0;
    2372 int nboundsaddedvio = 0;
    2373#endif
    2374
    2375 assert(scip != NULL);
    2376 assert(baselpsol != NULL);
    2377 assert(domreds != NULL);
    2378 assert(domredcutoff != NULL);
    2379 assert(domred != NULL);
    2380#ifdef SCIP_STATISTIC
    2381 assert(statistics != NULL);
    2382#endif
    2383
    2384 /* initially we have no cutoff */
    2385 *domredcutoff = FALSE;
    2386
    2387 /* as the bounds are tracked for all vars we have to iterate over all vars */
    2388 probvars = SCIPgetVars(scip);
    2389 nprobvars = SCIPgetNVars(scip);
    2390
    2391 assert(probvars != NULL);
    2392 assert(nprobvars > 0);
    2393
    2394 if( config->prefersimplebounds && domreds->nsimplebounds == 0 )
    2395 return SCIP_OKAY;
    2396
    2397 for( i = 0; i < nprobvars && !(*domredcutoff); i++ )
    2398 {
    2399 SCIP_VAR* var;
    2400 SCIP_Real proposedbound;
    2401 SCIP_Real baselpval;
    2402#ifdef SCIP_DEBUG
    2403 SCIP_Real oldbound;
    2404#endif
    2405 SCIP_Bool infeasible;
    2406 SCIP_Bool tightened;
    2407
    2408 var = probvars[i];
    2409
    2410 assert(var != NULL);
    2411
    2412 baselpval = SCIPgetSolVal(scip, baselpsol, var);
    2413
    2414 if( SCIPisGT(scip, domreds->lowerbounds[i], SCIPvarGetLbLocal(var)) )
    2415 {
    2416 /* apply lower bound */
    2417#ifdef SCIP_DEBUG
    2418 oldbound = SCIPvarGetLbLocal(var);
    2419#endif
    2420 proposedbound = domreds->lowerbounds[i];
    2421
    2422 if( config->onlyvioldomreds && SCIPisGE(scip, baselpval, proposedbound) )
    2423 continue;
    2424
    2425 /* add the new bound */
    2426 SCIP_CALL( SCIPtightenVarLb(scip, var, proposedbound, TRUE, &infeasible, &tightened) );
    2427
    2428#if defined(SCIP_DEBUG) || defined(SCIP_STATISTIC)
    2429 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Variable <%s>, old lower bound <%g>, proposed lower bound <%g>, new "
    2430 "lower bound <%g>\n", SCIPvarGetName(var), oldbound, proposedbound, SCIPvarGetLbLocal(var));
    2431#endif
    2432
    2433 if( infeasible )
    2434 {
    2435 /* the domain reduction may result in an empty model (ub < lb) */
    2436 *domredcutoff = TRUE;
    2437 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The domain reduction of variable <%s> resulted in an empty "
    2438 "model.\n", SCIPvarGetName(var));
    2439 }
    2440 else if( tightened )
    2441 {
    2442 /* the lb is now strictly greater than before */
    2443 *domred = TRUE;
    2444#if defined(SCIP_DEBUG) || defined(SCIP_STATISTIC)
    2445 nboundsadded++;
    2446#endif
    2447#ifdef SCIP_STATISTIC
    2448 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The lower bound of variable <%s> was successfully tightened (%d).\n",
    2449 SCIPvarGetName(var), domreds->lowerboundnproofs[i]);
    2450 statistics->ndomredproofnodes += domreds->lowerboundnproofs[i];
    2451#endif
    2452
    2453#if defined(SCIP_DEBUG) || defined(SCIP_STATISTIC)
    2454 if( SCIPisLT(scip, baselpval, SCIPvarGetLbLocal(var)) )
    2455 {
    2456 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The lower bound of variable <%s> is violated by the base lp "
    2457 "value <%g>.\n", SCIPvarGetName(var), baselpval);
    2458
    2459 nboundsaddedvio++;
    2460 }
    2461#endif
    2462 }
    2463 }
    2464
    2465 if( SCIPisLT(scip, domreds->upperbounds[i], SCIPvarGetUbLocal(var)) )
    2466 {
    2467 /* apply upper bound */
    2468#ifdef SCIP_DEBUG
    2469 oldbound = SCIPvarGetUbLocal(var);
    2470#endif
    2471 proposedbound = domreds->upperbounds[i];
    2472
    2473 if( config->onlyvioldomreds && SCIPisLE(scip, baselpval, proposedbound) )
    2474 continue;
    2475
    2476 /* add the new bound */
    2477 SCIP_CALL( SCIPtightenVarUb(scip, var, proposedbound, TRUE, &infeasible, &tightened) );
    2478
    2479#if defined(SCIP_DEBUG) || defined(SCIP_STATISTIC)
    2480 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Variable <%s>, old upper bound <%g>, proposed upper bound <%g>, new "
    2481 "upper bound <%g>\n", SCIPvarGetName(var), oldbound, proposedbound, SCIPvarGetUbLocal(var));
    2482#endif
    2483
    2484 if( infeasible )
    2485 {
    2486 /* the domain reduction may result in an empty model (ub < lb) */
    2487 *domredcutoff = TRUE;
    2488 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The domain reduction of variable <%s> resulted in an empty "
    2489 "model.\n", SCIPvarGetName(var));
    2490 }
    2491 else if( tightened )
    2492 {
    2493 /* the ub is now strictly smaller than before */
    2494 *domred = TRUE;
    2495#if defined(SCIP_DEBUG) || defined(SCIP_STATISTIC)
    2496 nboundsadded++;
    2497#endif
    2498#ifdef SCIP_STATISTIC
    2499 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The upper bound of variable <%s> was successfully tightened (%d).\n",
    2500 SCIPvarGetName(var), domreds->upperboundnproofs[i]);
    2501 statistics->ndomredproofnodes += domreds->upperboundnproofs[i];
    2502#endif
    2503
    2504#if defined(SCIP_DEBUG) || defined(SCIP_STATISTIC)
    2505 if( SCIPisGT(scip, baselpval, SCIPvarGetUbLocal(var)) )
    2506 {
    2507 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The upper bound of variable <%s> is violated by the base lp "
    2508 "value <%g>.\n", SCIPvarGetName(var), baselpval);
    2509
    2510 nboundsaddedvio++;
    2511 }
    2512#endif
    2513 }
    2514 }
    2515 }
    2516
    2517#ifdef SCIP_STATISTIC
    2518 statistics->ndomred += nboundsadded;
    2519 statistics->ndomredvio += nboundsaddedvio;
    2520#endif
    2521
    2522 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Truly changed <%d> domains of the problem, <%d> of them are violated by the "
    2523 "base lp.\n", nboundsadded, nboundsaddedvio);
    2524 return SCIP_OKAY;
    2525}
    2526
    2527/** Copies the current LP solution into the given pointer. Needs to be freed after usage! */
    2528static
    2530 SCIP* scip, /**< SCIP data structure */
    2531 SCIP_SOL** lpsol /**< pointer to store the solution into */
    2532 )
    2533{
    2534 assert(scip != NULL);
    2535 assert(lpsol != NULL);
    2536
    2537 /* create temporary solution */
    2538 SCIP_CALL( SCIPcreateLPSol(scip, lpsol, NULL) );
    2539
    2540 /* unlink the solution, so that newly solved lps don't have any influence on our copy */
    2541 SCIP_CALL( SCIPunlinkSol(scip, *lpsol) );
    2542
    2543 return SCIP_OKAY;
    2544}
    2545
    2546/** Executes the branching on a given variable with a given value. */
    2547static
    2549 SCIP* scip /**< SCIP data structure */,
    2550 CONFIGURATION* config, /**< config struct with the user configuration */
    2551 BRANCHINGDECISION* decision /**< the decision with all the needed data */
    2552 )
    2553{
    2554 SCIP_VAR* bestvar;
    2555 SCIP_Real bestval;
    2556 SCIP_NODE* downchild = NULL;
    2557 SCIP_NODE* upchild = NULL;
    2558
    2559 assert(scip != NULL);
    2560 assert(decision != NULL);
    2561 assert(config != NULL);
    2562
    2563 bestvar = decision->branchvar;
    2564 bestval = decision->branchval;
    2565 assert(bestvar != NULL);
    2566
    2567 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Effective branching on var <%s> with value <%g(%g)>. Old domain: [%g..%g].\n",
    2568 SCIPvarGetName(bestvar), bestval, SCIPgetSolVal(scip, NULL, bestvar), SCIPvarGetLbLocal(bestvar), SCIPvarGetUbLocal(bestvar));
    2569
    2570 assert(!SCIPisIntegral(scip, bestval));
    2571
    2572 /* branch on the given variable */
    2573 assert(SCIPisLT(scip, SCIPvarGetLbLocal(bestvar), bestval));
    2574 assert(SCIPisLT(scip, bestval, SCIPvarGetUbLocal(bestvar)));
    2575 SCIP_CALL( SCIPbranchVarVal(scip, bestvar, bestval, &downchild, NULL, &upchild) );
    2576
    2577 SCIPdebugMsg(scip, "down child (node %" SCIP_LONGINT_FORMAT "): branching bound change <%s> <= %g\n",
    2578 SCIPnodeGetNumber(downchild), SCIPvarGetName(bestvar), SCIPfeasFloor(scip, bestval));
    2579 SCIPdebugMsg(scip, "up child (node %" SCIP_LONGINT_FORMAT "): branching bound change <%s> >= %g\n",
    2580 SCIPnodeGetNumber(upchild), SCIPvarGetName(bestvar), SCIPfeasCeil(scip, bestval));
    2581
    2582 assert(downchild != NULL);
    2583 assert(upchild != NULL);
    2584
    2585 /* update the lower bounds in the children; we must not do this if columns are missing in the LP
    2586 * (e.g., because we are doing branch-and-price) or the problem should be solved exactly */
    2588 {
    2589 /* update the lower bound for the LPs for further children of both created nodes */
    2590 if( decision->downdbvalid )
    2591 {
    2592 SCIP_CALL( SCIPupdateNodeLowerbound(scip, downchild, decision->downdb) );
    2593 }
    2594 if( decision->updbvalid )
    2595 {
    2596 SCIP_CALL( SCIPupdateNodeLowerbound(scip, upchild, decision->updb) );
    2597 }
    2598
    2599 if( decision->boundsvalid && config->applychildbounds )
    2600 {
    2601 SCIP_VAR** vars;
    2602 int nvars;
    2603 int i;
    2604
    2605 assert(decision->downlowerbounds != NULL);
    2606 assert(decision->downupperbounds != NULL);
    2607 assert(decision->uplowerbounds != NULL);
    2608 assert(decision->upupperbounds != NULL);
    2609
    2610 nvars = SCIPgetNVars(scip);
    2611 vars = SCIPgetVars(scip);
    2612
    2613 assert(nvars == decision->boundssize);
    2614
    2615 for( i = 0; i < nvars; i++ )
    2616 {
    2617 SCIP_VAR* var = vars[i];
    2618 SCIP_Real currentlb;
    2619 SCIP_Real currentub;
    2620 SCIP_Real newlb = decision->downlowerbounds[i];
    2621 SCIP_Real newub = decision->downupperbounds[i];
    2622 assert(var != NULL);
    2623
    2624 currentlb = SCIPvarGetLbLocal(var);
    2625 currentub = SCIPvarGetUbLocal(var);
    2626
    2627 /* update the lower bound of the lower child in case it is better than the current one */
    2628 if( SCIPisGT(scip, newlb, currentlb) )
    2629 {
    2630 SCIP_CALL( SCIPchgVarLbNode(scip, downchild, var, newlb) );
    2631
    2632 SCIPdebugMsg(scip, "down child (node %" SCIP_LONGINT_FORMAT "): add bound change <%s> >= %g\n",
    2633 SCIPnodeGetNumber(downchild), SCIPvarGetName(var), newlb);
    2634 }
    2635
    2636 /* update the upper bound of the lower child in case it is better than the current one AND it is not the
    2637 * branching variable, as its upper bound is already updated
    2638 */
    2639 if( SCIPisLT(scip, newub, currentub) && var != bestvar )
    2640 {
    2641 SCIP_CALL( SCIPchgVarUbNode(scip, downchild, var, newub) );
    2642
    2643 SCIPdebugMsg(scip, "down child (node %" SCIP_LONGINT_FORMAT "): add bound change <%s> <= %g\n",
    2644 SCIPnodeGetNumber(downchild), SCIPvarGetName(var), newub);
    2645 }
    2646
    2647 newlb = decision->uplowerbounds[i];
    2648 newub = decision->upupperbounds[i];
    2649
    2650 /* update the lower bound of the upper child in case it is better than the current one AND it is not the
    2651 * branching variable, as its lower bound is already updated
    2652 */
    2653 if( SCIPisGT(scip, newlb, currentlb) && var != bestvar)
    2654 {
    2655 SCIP_CALL( SCIPchgVarLbNode(scip, upchild, var, newlb) );
    2656
    2657 SCIPdebugMsg(scip, "up child (node %" SCIP_LONGINT_FORMAT "): add bound change <%s> >= %g\n",
    2658 SCIPnodeGetNumber(upchild), SCIPvarGetName(var), newlb);
    2659 }
    2660
    2661 /* update the upper bound of the upper child in case it is better than the current one */
    2662 if( SCIPisLT(scip, newub, currentub) )
    2663 {
    2664 SCIP_CALL( SCIPchgVarUbNode(scip, upchild, var, newub) );
    2665
    2666 SCIPdebugMsg(scip, "up child (node %" SCIP_LONGINT_FORMAT "): add bound change <%s> <= %g\n",
    2667 SCIPnodeGetNumber(upchild), SCIPvarGetName(var), newub);
    2668 }
    2669 }
    2670 }
    2671 }
    2672 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, " -> down child's lowerbound: %.9g, estimate: %.9g\n",
    2673 SCIPnodeGetLowerbound(downchild), SCIPnodeGetEstimate(downchild));
    2674 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, " -> up child's lowerbound: %.9g, estimate: %.9g\n",
    2675 SCIPnodeGetLowerbound(upchild), SCIPnodeGetEstimate(upchild));
    2676
    2677 return SCIP_OKAY;
    2678}
    2679
    2680/** Get the number of iterations the last LP needed */
    2681static
    2683 SCIP* scip, /**< SCIP data structure */
    2684 SCIP_Longint* iterations /**< pointer to store the number of iterations */
    2685 )
    2686{
    2687 SCIP_LPI* lpi;
    2688 int tmpiter;
    2689
    2690 assert(scip != NULL);
    2691 assert(iterations != NULL);
    2692
    2693 /* get the LP interface of the last solved LP */
    2694 SCIP_CALL( SCIPgetLPI(scip, &lpi) );
    2695
    2696 /* get the number of iterations from the interface */
    2697 SCIP_CALL( SCIPlpiGetIterations(lpi, &tmpiter) );
    2698
    2699 *iterations = (SCIP_Longint)tmpiter;
    2700
    2701 return SCIP_OKAY;
    2702}
    2703
    2704/** Creates a new probing node with a new bound for the given candidate and solves the corresponding LP. */
    2705static
    2707 SCIP* scip, /**< SCIP data structure */
    2708 CONFIGURATION* config, /**< configuration to control the behavior */
    2709 SCIP_Bool downbranching, /**< the branching direction */
    2710 CANDIDATE* candidate, /**< the candidate to branch on */
    2711 BRANCHINGRESULTDATA* resultdata, /**< pointer to the result data which gets filled with the status */
    2712 SCIP_SOL* baselpsol, /**< the base lp solution */
    2713 DOMAINREDUCTIONS* domreds, /**< struct to store the domain reduction found during propagation */
    2714 STATUS* status /**< status will contain updated lperror and limit fields */
    2715 )
    2716{
    2717 SCIP_Real oldupperbound;
    2718 SCIP_Real oldlowerbound;
    2719 SCIP_Real newbound;
    2720 SCIP_LPSOLSTAT solstat;
    2721 SCIP_VAR* branchvar;
    2722 SCIP_Real branchval;
    2723
    2724 assert(scip != NULL);
    2725 assert(candidate != NULL);
    2726 assert(resultdata != NULL);
    2727 assert(status != NULL);
    2728 assert(config != NULL);
    2729 assert(status != NULL);
    2730
    2731 branchvar = candidate->branchvar;
    2732 branchval = candidate->branchval;
    2733
    2734 assert(branchvar != NULL);
    2735 assert(!SCIPisFeasIntegral(scip, branchval));
    2736
    2737 if( downbranching )
    2738 {
    2739 /* round the given value down, so that it can be used as the new upper bound */
    2740 newbound = SCIPfeasFloor(scip, branchval);
    2741 }
    2742 else
    2743 {
    2744 /* round the given value up, so that it can be used as the new lower bound */
    2745 newbound = SCIPfeasCeil(scip, branchval);
    2746 }
    2747
    2748 oldupperbound = SCIPvarGetUbLocal(branchvar);
    2749 oldlowerbound = SCIPvarGetLbLocal(branchvar);
    2750
    2751#ifdef SCIP_DEBUG
    2752 if( downbranching )
    2753 {
    2754 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "DownBranching: Var=<%s>, Proposed upper bound=<%g>, "
    2755 "old bounds=[<%g>..<%g>], new bounds=[<%g>..<%g>]\n", SCIPvarGetName(branchvar), newbound, oldlowerbound,
    2756 oldupperbound, oldlowerbound, newbound);
    2757 }
    2758 else
    2759 {
    2760 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "UpBranching: Var=<%s>, Proposed lower bound=<%g>, "
    2761 "old bounds=[<%g>..<%g>], new bounds=[<%g>..<%g>]\n", SCIPvarGetName(branchvar), newbound, oldlowerbound,
    2762 oldupperbound, newbound, oldupperbound);
    2763 }
    2764#endif
    2765
    2766 if( (downbranching && newbound < oldlowerbound - 0.5)
    2767 || (!downbranching && newbound > oldupperbound + 0.5) )
    2768 {
    2769 /* if lb > ub we can cutoff this node */
    2770 resultdata->cutoff = TRUE;
    2771
    2772 return SCIP_OKAY;
    2773 }
    2774
    2775 assert(!resultdata->cutoff);
    2776
    2778
    2779 if( downbranching )
    2780 {
    2781 /* down branching preparations */
    2782 if( SCIPisFeasLT(scip, newbound, oldupperbound) )
    2783 {
    2784 /* If the new upper bound is smaller than the old upper bound and also
    2785 * greater than (or equal to) the old lower bound, we set the new upper bound.
    2786 * oldLowerBound <= newUpperBound < oldUpperBound */
    2787 SCIP_CALL( SCIPchgVarUbProbing(scip, branchvar, newbound) );
    2788 }
    2789 }
    2790 else
    2791 {
    2792 /* up branching preparations */
    2793 if( SCIPisFeasGT(scip, newbound, oldlowerbound) )
    2794 {
    2795 /* If the new lower bound is greater than the old lower bound and also
    2796 * smaller than (or equal to) the old upper bound, we set the new lower bound.
    2797 * oldLowerBound < newLowerBound <= oldUpperBound
    2798 */
    2799 SCIP_CALL( SCIPchgVarLbProbing(scip, branchvar, newbound) );
    2800 }
    2801 }
    2802
    2803 /* restore the stored LP data (e.g., the basis) from a filtering run */
    2804 if( candidateHasWarmStartInfo(candidate, downbranching) )
    2805 {
    2806 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Restoring lp information for %s branch of variable <%s>\n",
    2807 downbranching ? "down" : "up", SCIPvarGetName(branchvar));
    2808 SCIP_CALL( candidateLoadWarmStartInfo(scip, candidate, downbranching) );
    2809 }
    2810
    2811 /* apply domain propagation */
    2812 if( config->propagate )
    2813 {
    2814 SCIP_Longint ndomredsfound = 0;
    2815
    2816 SCIP_CALL( SCIPpropagateProbing(scip, config->maxproprounds, &resultdata->cutoff, &ndomredsfound) );
    2817
    2818 if( ndomredsfound > 0 )
    2819 {
    2820 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Found %" SCIP_LONGINT_FORMAT " domain reductions via propagation.\n", ndomredsfound);
    2821
    2822 /* domreds != NULL iff config->usedomainreduction */
    2823 if( domreds != NULL )
    2824 {
    2825 int i;
    2826 SCIP_VAR** problemvars = SCIPgetVars(scip);
    2827 int nproblemvars = SCIPgetNVars(scip);
    2828
    2829 assert(problemvars != NULL);
    2830
    2831 assert(config->usedomainreduction);
    2832
    2833 for( i = 0; i < nproblemvars; i++ )
    2834 {
    2835 SCIP_Real lowerbound;
    2836 SCIP_Real upperbound;
    2837 SCIP_VAR* var = problemvars[i];
    2838 assert(var != NULL);
    2839
    2840 lowerbound = SCIPvarGetLbLocal(var);
    2841 upperbound = SCIPvarGetUbLocal(var);
    2842#ifdef SCIP_STATISTIC
    2843 addLowerBound(scip, var, lowerbound, baselpsol, FALSE, domreds, 0, FALSE);
    2844 addUpperBound(scip, var, upperbound, baselpsol, FALSE, domreds, 0, FALSE);
    2845#else
    2846 addLowerBound(scip, var, lowerbound, baselpsol, FALSE, domreds);
    2847 addUpperBound(scip, var, upperbound, baselpsol, FALSE, domreds);
    2848#endif
    2849 }
    2850 }
    2851 }
    2852 }
    2853
    2854 if( !resultdata->cutoff )
    2855 {
    2856 /* solve the prepared probing LP */
    2857 SCIP_CALL( SCIPsolveProbingLP(scip, -1, &status->lperror, &resultdata->cutoff) );
    2858
    2859 /* store the number of iterations needed */
    2861
    2862 solstat = SCIPgetLPSolstat(scip);
    2863 assert(solstat != SCIP_LPSOLSTAT_UNBOUNDEDRAY);
    2864
    2865 /* for us an error occurred, if an error during the solving occurred or the lp could not be solved but was not
    2866 * cutoff */
    2867 status->lperror = status->lperror || (solstat == SCIP_LPSOLSTAT_NOTSOLVED && resultdata->cutoff == FALSE);
    2868
    2869 /* if we seem to have reached a {time, iteration}-limit or the user cancelled the execution, we want to stop
    2870 * further calculations and instead return the current calculation state */
    2871 status->limitreached = (solstat == SCIP_LPSOLSTAT_ITERLIMIT) || (solstat == SCIP_LPSOLSTAT_TIMELIMIT);
    2872
    2873 if( resultdata->cutoff )
    2874 {
    2875 resultdata->objval = SCIPinfinity(scip);
    2876 resultdata->dualbound = SCIPinfinity(scip);
    2877 resultdata->dualboundvalid = TRUE;
    2878 }
    2879 else if( !status->limitreached && !status->lperror )
    2880 {
    2881 SCIP_Bool foundsol = FALSE;
    2882
    2883 SCIP_CALL( SCIPtryStrongbranchLPSol(scip, &foundsol, &resultdata->cutoff) );
    2884
    2885 /* if we have no error, we save the new objective value and the cutoff decision in the resultdata */
    2886 resultdata->objval = SCIPgetLPObjval(scip);
    2887 resultdata->dualbound = SCIPgetLPObjval(scip);
    2888 resultdata->dualboundvalid = TRUE;
    2889 resultdata->cutoff = resultdata->cutoff || SCIPisGE(scip, resultdata->objval, SCIPgetCutoffbound(scip));
    2890
    2891 assert(solstat != SCIP_LPSOLSTAT_INFEASIBLE || resultdata->cutoff);
    2892 }
    2893 }
    2894
    2895 return SCIP_OKAY;
    2896}
    2897
    2898/** Creates a logic or constraint based on the given 'consvars'. This array has to consist of the negated
    2899 * versions of the variables present on a cutoff "path" (path means all variables from the root directly
    2900 * to the cutoff node).
    2901 * Let x_1, ..., x_n be the variables on a path to a cutoff with the branchings x_i <= 1 for all i.
    2902 * Summed up the constraints would look like x_1 + ... x_n <= n-1.
    2903 * Let y_i = 1 - x_i. Then we have y_1 + ... + y_n >= 1 which is a logic or constraint.
    2904 */
    2905static
    2907 SCIP* scip, /**< SCIP data structure */
    2908 CONFIGURATION* config, /**< configuration containing flags changing the behavior */
    2909 SCIP_CONS** constraint, /**< pointer to store the created constraint in */
    2910 char* constraintname, /**< name of the new constraint */
    2911 SCIP_VAR** consvars, /**< array containing the negated binary vars */
    2912 int nconsvars /**< the number of elements in 'consvars' */
    2913 )
    2914{
    2915 SCIP_Bool initial;
    2917 SCIP_Bool removable;
    2918 SCIP_Bool enforce = FALSE;
    2919 SCIP_Bool check = FALSE;
    2920 SCIP_Bool propagate = TRUE;
    2921 SCIP_Bool local = TRUE;
    2922 SCIP_Bool modifiable = FALSE;
    2923 SCIP_Bool dynamic = FALSE;
    2924 SCIP_Bool stickingatnode = FALSE;
    2925
    2926 assert(scip != NULL);
    2927 assert(config != NULL);
    2928 assert(constraint != NULL);
    2929 assert(constraintname != NULL);
    2930 assert(consvars != NULL);
    2931 assert(nconsvars > 0);
    2932
    2933 initial = (config->addbinconsrow == 2);
    2934 separate = (config->addbinconsrow == 1);
    2935 removable = (config->addbinconsrow == 1);
    2936
    2937 /* creating a logic or constraint based on the list of vars in 'consvars'.
    2938 * A logic or constraints looks like that: y_1 + ... + y_n >= 1.
    2939 */
    2940 SCIP_CALL( SCIPcreateConsLogicor(scip, constraint, constraintname, nconsvars, consvars, initial, separate, enforce,
    2941 check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
    2942 return SCIP_OKAY;
    2943}
    2944
    2945/**
    2946 * Create a name for the binary constraint.
    2947 */
    2948static
    2950 SCIP_VAR** binaryvars, /**< the variables contained in the constraint */
    2951 int nbinaryvars, /**< the number of elements in 'binaryvars' */
    2952 char* constraintname /**< the char pointer to store the name in */
    2953 )
    2954{
    2955 int i;
    2956
    2957 assert(binaryvars != NULL);
    2958 assert(nbinaryvars > 0);
    2959 assert(constraintname != NULL);
    2960 assert(binaryvars[0] != NULL);
    2961
    2962 (void) SCIPsnprintf(constraintname, SCIP_MAXSTRLEN, "lookahead_bin_%s", SCIPvarGetName(binaryvars[0]));
    2963
    2964 for( i = 1; i < nbinaryvars; i++ )
    2965 {
    2966 size_t oldlen;
    2967 SCIP_VAR* var = binaryvars[i];
    2968 assert(var != NULL);
    2969
    2970 oldlen = strlen(constraintname);
    2971 (void) strncat(constraintname, "_", SCIP_MAXSTRLEN-oldlen);
    2972 (void) strncat(constraintname, SCIPvarGetName(var), SCIP_MAXSTRLEN-oldlen-1);
    2973 }
    2974}
    2975
    2976/**
    2977 * Add the constraints found during the lookahead branching.
    2978 * The implicit binary bounds were found when two or more consecutive branchings of binary variables were cutoff. Then these
    2979 * branching constraints can be combined into a single 'binary constraint'.
    2980 */
    2981static
    2983 SCIP* scip, /**< SCIP data structure */
    2984 CONFIGURATION* config, /**< the configuration of the branching rule */
    2985 BINCONSDATA* binconsdata, /**< collected binary constraints */
    2986 SCIP_SOL* baselpsol /**< the original lp solution, used to check the violation of the constraint */
    2987#ifdef SCIP_STATISTIC
    2988 ,STATISTICS* statistics /**< statistics data */
    2989#endif
    2990 )
    2991{
    2992 assert(scip != NULL);
    2993 assert(config != NULL);
    2994 assert(binconsdata != NULL);
    2995 assert(baselpsol != NULL);
    2996 assert(binconsdata->binaryvars != NULL);
    2997 assert(binconsdata->binaryvars->nbinaryvars > 0);
    2998
    2999 /* if we only have one var for the constraint, we can ignore it as it is already added as a domain reduction. */
    3000 if( binconsdata->binaryvars->nbinaryvars > 1 )
    3001 {
    3002 int i;
    3003 SCIP_VAR** negatedvars;
    3004 SCIP_Real lhssum = 0.0;
    3005 SCIP_Bool violated;
    3006
    3007 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Adding binary constraint for <%i> vars.\n",
    3008 binconsdata->binaryvars->nbinaryvars);
    3009
    3010 SCIP_CALL( SCIPallocBufferArray(scip, &negatedvars, binconsdata->binaryvars->nbinaryvars) );
    3011
    3012 for( i = 0; i < binconsdata->binaryvars->nbinaryvars; i++ )
    3013 {
    3014 SCIP_VAR* var = binconsdata->binaryvars->binaryvars[i];
    3015 assert(var != NULL);
    3016 assert(SCIPvarIsBinary(var));
    3017
    3018 SCIP_CALL( SCIPgetNegatedVar(scip, var, &negatedvars[i]) );
    3019 lhssum += SCIPgetSolVal(scip, baselpsol, negatedvars[i]);
    3020 }
    3021
    3022 violated = (lhssum < 1);
    3023
    3024 if( config->addnonviocons || violated )
    3025 {
    3026 SCIP_CALL( constraintListAppend(scip, binconsdata->conslist, negatedvars,
    3027 binconsdata->binaryvars->nbinaryvars, violated) );
    3028
    3029 /* the constraint we will be building is a logic or: we have a list of binary variables that were
    3030 * cutoff while we branched on with >= 1. So we have the constraint: x_1 + ... + x_n <= n-1.
    3031 * Let y = (1-x), then we have an equivalent formulation: y_1 + ... + y_n >= 1. If the base lp
    3032 * is violating this constraint we count this for our number of violated constraints and bounds. */
    3033 if( violated )
    3034 binconsdata->conslist->nviolatedcons++;
    3035 }
    3036
    3037 SCIPfreeBufferArray(scip, &negatedvars);
    3038 }
    3039#ifdef SCIP_STATISTIC
    3040 else
    3041 {
    3042 assert(statistics != NULL);
    3043 statistics->ndomredcons++;
    3044 }
    3045#endif
    3046
    3047 return SCIP_OKAY;
    3048}
    3049
    3050/** applies the binary constraints to the original problem. */
    3051static
    3053 SCIP* scip, /**< SCIP data structure */
    3054 SCIP_NODE* basenode, /**< original branching node */
    3055 CONSTRAINTLIST* conslist, /**< list of constraints to be added */
    3056 CONFIGURATION* config, /**< the configuration of the branching rule */
    3057 SCIP_Bool* consadded, /**< pointer to store whether at least one constraint was added */
    3058 SCIP_Bool* cutoff, /**< pointer to store whether the original problem was made infeasible */
    3059 SCIP_Bool* boundchange /**< pointer to store whether a bound change has been applied by adding the
    3060 * constraint as a clique */
    3061#ifdef SCIP_STATISTIC
    3062 ,STATISTICS* statistics /**< statistics data */
    3063#endif
    3064 )
    3065{
    3066 int nconsadded = 0;
    3067 int i;
    3068#ifdef SCIP_STATISTIC
    3069 int nvioconsadded = 0;
    3070
    3071 assert(statistics != NULL);
    3072#endif
    3073 assert(basenode != NULL);
    3074 assert(conslist != NULL);
    3075 assert(config != NULL);
    3076 assert(consadded != NULL);
    3077 assert(cutoff != NULL);
    3078 assert(boundchange != NULL);
    3079
    3080 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "processing %d binary constraints.\n", conslist->nelements);
    3081
    3082 if( conslist->nelements == 0 )
    3083 return SCIP_OKAY;
    3084
    3085 for( i = 0; i < conslist->nelements; i++ )
    3086 {
    3087 SCIP_VAR** vars = conslist->consvars[i];
    3088 int nvars = conslist->nconsvars[i];
    3089 int v;
    3090#ifdef SCIP_STATISTIC
    3091 SCIP_Bool violated = conslist->violated[i];
    3092#endif
    3093
    3094 assert(vars != NULL);
    3095
    3096 for( v = 0; v < nvars; ++v )
    3097 {
    3098 assert(vars[v] != NULL);
    3099 assert(SCIPvarIsBinary(vars[v]));
    3100
    3101 if( SCIPvarGetLbLocal(vars[v]) > 0.5 )
    3102 break;
    3103 }
    3104
    3105 /* no variable is fixed to 1 yet, so constraint is not redundant */
    3106 if( v == nvars )
    3107 {
    3108 SCIP_CONS* constraint;
    3109 char constraintname[SCIP_MAXSTRLEN];
    3110
    3111 /* create a name for the new constraint */
    3112 createBinaryConstraintName(vars, nvars, constraintname);
    3113 /* create the constraint with the freshly created name */
    3114 SCIP_CALL( createBinaryConstraint(scip, config, &constraint, constraintname, vars, nvars) );
    3115
    3116#ifdef PRINTNODECONS
    3117 SCIPinfoMessage(scip, NULL, "Created constraint:\n");
    3118 SCIP_CALL( SCIPprintCons(scip, constraint, NULL) );
    3119 SCIPinfoMessage(scip, NULL, "\n");
    3120#endif
    3121 /* add the constraint to the given node */
    3122 SCIP_CALL( SCIPaddConsNode(scip, basenode, constraint, NULL) );
    3123
    3124 nconsadded++;
    3125
    3126#ifdef SCIP_STATISTIC
    3127 if( violated )
    3128 nvioconsadded++;
    3129#endif
    3130
    3131 /* release the constraint, as it is no longer needed */
    3132 SCIP_CALL( SCIPreleaseCons(scip, &constraint) );
    3133
    3134 /* a 2-variable logicor constraint can be expressend as a clique on the negated variables;
    3135 * add it to the clique table if we are at the root node */
    3136 if( nvars == 2 && config->addclique && SCIPgetNNodes(scip) == 1 )
    3137 {
    3138 SCIP_Bool* values;
    3139 SCIP_Bool infeasible;
    3140 int nbdchgs;
    3141
    3142 SCIP_CALL( SCIPallocClearBufferArray(scip, &values, nvars) );
    3143
    3144 /* a two-variable logicor constraint x + y >= 1 yields the implication x == 0 -> y == 1, and is represented
    3145 * by the clique inequality ~x + ~y <= 1
    3146 */
    3147 SCIP_CALL( SCIPaddClique(scip, vars, values, nvars, FALSE, &infeasible, &nbdchgs) );
    3148
    3149#ifdef SCIP_STATISTIC
    3150 statistics->ncliquesadded++;
    3151#endif
    3152
    3153 if( infeasible )
    3154 *cutoff = TRUE;
    3155
    3156 if( nbdchgs > 0 )
    3157 *boundchange = TRUE;
    3158
    3159 SCIPfreeBufferArray(scip, &values);
    3160 }
    3161 }
    3162 }
    3163
    3164 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "added %d/%d binary constraints.\n", nconsadded, conslist->nelements);
    3165
    3166 if( nconsadded > 0 )
    3167 {
    3168 *consadded = TRUE;
    3169
    3170#ifdef SCIP_STATISTIC
    3171 statistics->nbinconst += nconsadded;
    3172 statistics->nbinconstvio += nvioconsadded;
    3173#endif
    3174 }
    3175
    3176 return SCIP_OKAY;
    3177}
    3178
    3179/** checks whether the given bounds are still the bounds of the given variable */
    3180static
    3182 SCIP* scip, /**< SCIP data structure */
    3183 SCIP_VAR* var, /**< variable to check the bounds of */
    3184 SCIP_Real lowerbound, /**< reference lower bound */
    3185 SCIP_Real upperbound /**< reference upper bound */
    3186 )
    3187{
    3188 assert(scip != NULL);
    3189 assert(var != NULL);
    3190 assert(SCIPisFeasIntegral(scip, lowerbound));
    3191 assert(SCIPisFeasIntegral(scip, upperbound));
    3192 assert(!SCIPisEQ(scip, lowerbound, upperbound));
    3193 assert(SCIPvarIsIntegral(var));
    3194
    3195 /* due to roundings the value might have changed slightly without an actual influence on the integral value */
    3196 return SCIPvarGetLbLocal(var) > lowerbound + 0.5 || SCIPvarGetUbLocal(var) < upperbound - 0.5;
    3197}
    3198
    3199/** Checks whether the branching rule should continue or terminate with the currently gathered data */
    3200static
    3202 STATUS* status, /**< current status */
    3203 SCIP_Bool checkdomreds /**< should domain reductions be checked? */
    3204 )
    3205{
    3206 assert(status != NULL);
    3207
    3208 return !status->lperror && !status->cutoff && !status->limitreached
    3209 && !status->maxnconsreached && (!checkdomreds || !status->domred);
    3210}
    3211
    3212/** Checks whether the branching rule should continue or terminate with the currently gathered data. Additionally decrements
    3213 * the given loopcounter. This is needed to better emulate the behavior of FSB by LAB with a depth of 1. */
    3214static
    3216 STATUS* status, /**< current status */
    3217 int* loopcounter /**< the counter to decrement */
    3218 )
    3219{
    3220 SCIP_Bool branchfurther;
    3221
    3222 assert(status != NULL);
    3223 assert(loopcounter != NULL);
    3224
    3225 branchfurther = isBranchFurther(status, FALSE);
    3226
    3227 if( !branchfurther )
    3228 (*loopcounter)--;
    3229
    3230 return branchfurther;
    3231}
    3232
    3233/** determines whether the previous LAB result of a variable should be reused */
    3234static
    3236 SCIP* scip, /**< SCIP data structure */
    3237 PERSISTENTDATA* persistent, /**< data storage over multiple calls to the rule */
    3238 CONFIGURATION* config, /**< the configuration of the branching rule */
    3239 SCIP_VAR* branchvar /**< variable to check */
    3240 )
    3241{
    3242 assert(scip != NULL);
    3243 assert(config != NULL);
    3244 assert(branchvar != NULL);
    3245
    3246 /* an old branching can be reused, if we are still at the same node and just a few LPs were solved in between */
    3247 if( config->inscoring )
    3248 {
    3249 return SCIPgetVarStrongbranchNode(scip, branchvar) == SCIPgetNNodes(scip)
    3250 && SCIPgetVarStrongbranchLPAge(scip, branchvar) < config->reevalagefsb;
    3251 }
    3252 else
    3253 {
    3254 return persistent->lastbranchid[SCIPvarGetProbindex(branchvar)] == SCIPgetNNodes(scip)
    3255 && SCIPgetNLPs(scip) - persistent->lastbranchnlps[SCIPvarGetProbindex(branchvar)] < config->reevalage;
    3256 }
    3257}
    3258
    3259/** retrieves previous LAB result for the given variable */
    3260static
    3262 SCIP* scip, /**< SCIP data structure */
    3263 PERSISTENTDATA* persistent, /**< data storage over multiple calls to the rule */
    3264 CONFIGURATION* config, /**< the configuration of the branching rule */
    3265 SCIP_VAR* branchvar, /**< variable to get previous results for */
    3266 BRANCHINGRESULTDATA* downbranchingresult,/**< pointer to store the previous down result in */
    3267 BRANCHINGRESULTDATA* upbranchingresult, /**< pointer to store the previous up result in */
    3268 SCIP_Real* oldlpobjval /**< pointer to store the previous base lp objval in */
    3269 )
    3270{
    3271 assert(scip != NULL);
    3272 assert(persistent != NULL);
    3273 assert(branchvar != NULL);
    3274 assert(downbranchingresult != NULL);
    3275 assert(upbranchingresult != NULL);
    3276 assert(oldlpobjval != NULL);
    3277
    3278 if( config->inscoring )
    3279 {
    3280 SCIP_CALL( SCIPgetVarStrongbranchLast(scip, branchvar, &downbranchingresult->dualbound, &upbranchingresult->dualbound,
    3281 &downbranchingresult->dualboundvalid, &upbranchingresult->dualboundvalid, NULL, oldlpobjval) );
    3282 downbranchingresult->objval = downbranchingresult->dualbound;
    3283 upbranchingresult->objval = upbranchingresult->dualbound;
    3284 }
    3285 else
    3286 {
    3287 int varindex = SCIPvarGetProbindex(branchvar);
    3288
    3289 branchingResultDataCopy(persistent->lastbranchdownres[varindex], downbranchingresult);
    3290 branchingResultDataCopy(persistent->lastbranchupres[varindex], upbranchingresult);
    3291 *oldlpobjval = persistent->lastbranchlpobjval[varindex];
    3292 }
    3293
    3294#ifdef SCIP_DEBUG
    3295 {
    3296 SCIP_Real downgain;
    3297 SCIP_Real upgain;
    3298
    3299 downgain = MAX(downbranchingresult->dualbound - *oldlpobjval, 0);
    3300 upgain = MAX(upbranchingresult->dualbound - *oldlpobjval, 0);
    3301
    3302 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Lookahead branching on variable <%s> already performed (lpage=%"
    3303 SCIP_LONGINT_FORMAT ", down=%.9g (%+g), up=%.9g (%+g))\n", SCIPvarGetName(branchvar),
    3304 SCIPgetNLPs(scip) - persistent->lastbranchnlps[SCIPvarGetProbindex(branchvar)],
    3305 downbranchingresult->dualbound, downgain, upbranchingresult->dualbound, upgain);
    3306 }
    3307#endif
    3308
    3309 return SCIP_OKAY;
    3310}
    3311
    3312/** stores the LAB result for use in a later call to the branching rule */
    3313static
    3315 SCIP* scip, /**< SCIP data structure */
    3316 PERSISTENTDATA* persistent, /**< data storage over multiple calls to the rule */
    3317 CONFIGURATION* config, /**< the configuration of the branching rule */
    3318 SCIP_VAR* branchvar, /**< variable to store previous results for */
    3319 SCIP_Real branchval, /**< the value of branchvar */
    3320 BRANCHINGRESULTDATA* downbranchingresult,/**< down branching result to store */
    3321 BRANCHINGRESULTDATA* upbranchingresult, /**< up branching result to store */
    3322 SCIP_Real lpobjval /**< base lp obj val */
    3323 )
    3324{
    3325 assert(scip != NULL);
    3326 assert(persistent != NULL);
    3327 assert(branchvar != NULL);
    3328 assert(downbranchingresult != NULL);
    3329 assert(upbranchingresult != NULL);
    3330
    3331 if( config->inscoring )
    3332 {
    3333 SCIP_Longint niterations = downbranchingresult->niterations + upbranchingresult->niterations;
    3334
    3335 SCIP_CALL( SCIPsetVarStrongbranchData(scip, branchvar, lpobjval, branchval, downbranchingresult->dualbound,
    3336 upbranchingresult->dualbound, downbranchingresult->dualboundvalid, upbranchingresult->dualboundvalid, niterations,
    3337 INT_MAX) );
    3338 }
    3339 else
    3340 {
    3341 int varindex = SCIPvarGetProbindex(branchvar);
    3342
    3343 branchingResultDataCopy(downbranchingresult, persistent->lastbranchdownres[varindex]);
    3344 branchingResultDataCopy(upbranchingresult, persistent->lastbranchupres[varindex]);
    3345 persistent->lastbranchlpobjval[varindex] = lpobjval;
    3346 persistent->lastbranchid[varindex] = SCIPgetNNodes(scip);
    3347 persistent->lastbranchnlps[varindex] = SCIPgetNLPs(scip);
    3348 }
    3349
    3350 return SCIP_OKAY;
    3351}
    3352
    3353/** calculates the FSB scores for the given candidates */
    3354static
    3356 SCIP* scip, /**< SCIP data structure */
    3357 STATUS* status, /**< current status */
    3358 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
    3359 CONFIGURATION* config, /**< the configuration of the branching rule */
    3360 SCIP_SOL* baselpsol, /**< base lp solution */
    3361 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
    3362 BINCONSDATA* binconsdata, /**< container collecting all binary constraints; or NULL */
    3363 CANDIDATELIST* candidatelist, /**< list containing all candidates to consider */
    3364 BRANCHINGDECISION* decision, /**< struct to store the final decision */
    3365 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
    3366 LEVEL2DATA* level2data, /**< level 2 LP results data */
    3367 SCIP_Real lpobjval /**< base LP objective value */
    3368#ifdef SCIP_STATISTIC
    3369 ,STATISTICS* statistics /**< general statistical data */
    3370 ,LOCALSTATISTICS* localstats /**< local statistics, may be disregarded */
    3371#endif
    3372 )
    3373{
    3374 assert(scip != NULL);
    3375 assert(config != NULL);
    3376 assert(candidatelist != NULL);
    3377 assert(status != NULL);
    3378 assert(scorecontainer != NULL);
    3379 assert(SCIPinProbing(scip));
    3381
    3382 /* inform configuration that we are in scoring mode now */
    3383 config->inscoring = TRUE;
    3384
    3385#ifdef SCIP_STATISTIC
    3386 SCIP_CALL( selectVarRecursive(scip, status, persistent, config, baselpsol, domainreductions,
    3387 binconsdata, candidatelist, decision, scorecontainer, level2data, 1,
    3388 lpobjval, lpobjval, NULL, NULL, NULL, NULL, NULL, NULL,
    3389 statistics, localstats, NULL, NULL) );
    3390#else
    3391 SCIP_CALL( selectVarRecursive(scip, status, persistent, config, baselpsol, domainreductions,
    3392 binconsdata, candidatelist, decision, scorecontainer, level2data, 1,
    3393 lpobjval, lpobjval, NULL, NULL, NULL, NULL, NULL, NULL) );
    3394#endif
    3395
    3396 /* inform configuration that we leave scoring mode now */
    3397 config->inscoring = FALSE;
    3398
    3399 return SCIP_OKAY;
    3400}
    3401
    3402#ifdef SCIP_DEBUG
    3403/** prints the given candidate list */
    3404static
    3405void printCandidates(
    3406 SCIP* scip, /**< SCIP data structure */
    3407 SCIP_VERBLEVEL lvl, /**< verbosity level to print the list in */
    3408 CANDIDATELIST* candidatelist /**< the list to be printed */
    3409 )
    3410{
    3411 int ncands;
    3412 int i;
    3413
    3414 assert(scip != NULL);
    3415 assert(candidatelist != NULL);
    3416
    3417 ncands = candidatelist->ncandidates;
    3418
    3419 LABdebugMessagePrint(scip, lvl, "[");
    3420
    3421 for( i = 0; i < ncands; i++ )
    3422 {
    3423 CANDIDATE* cand = candidatelist->candidates[i];
    3424
    3425 assert(cand != NULL);
    3426 assert(cand->branchvar != NULL);
    3427
    3428 LABdebugMessagePrint(scip, lvl, "%s", SCIPvarGetName(cand->branchvar));
    3429 if(i != ncands-1)
    3430 {
    3431 LABdebugMessagePrint(scip, lvl, ", ");
    3432 }
    3433 }
    3434 LABdebugMessagePrint(scip, lvl, "]\n");
    3435}
    3436#endif
    3437
    3438/** calculates the score based on the down and up branching result */
    3439static
    3441 SCIP* scip, /**< SCIP data structure */
    3442 SCIP_VAR* branchvar, /**< variable to get the score for */
    3443 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
    3444 BRANCHINGRESULTDATA* upbranchingresult, /**< branching result of the up branch */
    3445 SCIP_Real lpobjval /**< objective value to get difference to as gain */
    3446 )
    3447{
    3448 SCIP_Real score;
    3449 SCIP_Real downgain = SCIPsumepsilon(scip);
    3450 SCIP_Real upgain = SCIPsumepsilon(scip);
    3451
    3452 assert(scip != NULL);
    3453 assert(branchvar != NULL);
    3454 assert(downbranchingresult != NULL);
    3455 assert(upbranchingresult != NULL);
    3456
    3457 /* the gain is the difference of the dualbound of a child and the reference objective value;
    3458 * by bounding it by zero we are safe from numerical troubles
    3459 */
    3460 if( !downbranchingresult->cutoff )
    3461 downgain = MAX(downgain, downbranchingresult->dualbound - lpobjval);
    3462 if( !upbranchingresult->cutoff )
    3463 upgain = MAX(upgain, upbranchingresult->dualbound - lpobjval);
    3464
    3465 downgain = 100.0 * downgain;
    3466 upgain = 100.0 * upgain;
    3467
    3468 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
    3469 * realistic gain for the infeasible child;
    3470 * if both children are infeasible we just reset the initial zero values again
    3471 */
    3472 if( downbranchingresult->cutoff )
    3473 downgain = 2 * upgain;
    3474 if( upbranchingresult->cutoff )
    3475 upgain = 2 * downgain;
    3476
    3477 score = SCIPgetBranchScore(scip, branchvar, downgain, upgain);
    3478
    3479 return score;
    3480}
    3481
    3482/** calculates the score based on the down and up branching result */
    3483static
    3485 SCIP* scip, /**< SCIP data structure */
    3486 SCIP_VAR* branchvar, /**< variable to get the score for */
    3487 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
    3488 BRANCHINGRESULTDATA* upbranchingresult, /**< branching result of the up branch */
    3489 SCIP_Real lpobjval /**< objective value to get difference to as gain */
    3490 )
    3491{
    3492 SCIP_Real lpscore;
    3493 SCIP_Real dbscore;
    3494 SCIP_Real score;
    3495 SCIP_Real downgain = SCIPsumepsilon(scip);
    3496 SCIP_Real upgain = SCIPsumepsilon(scip);
    3497
    3498 assert(scip != NULL);
    3499 assert(branchvar != NULL);
    3500 assert(downbranchingresult != NULL);
    3501 assert(upbranchingresult != NULL);
    3502
    3503 /* the gain is the difference of the dualbound of a child and the reference objective value;
    3504 * by bounding it by zero we are safe from numerical troubles
    3505 */
    3506 if( !downbranchingresult->cutoff )
    3507 downgain = MAX(downgain, downbranchingresult->objval - lpobjval);
    3508 if( !upbranchingresult->cutoff )
    3509 upgain = MAX(upgain, upbranchingresult->objval - lpobjval);
    3510
    3511 downgain = 100.0 * downgain;
    3512 upgain = 100.0 * upgain;
    3513
    3514 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
    3515 * realistic gain for the infeasible child;
    3516 * if both children are infeasible we just reset the initial zero values again
    3517 */
    3518 if( downbranchingresult->cutoff )
    3519 downgain = 2 * upgain;
    3520 if( upbranchingresult->cutoff )
    3521 upgain = 2 * downgain;
    3522
    3523 lpscore = SCIPgetBranchScore(scip, branchvar, downgain, upgain);
    3524
    3525 /* the gain is the difference of the dualbound of a child and the reference objective value;
    3526 * by bounding it by zero we are safe from numerical troubles
    3527 */
    3528 if( !downbranchingresult->cutoff )
    3529 downgain = MAX(SCIPsumepsilon(scip), downbranchingresult->dualbound - lpobjval); /*lint !e666*/
    3530 if( !upbranchingresult->cutoff )
    3531 upgain = MAX(SCIPsumepsilon(scip), upbranchingresult->dualbound - lpobjval); /*lint !e666*/
    3532
    3533 downgain = 100.0 * downgain;
    3534 upgain = 100.0 * upgain;
    3535
    3536 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
    3537 * realistic gain for the infeasible child;
    3538 * if both children are infeasible we just reset the initial zero values again
    3539 */
    3540 if( downbranchingresult->cutoff )
    3541 downgain = 2 * upgain;
    3542 if( upbranchingresult->cutoff )
    3543 upgain = 2 * downgain;
    3544
    3545 dbscore = SCIPgetBranchScore(scip, branchvar, downgain, upgain);
    3546
    3547 score = SCIPgetBranchScore(scip, branchvar, lpscore, dbscore);
    3548
    3549 return score;
    3550}
    3551
    3552/** calculates the score based on the down and up branching scores */
    3553static
    3555 SCIP* scip, /**< SCIP data structure */
    3556 SCIP_VAR* branchvar, /**< variable to get the score for */
    3557 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
    3558 BRANCHINGRESULTDATA* upbranchingresult /**< branching result of the up branch */
    3559 )
    3560{
    3561 SCIP_Real score;
    3562 SCIP_Real downscore;
    3563 SCIP_Real upscore;
    3564
    3565 assert(scip != NULL);
    3566 assert(branchvar != NULL);
    3567 assert(downbranchingresult != NULL);
    3568 assert(upbranchingresult != NULL);
    3569
    3570 assert(downbranchingresult->deeperscore >= -0.2 || downbranchingresult->cutoff || SCIPisStopped(scip));
    3571 assert(upbranchingresult->deeperscore >= -0.2 || upbranchingresult->cutoff || SCIPisStopped(scip));
    3572
    3573 downscore = sqrt(downbranchingresult->deeperscore);
    3574 upscore = sqrt(upbranchingresult->deeperscore);
    3575
    3576 downscore = MAX(downscore, SCIPsumepsilon(scip)); /*lint !e666*/
    3577 upscore = MAX(upscore, SCIPsumepsilon(scip)); /*lint !e666*/
    3578
    3579 if( downbranchingresult->cutoff )
    3580 downscore = 2 * upscore;
    3581 if( upbranchingresult->cutoff )
    3582 upscore = 2 * downscore;
    3583
    3584 score = SCIPgetBranchScore(scip, branchvar, downscore, upscore);
    3585
    3586 return score;
    3587}
    3588
    3589/** calculates the score based on the down and up branching scores */
    3590static
    3592 SCIP* scip, /**< SCIP data structure */
    3593 SCIP_VAR* branchvar, /**< variable to get the score for */
    3594 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
    3595 BRANCHINGRESULTDATA* upbranchingresult /**< branching result of the up branch */
    3596 )
    3597{
    3598 SCIP_Real score;
    3599 SCIP_Real downscore;
    3600 SCIP_Real upscore;
    3601 SCIP_Real totaldowngains;
    3602 SCIP_Real totalupgains;
    3603 SCIP_Real nlowestlevelcutoffs;
    3604 int ntotaldowngains;
    3605 int ntotalupgains;
    3606
    3607 assert(scip != NULL);
    3608 assert(branchvar != NULL);
    3609 assert(downbranchingresult != NULL);
    3610 assert(upbranchingresult != NULL);
    3611
    3612 assert(downbranchingresult->deeperscore >= -0.2 || downbranchingresult->cutoff || SCIPisStopped(scip));
    3613 assert(upbranchingresult->deeperscore >= -0.2 || upbranchingresult->cutoff || SCIPisStopped(scip));
    3614
    3615 nlowestlevelcutoffs = (1.0 * downbranchingresult->ndeepestcutoffs + upbranchingresult->ndeepestcutoffs)/(MAX(1,downbranchingresult->ndeepestnodes + upbranchingresult->ndeepestnodes));
    3616 totaldowngains = downbranchingresult->totalgains;
    3617 totalupgains = upbranchingresult->totalgains;
    3618 ntotaldowngains = MAX(1, downbranchingresult->ntotalgains);
    3619 ntotalupgains = MAX(1, upbranchingresult->ntotalgains);
    3620
    3621 downscore = sqrt(downbranchingresult->deeperscore);
    3622 upscore = sqrt(upbranchingresult->deeperscore);
    3623
    3624 downscore = MAX(downscore, SCIPsumepsilon(scip)); /*lint !e666*/
    3625 upscore = MAX(upscore, SCIPsumepsilon(scip)); /*lint !e666*/
    3626
    3627 if( downbranchingresult->cutoff )
    3628 downscore = 2 * upscore;
    3629 if( upbranchingresult->cutoff )
    3630 upscore = 2 * downscore;
    3631
    3632 score = SCIPgetBranchScore(scip, branchvar, downscore, upscore);
    3633
    3634 downscore = sqrt(totaldowngains/ntotaldowngains);
    3635 upscore = sqrt(totalupgains/ntotalupgains);
    3636
    3637 downscore = MAX(downscore, SCIPsumepsilon(scip)); /*lint !e666*/
    3638 upscore = MAX(upscore, SCIPsumepsilon(scip)); /*lint !e666*/
    3639
    3640 score += SCIPgetBranchScore(scip, branchvar, downscore, upscore)*nlowestlevelcutoffs;
    3641
    3642 return score;
    3643}
    3644
    3645/** calculates the combined gain, weighted with parameters given by the user configuration */
    3646static
    3648 SCIP* scip, /**< SCIP data structure */
    3649 CONFIGURATION* config, /**< LAB configuration */
    3650 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
    3651 BRANCHINGRESULTDATA* upbranchingresult, /**< branching result of the up branch */
    3652 SCIP_Real lpobjval /**< objective value to get difference to as gain */
    3653 )
    3654{
    3655 SCIP_Real downgain = 0.0;
    3656 SCIP_Real upgain = 0.0;
    3657
    3658 assert(config != NULL);
    3659 assert(downbranchingresult != NULL);
    3660 assert(upbranchingresult != NULL);
    3661
    3662 /* the gain is the difference of the dualbound of a child and the reference objective value;
    3663 * by bounding it by zero we are safe from numerical troubles
    3664 */
    3665 if( !downbranchingresult->cutoff )
    3666 downgain = MAX(0, downbranchingresult->dualbound - lpobjval);
    3667 if( !upbranchingresult->cutoff )
    3668 upgain = MAX(0, upbranchingresult->dualbound - lpobjval);
    3669
    3670 if( config->scoringfunction == 's' )
    3671 {
    3672 if( downbranchingresult->cutoff )
    3673 downgain = SCIPinfinity(scip);
    3674 if( upbranchingresult->cutoff )
    3675 upgain = SCIPinfinity(scip);
    3676 }
    3677 else
    3678 {
    3679 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
    3680 * realistic gain for the infeasible child;
    3681 * if both children are infeasible we just reset the initial zero values again
    3682 */
    3683 if( downbranchingresult->cutoff )
    3684 downgain = upgain;
    3685 if( upbranchingresult->cutoff )
    3686 upgain = downgain;
    3687 }
    3688
    3689 return config->minweight * MIN(downgain, upgain) + (1.0 - config->minweight) * MAX(downgain, upgain);
    3690}
    3691
    3692/** calculates the score as mentioned in the lookahead branching paper by Glankwamdee and Linderoth;
    3693 * their score scales the number of cutoffs on the last layer of a 2-level temporary branching tree with the average gain of
    3694 * every last level problem; together with the best gain for each branch of a variable we get the final score
    3695 */
    3696static
    3698 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
    3699 BRANCHINGRESULTDATA* upbranchingresult /**< branching result of the up branch */
    3700 )
    3701{
    3702 SCIP_Real bestdowngain;
    3703 SCIP_Real bestupgain;
    3704 SCIP_Real totaldowngains;
    3705 SCIP_Real totalupgains;
    3706 int nlowestlevelcutoffs;
    3707 int ntotaldowngains;
    3708 int ntotalupgains;
    3709
    3710 assert(downbranchingresult != NULL);
    3711 assert(upbranchingresult != NULL);
    3712
    3713 nlowestlevelcutoffs = downbranchingresult->ndeepestcutoffs + upbranchingresult->ndeepestcutoffs;
    3714 bestdowngain = downbranchingresult->bestgain;
    3715 bestupgain = upbranchingresult->bestgain;
    3716 totaldowngains = downbranchingresult->totalgains;
    3717 totalupgains = upbranchingresult->totalgains;
    3718 ntotaldowngains = MAX(1, downbranchingresult->ntotalgains);
    3719 ntotalupgains = MAX(1, upbranchingresult->ntotalgains);
    3720
    3721 return bestdowngain + bestupgain + (totaldowngains/ntotaldowngains + totalupgains/ntotalupgains)*nlowestlevelcutoffs;
    3722}
    3723
    3724/** calculates the score as mentioned in the lookahead branching paper by Glankwamdee and Linderoth;
    3725 * their score scales the number of cutoffs on the last layer of a 2-level temporary branching tree with the average gain of
    3726 * every last level problem; together with the best gain for each branch of a variable we get the final score
    3727 */
    3728static
    3730 CONFIGURATION* config, /**< LAB configuration */
    3731 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
    3732 BRANCHINGRESULTDATA* upbranchingresult /**< branching result of the up branch */
    3733 )
    3734{
    3735 SCIP_Real bestdowngain;
    3736 SCIP_Real bestupgain;
    3737 SCIP_Real totaldowngains;
    3738 SCIP_Real totalupgains;
    3739 SCIP_Real nlowestlevelcutoffs;
    3740 int ntotaldowngains;
    3741 int ntotalupgains;
    3742
    3743 assert(downbranchingresult != NULL);
    3744 assert(upbranchingresult != NULL);
    3745
    3746 nlowestlevelcutoffs = (1.0 * downbranchingresult->ndeepestcutoffs + upbranchingresult->ndeepestcutoffs)/(downbranchingresult->ndeepestnodes + upbranchingresult->ndeepestnodes);
    3747 bestdowngain = downbranchingresult->bestgain;
    3748 bestupgain = upbranchingresult->bestgain;
    3749 totaldowngains = downbranchingresult->totalgains;
    3750 totalupgains = upbranchingresult->totalgains;
    3751 ntotaldowngains = MAX(1, downbranchingresult->ntotalgains);
    3752 ntotalupgains = MAX(1, upbranchingresult->ntotalgains);
    3753
    3754 return config->minweight*MIN(bestdowngain, bestupgain) + (1.0 - config->minweight)*MAX(bestdowngain, bestupgain) + (totaldowngains/ntotaldowngains + totalupgains/ntotalupgains)*nlowestlevelcutoffs;
    3755}
    3756
    3757static
    3759 SCIP* scip, /**< SCIP data structure */
    3760 SCIP_VAR* branchvar, /**< variable to get the score for */
    3761 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
    3762 BRANCHINGRESULTDATA* upbranchingresult, /**< branching result of the up branch */
    3763 SCIP_Real lpobjval /**< objective value to get difference to as gain */
    3764 )
    3765{
    3766 SCIP_Real score;
    3767 SCIP_Real downgain = SCIPsumepsilon(scip);
    3768 SCIP_Real upgain = SCIPsumepsilon(scip);
    3769 SCIP_Real gap;
    3770 int nlowestlevelcutoffs;
    3771
    3772 assert(downbranchingresult != NULL);
    3773 assert(upbranchingresult != NULL);
    3774
    3775 nlowestlevelcutoffs = 0;
    3776
    3777 /* the gain is the difference of the dualbound of a child and the reference objective value;
    3778 * by bounding it by zero we are safe from numerical troubles
    3779 */
    3780 if( !downbranchingresult->cutoff )
    3781 {
    3782 nlowestlevelcutoffs += downbranchingresult->ndeepestcutoffs;
    3783 downgain = MAX(downgain, downbranchingresult->dualbound - lpobjval);
    3784 }
    3785 if( !upbranchingresult->cutoff )
    3786 {
    3787 nlowestlevelcutoffs += upbranchingresult->ndeepestcutoffs;
    3788 upgain = MAX(upgain, upbranchingresult->dualbound - lpobjval);
    3789 }
    3790
    3791 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
    3792 * realistic gain for the infeasible child;
    3793 * if both children are infeasible we just reset the initial zero values again
    3794 */
    3795 if( downbranchingresult->cutoff )
    3796 {
    3797 nlowestlevelcutoffs += 2 * SCIPgetNPseudoBranchCands(scip);
    3798 downgain = 2 * upgain;
    3799 }
    3800 if( upbranchingresult->cutoff )
    3801 {
    3802 nlowestlevelcutoffs += 2 * SCIPgetNPseudoBranchCands(scip);
    3803 upgain = 2 * downgain;
    3804 }
    3805
    3806 gap = SCIPgetCutoffbound(scip) - lpobjval;
    3807
    3808 downgain = downgain/gap;
    3809 upgain = upgain/gap;
    3810
    3811 score = 1.0 * nlowestlevelcutoffs + SCIPgetBranchScore(scip, branchvar, downgain, upgain);
    3812
    3813 return score;
    3814}
    3815
    3816static
    3818 SCIP* scip, /**< SCIP data structure */
    3819 SCIP_VAR* branchvar, /**< variable to get the score for */
    3820 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
    3821 BRANCHINGRESULTDATA* upbranchingresult, /**< branching result of the up branch */
    3822 SCIP_Real lpobjval /**< objective value to get difference to as gain */
    3823 )
    3824{
    3825 SCIP_Real score;
    3826 SCIP_Real downgain = SCIPsumepsilon(scip);
    3827 SCIP_Real upgain = SCIPsumepsilon(scip);
    3828 SCIP_Real gap;
    3829 int factor;
    3830 SCIP_Real nlowestlevelcutoffs;
    3831
    3832 assert(downbranchingresult != NULL);
    3833 assert(upbranchingresult != NULL);
    3834
    3835 assert(downbranchingresult->ndeepestnodes + upbranchingresult->ndeepestnodes > 0 || (downbranchingresult->cutoff && upbranchingresult->cutoff));
    3836
    3837 nlowestlevelcutoffs = (1.0 * downbranchingresult->ndeepestcutoffs + upbranchingresult->ndeepestcutoffs)/(1 + downbranchingresult->ndeepestnodes + upbranchingresult->ndeepestnodes);
    3838
    3840 if( factor > SCIPgetNLPRows(scip) )
    3841 factor = SCIPgetNLPRows(scip);
    3842 factor = factor * factor;
    3843
    3844 /* the gain is the difference of the dualbound of a child and the reference objective value;
    3845 * by bounding it by zero we are safe from numerical troubles
    3846 */
    3847 if( !downbranchingresult->cutoff )
    3848 {
    3849 downgain = MAX(downgain, downbranchingresult->dualbound - lpobjval);
    3850 }
    3851 if( !upbranchingresult->cutoff )
    3852 {
    3853 upgain = MAX(upgain, upbranchingresult->dualbound - lpobjval);
    3854 }
    3855
    3856 /* in case a child is infeasible and therefore cutoff we take the gain of the other child to receive a somewhat
    3857 * realistic gain for the infeasible child;
    3858 * if both children are infeasible we just reset the initial zero values again
    3859 */
    3860 if( downbranchingresult->cutoff )
    3861 {
    3862 downgain = 2 * upgain;
    3863 }
    3864 if( upbranchingresult->cutoff )
    3865 {
    3866 upgain = 2 * downgain;
    3867 }
    3868
    3869 gap = SCIPgetCutoffbound(scip) - lpobjval;
    3870
    3871 downgain = downgain/gap;
    3872 upgain = upgain/gap;
    3873
    3874 score = factor * nlowestlevelcutoffs + SCIPgetBranchScore(scip, branchvar, downgain, upgain);
    3875
    3876 return score;
    3877}
    3878
    3879/** scoring method that selects an actual scoring method based on the user configuration */
    3880static
    3882 SCIP* scip, /**< SCIP data structure */
    3883 CONFIGURATION* config, /**< LAB configuration */
    3884 SCIP_VAR* branchvar, /**< variable to get the score for */
    3885 BRANCHINGRESULTDATA* downbranchingresult,/**< branching result of the down branch */
    3886 BRANCHINGRESULTDATA* upbranchingresult, /**< branching result of the up branch */
    3887 SCIP_Real lpobjval, /**< objective value to get difference to as gain */
    3888 SCIP_Real baselpobjval /**< base objective value to get difference to as gain */
    3889 )
    3890{
    3891 SCIP_Real score;
    3892 char scoringfunction;
    3893
    3894 assert(scip != NULL);
    3895 assert(config != NULL);
    3896 assert(branchvar != NULL);
    3897 assert(downbranchingresult != NULL);
    3898 assert(upbranchingresult != NULL);
    3899
    3900 if( config->inscoring )
    3901 scoringfunction = config->scoringscoringfunction;
    3902 else if( SCIPgetProbingDepth(scip) > 0 )
    3903 scoringfunction = config->deeperscoringfunction;
    3904 else
    3905 scoringfunction = config->scoringfunction;
    3906
    3907 switch( scoringfunction )
    3908 {
    3909 case 's':
    3910 score = calculateScaledCutoffScore(downbranchingresult, upbranchingresult);
    3911 break;
    3912 case 'w':
    3913 score = calculateWeightedCutoffScore(config, downbranchingresult, upbranchingresult);
    3914 break;
    3915 case 'f':
    3916 score = calculateWeightedGain(scip, config, downbranchingresult, upbranchingresult, baselpobjval);
    3917 break;
    3918 case 'p':
    3919 score = calculateScoreFromDeeperscore(scip, branchvar, downbranchingresult, upbranchingresult);
    3920 break;
    3921 case 'a':
    3922 score = calculateScoreFromDeeperscoreAndCutoffs(scip, branchvar, downbranchingresult, upbranchingresult);
    3923 break;
    3924 case 'l':
    3925 score = calculateScoreFromResult2(scip, branchvar, downbranchingresult, upbranchingresult, lpobjval);
    3926 break;
    3927 case 'c':
    3928 score = calculateCutoffScore(scip, branchvar, downbranchingresult, upbranchingresult, lpobjval);
    3929 break;
    3930 case 'r':
    3931 score = calculateRelCutoffScore(scip, branchvar, downbranchingresult, upbranchingresult, lpobjval);
    3932 break;
    3933 case 'x':
    3934 score = calculateScoreFromResult(scip, branchvar, downbranchingresult, upbranchingresult, baselpobjval);
    3935 break;
    3936 default:
    3937 assert(scoringfunction == 'd');
    3938 score = calculateScoreFromResult(scip, branchvar, downbranchingresult, upbranchingresult, lpobjval);
    3939 }
    3940
    3941 return score;
    3942}
    3943
    3944/** calculates the score based on the pseudocosts of the given variable */
    3945static
    3947 SCIP* scip, /**< SCIP data structure */
    3948 CANDIDATE* lpcand /**< candidate to get the score for */
    3949 )
    3950{
    3951 SCIP_Real downpseudocost;
    3952 SCIP_Real uppseudocost;
    3953 SCIP_Real score;
    3954
    3955 assert(scip != NULL);
    3956 assert(lpcand != NULL);
    3957
    3958 downpseudocost = SCIPgetVarPseudocostVal(scip, lpcand->branchvar, 0-lpcand->fracval);
    3959 uppseudocost = SCIPgetVarPseudocostVal(scip, lpcand->branchvar, 1-lpcand->fracval);
    3960
    3961 score = SCIPgetBranchScore(scip, lpcand->branchvar, downpseudocost, uppseudocost);
    3962
    3963 return score;
    3964}
    3965
    3966#ifdef SCIP_DEBUG
    3967/** prints the names of the candidates of the given candidate list with their corresponding scores */
    3968static
    3969void printCandidateList(
    3970 SCIP* scip, /**< SCIP data structure */
    3971 CANDIDATELIST* candidatelist, /**< list to be printed */
    3972 SCORECONTAINER* scorecontainer /**< container with all scores */
    3973 )
    3974{
    3975 int i;
    3976
    3977 assert(scip != NULL);
    3978 assert(candidatelist != NULL);
    3979 assert(scorecontainer != NULL);
    3980
    3981 for( i = 0; i < candidatelist->ncandidates; i++ )
    3982 {
    3983 SCIP_VAR* var = candidatelist->candidates[i]->branchvar;
    3984 SCIP_Real score = scorecontainer->scores[SCIPvarGetProbindex(var)];
    3985
    3986 assert(var != NULL);
    3987
    3988 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, " Index %2i: Var %s Score %.9g\n", i, SCIPvarGetName(var), score);
    3989 }
    3990}
    3991#endif
    3992
    3993/** sorts the best candidates (w.r.t. the score in the container) of the candidate list to the front of the list */
    3994static
    3996 SCIP* scip, /**< SCIP data structure */
    3997 CANDIDATELIST* candidatelist, /**< candidates to be sorted */
    3998 SCORECONTAINER* scorecontainer, /**< container with the scores for each candidate */
    3999 int nbestcandidates /**< number of candidates that should be kept sorted at the start of the list*/
    4000 )
    4001{
    4002 int i;
    4003
    4004 assert(scip != NULL);
    4005 assert(candidatelist != NULL);
    4006 assert(scorecontainer != NULL);
    4007 assert(candidatelist->ncandidates > 0);
    4008 assert(nbestcandidates <= candidatelist->ncandidates);
    4009
    4010 for( i = 1; i < candidatelist->ncandidates; i++ )
    4011 {
    4012 CANDIDATE* movecand = candidatelist->candidates[i];
    4013 int moveprobindex;
    4014 SCIP_Real movescore;
    4015 int nsorted;
    4016 int insertionindex;
    4017 assert(movecand != NULL);
    4018
    4019 moveprobindex = SCIPvarGetProbindex(movecand->branchvar);
    4020 movescore = scorecontainer->scores[moveprobindex];
    4021
    4022 /* the length of the sorted portion of the array, starting at 0 */
    4023 nsorted = MIN(i, nbestcandidates);
    4024
    4025 insertionindex = findInsertionPoint(scip, scorecontainer, movescore, candidatelist->candidates, nsorted);
    4026
    4027 assert(insertionindex <= nsorted);
    4028
    4029 /* if no change has to be made, skip the reordering;
    4030 * if the insertionindex lies after the sorted block, skip the reordering
    4031 */
    4032 if( insertionindex != i && insertionindex < nsorted )
    4033 {
    4034 int j;
    4035 CANDIDATE* reordercand = movecand;
    4036
    4037 /* move everything inside the sorted block one place further */
    4038 for( j = insertionindex; j < nsorted; j++ )
    4039 {
    4040 CANDIDATE* oldcand = candidatelist->candidates[j];
    4041 assert(oldcand != NULL);
    4042
    4043 candidatelist->candidates[j] = reordercand;
    4044 reordercand = oldcand;
    4045 }
    4046 /* the dropped element gets placed in the position of the actually moved element */
    4047 candidatelist->candidates[i] = reordercand;
    4048 }
    4049 }
    4050
    4051#ifdef SCIP_DEBUG
    4052 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "All %i candidates, with the first %i candidates sorted by their FSB score:"
    4053 "\n", candidatelist->ncandidates, nbestcandidates);
    4054 printCandidateList(scip, candidatelist, scorecontainer);
    4055#endif
    4056}
    4057
    4058/** checks whether the given candidates is reliable, so that its pseudocosts may be used */
    4059static
    4061 SCIP* scip, /**< SCIP data structure */
    4062 SCIP_VAR* branchvar /**< var to check for reliability */
    4063 )
    4064{
    4065 SCIP_Real size;
    4066 SCIP_Real downsize;
    4067 SCIP_Real upsize;
    4068 SCIP_Real reliable = 5;
    4069
    4070 assert(scip != NULL);
    4071 assert(branchvar != NULL);
    4072
    4075 size = MIN(downsize, upsize);
    4076
    4077 return size >= reliable;
    4078}
    4079
    4080/** checks whether the current problem is feasible or cutoff */
    4081static
    4083 SCIP* scip /**< SCIP data structure */
    4084 )
    4085{
    4086 assert(scip != NULL);
    4087
    4089}
    4090
    4091/** Ensures that the scores are present in the scorecontainer for each of the candidates to consider */
    4092static
    4094 SCIP* scip, /**< SCIP data structure */
    4095 STATUS* status, /**< current status */
    4096 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
    4097 CONFIGURATION* config, /**< the configuration of the branching rule */
    4098 SCIP_SOL* baselpsol, /**< base lp solution */
    4099 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
    4100 BINCONSDATA* binconsdata, /**< container collecting all binary constraints; or NULL */
    4101 CANDIDATELIST* allcandidates, /**< list containing all candidates to consider */
    4102 BRANCHINGDECISION* decision, /**< struct to store the final decision */
    4103 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
    4104 LEVEL2DATA* level2data, /**< level 2 LP results data */
    4105 SCIP_Real lpobjval /**< base LP objective value */
    4106#ifdef SCIP_STATISTIC
    4107 ,STATISTICS* statistics /**< general statistical data */
    4108 ,LOCALSTATISTICS* localstats /**< local statistics, may be disregarded */
    4109#endif
    4110 )
    4111{
    4112 int i;
    4113 int nunscoredcandidates = 0;
    4114 int* candidateunscored;
    4115
    4116 assert(scip != NULL);
    4117 assert(config != NULL);
    4118 assert(status != NULL);
    4119 assert(allcandidates != NULL);
    4120 assert(scorecontainer != NULL);
    4121 assert(allcandidates->candidates != NULL || allcandidates->ncandidates == 0);
    4122
    4123 SCIP_CALL( SCIPallocBufferArray(scip, &candidateunscored, allcandidates->ncandidates) );
    4124
    4125 /* filter the candidates based on the presence of a score in the 'scorecontainer'. Only those without a score need a
    4126 * new one.
    4127 */
    4128 for( i = 0; i < allcandidates->ncandidates; i++ )
    4129 {
    4130 CANDIDATE* lpcand = allcandidates->candidates[i];
    4131 SCIP_VAR* branchvar = lpcand->branchvar;
    4132 int probindex = SCIPvarGetProbindex(branchvar);
    4133 SCIP_Real knownscore = scorecontainer->scores[probindex];
    4134
    4135 assert(lpcand != NULL);
    4136 assert(branchvar != NULL);
    4137
    4138 if( SCIPisLT(scip, knownscore, 0.0) )
    4139 {
    4140 if( config->abbrevpseudo && isCandidateReliable(scip, branchvar) )
    4141 {
    4143 SCIP_CALL( scoreContainerSetScore(scip, scorecontainer, lpcand, score, 0.0, 0.0) );
    4144 }
    4145 else if( config->level2avgscore && SCIPgetProbingDepth(scip) > 0 )
    4146 {
    4147 assert(scorecontainer->nsetscores > 0);
    4148 SCIP_CALL( scoreContainerSetScore(scip, scorecontainer, lpcand,
    4149 scorecontainer->scoresum / scorecontainer->nsetscores, 0.0, 0.0) );
    4150 }
    4151 else if( config->level2zeroscore && SCIPgetProbingDepth(scip) > 0 )
    4152 {
    4153 assert(scorecontainer->nsetscores > 0);
    4154 SCIP_CALL( scoreContainerSetScore(scip, scorecontainer, lpcand,
    4155 -0.1, 0.0, 0.0) );
    4156 }
    4157 else
    4158 {
    4159 /* score is unknown and needs to be calculated */
    4160 candidateunscored[nunscoredcandidates] = i;
    4161 nunscoredcandidates++;
    4162 }
    4163 }
    4164 }
    4165
    4166 if( nunscoredcandidates > 0 )
    4167 {
    4168 CANDIDATELIST* unscoredcandidates;
    4169
    4170 /* allocate the list of candidates without any score (gets updated further on) */
    4171 SCIP_CALL( candidateListCreate(scip, &unscoredcandidates, nunscoredcandidates) );
    4172
    4173 /* move the unscored candidates to the temp list */
    4174 for( i = 0; i < nunscoredcandidates; i++ )
    4175 {
    4176 int candindex = candidateunscored[i];
    4177
    4178 assert(allcandidates->candidates[candindex] != NULL);
    4179
    4180 unscoredcandidates->candidates[i] = allcandidates->candidates[candindex];
    4181 }
    4182
    4183#ifdef SCIP_DEBUG
    4184 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Of the given %i candidates, %i have no score: ",
    4185 allcandidates->ncandidates, nunscoredcandidates);
    4186 printCandidates(scip, SCIP_VERBLEVEL_HIGH, unscoredcandidates);
    4187 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Calculating the FSB result to get a score for the remaining "
    4188 "candidates.\n");
    4189#endif
    4190
    4191 /* Calculate all remaining FSB scores and collect the scores in the container */;
    4192#ifdef SCIP_STATISTIC
    4193 SCIP_CALL( getFSBResult(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, unscoredcandidates,
    4194 decision, scorecontainer, level2data, lpobjval, statistics, localstats) );
    4195#else
    4196 SCIP_CALL( getFSBResult(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, unscoredcandidates,
    4197 decision, scorecontainer, level2data, lpobjval) );
    4198#endif
    4199
    4200 /* move the now scored candidates back to the original list */
    4201 for( i = 0; i < nunscoredcandidates; i++ )
    4202 {
    4203 assert(allcandidates->candidates[candidateunscored[i]] == unscoredcandidates->candidates[i]);
    4204
    4205 assert(unscoredcandidates->candidates[i] != NULL);
    4206 unscoredcandidates->candidates[i] = NULL;
    4207 }
    4208
    4209 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Calculated the scores for the remaining candidates\n");
    4210
    4211 SCIP_CALL( candidateListFree(scip, &unscoredcandidates) );
    4212 }
    4213
    4214 /* reset the best sorted indices, as those are only valid on the FSB run already completed */
    4216
    4217 SCIPfreeBufferArray(scip, &candidateunscored);
    4218
    4219 return SCIP_OKAY;
    4220}
    4221
    4222/** Get the candidates to temporarily branch on. In the LAB case this is the complete list of possible candidates. In the
    4223 * ALAB case only the 'best' candidates are returned. */
    4224static
    4226 SCIP* scip, /**< SCIP data structure */
    4227 STATUS* status, /**< current status */
    4228 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
    4229 CONFIGURATION* config, /**< the configuration of the branching rule */
    4230 SCIP_SOL* baselpsol, /**< base lp solution */
    4231 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
    4232 BINCONSDATA* binconsdata, /**< container collecting all binary constraints; or NULL */
    4233 CANDIDATELIST* candidatelist, /**< list of candidates to branch on */
    4234 BRANCHINGDECISION* decision, /**< struct to store the final decision */
    4235 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
    4236 LEVEL2DATA* level2data, /**< level 2 LP results data */
    4237 SCIP_Real lpobjval /**< base LP objective value */
    4238#ifdef SCIP_STATISTIC
    4239 ,STATISTICS* statistics /**< general statistical data */
    4240 ,LOCALSTATISTICS* localstats /**< local statistics, may be disregarded */
    4241#endif
    4242 )
    4243{
    4244 assert(scip != NULL);
    4245 assert(config != NULL);
    4246 assert(status != NULL);
    4247 assert(candidatelist != NULL);
    4248 assert(SCIPinProbing(scip));
    4249
    4250 /* abbreviated LAB: only use the "best" candidates */
    4251 if( config->abbreviated )
    4252 {
    4253 assert(scorecontainer != NULL);
    4254
    4255 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Getting the best (at most) %i of the given %i candidates: ",
    4256 config->maxncands, candidatelist->ncandidates);
    4257#ifdef SCIP_DEBUG
    4258 printCandidates(scip, SCIP_VERBLEVEL_HIGH, candidatelist);
    4259#endif
    4260
    4261 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "%s", "Ensuring that all candidates have a score.\n");
    4262#ifdef SCIP_STATISTIC
    4263 SCIP_CALL( ensureScoresPresent(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
    4264 decision, scorecontainer, level2data, lpobjval, statistics, localstats) );
    4265#else
    4266 SCIP_CALL( ensureScoresPresent(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
    4267 decision, scorecontainer, level2data, lpobjval) );
    4268#endif
    4269
    4270 /* if we didn't find any domreds or constraints during the FSB scoring, we branch on */
    4271 if( isBranchFurther(status, SCIPgetProbingDepth(scip) == 0) )
    4272 {
    4273 int nusedcands;
    4274 int i;
    4275
    4276 if( SCIPgetProbingDepth(scip) == 0 || config->maxndeepercands == 0 )
    4277 nusedcands = MIN(config->maxncands, candidatelist->ncandidates);
    4278 else
    4279 nusedcands = MIN(config->maxndeepercands, candidatelist->ncandidates);
    4280
    4281 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "%s", "Filter the candidates by their score.\n");
    4282
    4283 sortFirstCandidatesByScore(scip, candidatelist, scorecontainer, nusedcands);
    4284
    4285 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Best candidate according to FSB scores: <%s>\n",
    4286 SCIPvarGetName(candidatelist->candidates[0]->branchvar));
    4287
    4288 if( config->worsefactor >= 0 )
    4289 {
    4290 for( i = 1; i < nusedcands; ++i )
    4291 {
    4292 if( scorecontainer->scores[SCIPvarGetProbindex(candidatelist->candidates[0]->branchvar)] >
    4293 config->worsefactor * scorecontainer->scores[SCIPvarGetProbindex(candidatelist->candidates[i]->branchvar)] )
    4294 break;
    4295 }
    4296 nusedcands = i;
    4297 }
    4298
    4299 if( config->filterbymaxgain && SCIPgetProbingDepth(scip) == 0 )
    4300 {
    4301 SCIP_Real maxgain;
    4302 SCIP_Real bestmaxgain = MAX(scorecontainer->downgains[SCIPvarGetProbindex(candidatelist->candidates[0]->branchvar)],
    4303 scorecontainer->upgains[SCIPvarGetProbindex(candidatelist->candidates[0]->branchvar)]); /*lint !e666*/
    4304
    4305 if( bestmaxgain == 0.0 )
    4306 nusedcands = 1;
    4307 else
    4308 {
    4309 for( i = nusedcands - 1; i >= 1; --i )
    4310 {
    4311 maxgain = MAX(scorecontainer->downgains[SCIPvarGetProbindex(candidatelist->candidates[i]->branchvar)],
    4312 scorecontainer->upgains[SCIPvarGetProbindex(candidatelist->candidates[i]->branchvar)]); /*lint !e666*/
    4313
    4314 if( SCIPisSumLE(scip, maxgain / bestmaxgain, 1.0) )
    4315 {
    4316 --nusedcands;
    4317
    4318 if( i < nusedcands )
    4319 {
    4320 CANDIDATE* tmp = candidatelist->candidates[i];
    4321 candidatelist->candidates[i] = candidatelist->candidates[nusedcands];
    4322 candidatelist->candidates[nusedcands] = tmp;
    4323 }
    4324 }
    4325 }
    4326 }
    4327 }
    4328
    4329 if( SCIPgetProbingDepth(scip) > 0 && scorecontainer->scores[SCIPvarGetProbindex(candidatelist->candidates[0]->branchvar)] > -0.05)
    4330 {
    4331 for( i = 1; i < nusedcands; ++i )
    4332 {
    4333 if( scorecontainer->scores[SCIPvarGetProbindex(candidatelist->candidates[i]->branchvar)] < -0.05 )
    4334 break;
    4335 }
    4336 nusedcands = i;
    4337 }
    4338
    4339 SCIP_CALL( candidateListKeep(scip, candidatelist, nusedcands) );
    4340 }
    4341#ifdef SCIP_DEBUG
    4342 else
    4343 {
    4344 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Strong Branching would have stopped.\n");
    4345 }
    4346#endif
    4347
    4349 status->cutoff = TRUE;
    4350 }
    4351 else
    4352 {
    4353 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Getting the branching candidates by selecting all candidates.\n");
    4354 }
    4355
    4356 return SCIP_OKAY;
    4357}
    4358
    4359/** Executes the general branching on a variable in a given direction (up/down) and repeats the algorithm from the new node */
    4360static
    4362 SCIP* scip, /**< SCIP data structure */
    4363 STATUS* status, /**< current status */
    4364 CONFIGURATION* config, /**< the configuration of the branching rule */
    4365 SCIP_SOL* baselpsol, /**< the base lp solution */
    4366 CANDIDATE* candidate, /**< candidate to branch on */
    4367 SCIP_Real localbaselpsolval, /**< the objective value of the current temporary problem */
    4368 SCIP_Real baselpobjval, /**< LP objective value of focus node (not probing) */
    4369 int recursiondepth, /**< remaining recursion depth */
    4370 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
    4371 BINCONSDATA* binconsdata, /**< container collecting all binary constraints; or NULL */
    4372 LEVEL2DATA* level2data, /**< level 2 LP results data */
    4373 BRANCHINGRESULTDATA* branchingresult, /**< container to store the result of the branching in */
    4374 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
    4375 SCIP_Bool downbranching /**< should we branch up or down in here? */
    4376#ifdef SCIP_STATISTIC
    4377 ,STATISTICS* statistics /**< general statistical data */
    4378 ,LOCALSTATISTICS* localstats /**< local statistics, may be disregarded */
    4379#endif
    4380 )
    4381{
    4382 int probingdepth;
    4383 SCIP_VAR* branchvar;
    4384 SCIP_Real branchvalfrac;
    4385 SCIP_Real branchval;
    4386 SCIP_Bool varisbinary;
    4387 SCIP_Bool solvedlp = TRUE;
    4388
    4389 assert(scip != NULL);
    4390 assert(status != NULL);
    4391 assert(config != NULL);
    4392 assert(candidate != NULL);
    4393 assert(branchingresult != NULL);
    4394
    4395 branchvar = candidate->branchvar;
    4396 branchvalfrac = candidate->fracval;
    4397 branchval = candidate->branchval;
    4398
    4399 assert(branchvar != NULL);
    4400
    4401 probingdepth = SCIPgetProbingDepth(scip);
    4402 varisbinary = SCIPvarIsBinary(branchvar);
    4403
    4404 if( binconsdata != NULL && varisbinary )
    4405 {
    4406 if( downbranching )
    4407 {
    4408 /* In case that the branch variable is binary, add the negated var to the list.
    4409 * This list is used to generate a set packing constraint for cutoff branches which were reached by only using
    4410 * binary variables.
    4411 * DownBranching on a binary variable x means: x <= 0
    4412 * When this cutoff occurs we have that: x >= 1 <=> 1-x <= 0
    4413 */
    4414 SCIP_VAR* negbranchvar;
    4415
    4416 SCIP_CALL( SCIPgetNegatedVar(scip, branchvar, &negbranchvar) );
    4417
    4418 assert(negbranchvar != NULL);
    4419
    4420 binaryVarListAppend(scip, binconsdata->binaryvars, negbranchvar);
    4421 }
    4422 else
    4423 {
    4424 /* In case that the branch variable is binary, add the var to the list.
    4425 * This list is used to generate a set packing constraint for cutoff branches which were reached by only using
    4426 * binary variables.
    4427 * UpBranching on a binary variable x means: x >= 1
    4428 * When this cutoff occurs we have that: x <= 0
    4429 */
    4430 binaryVarListAppend(scip, binconsdata->binaryvars, branchvar);
    4431 }
    4432 }
    4433
    4434 if( level2data != NULL )
    4435 {
    4436 SCIP_Real newbound = downbranching ? SCIPfeasFloor(scip, branchval) : SCIPfeasCeil(scip, branchval);
    4437
    4438 if( SCIPgetProbingDepth(scip) == 0 )
    4439 {
    4440 assert(SCIPvarGetProbindex(branchvar) >= 0);
    4441 level2data->branchvar1 = (unsigned int) SCIPvarGetProbindex(branchvar);
    4442 level2data->branchdir1 = !downbranching;
    4443 level2data->branchval1 = newbound;
    4444 }
    4445 else
    4446 {
    4447 LEVEL2RESULT* result;
    4448
    4449 assert(SCIPgetProbingDepth(scip) == 1);
    4450 assert(SCIPvarGetProbindex(branchvar) >= 0);
    4451
    4452 level2data->branchvar2 = (unsigned int) SCIPvarGetProbindex(branchvar);
    4453 level2data->branchdir2 = !downbranching;
    4454 level2data->branchval2 = newbound;
    4455
    4456 SCIP_CALL( level2dataGetResult(scip, level2data, &result) );
    4457
    4458 /* we already processed a similar level 2 node */
    4459 if( result != NULL )
    4460 {
    4461 solvedlp = FALSE;
    4462#ifdef SCIP_STATISTIC
    4463 statistics->nduplicatelps[probingdepth]++;
    4464#endif
    4465 branchingresult->objval = result->lpobjval;
    4466 branchingresult->dualbound = result->lpobjval;
    4467 branchingresult->dualboundvalid = result->valid;
    4468 branchingresult->cutoff = result->cutoff;
    4469 branchingresult->niterations = 0;
    4470
    4471 if( !branchingresult->cutoff && branchingresult->dualboundvalid
    4472 && SCIPisGE(scip, branchingresult->objval, SCIPgetCutoffbound(scip)) )
    4473 branchingresult->cutoff = TRUE;
    4474
    4476 "Use old %s branching result on var <%s> with 'val > %g' and bounds [<%g>..<%g>]: objval <%.9g>, cutoff <%d> "
    4477 "(the parent objval was <%.9g>)\n",
    4478 downbranching ? "down" : "up", SCIPvarGetName(branchvar), branchval, SCIPvarGetLbLocal(branchvar),
    4479 SCIPvarGetUbLocal(branchvar), branchingresult->objval, branchingresult->cutoff, localbaselpsolval);
    4480 }
    4481 }
    4482 }
    4483
    4484 if( solvedlp )
    4485 {
    4486 SCIP_CALL( executeBranching(scip, config, downbranching, candidate, branchingresult, baselpsol, domainreductions,
    4487 status) );
    4488
    4489 assert(SCIPgetProbingDepth(scip) == 1 || SCIPgetProbingDepth(scip) == 2);
    4490
    4491 if( level2data != NULL && SCIPgetProbingDepth(scip) == 2)
    4492 {
    4493 SCIP_Bool duplicate;
    4494
    4495 SCIP_CALL( level2dataStoreResult(scip, level2data, branchingresult->objval, branchingresult->cutoff, branchingresult->dualboundvalid, &duplicate) );
    4496 assert(!duplicate);
    4497 }
    4498
    4499#ifdef SCIP_STATISTIC
    4500 statistics->nlpssolved[probingdepth]++;
    4501 statistics->nlpiterations[probingdepth] += branchingresult->niterations;
    4502
    4503 if( config->inscoring )
    4504 {
    4505 statistics->nlpssolvedfsb[probingdepth]++;
    4506 statistics->nlpiterationsfsb[probingdepth] += branchingresult->niterations;
    4507 }
    4508#endif
    4509 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Solving the LP took %" SCIP_LONGINT_FORMAT " iterations (status %d).\n",
    4510 branchingresult->niterations, SCIPgetLPSolstat(scip));
    4511
    4512#ifdef SCIP_DEBUG
    4513 if( status->lperror )
    4514 {
    4515 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The LP could not be solved.\n");
    4516 }
    4517 else if( branchingresult->cutoff )
    4518 {
    4519 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The solved LP was infeasible and as such is cutoff\n");
    4520 }
    4521 else
    4522 {
    4523 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The solved LP was feasible and has an objval <%.9g> (the parent objval was "
    4524 "<%.9g>)\n", branchingresult->objval, localbaselpsolval);
    4525 }
    4526#endif
    4527 }
    4528
    4529 if( !branchingresult->cutoff && !status->lperror && !status->limitreached )
    4530 {
    4531 SCIP_Real localgain;
    4532
    4533 localgain = MAX(0, branchingresult->objval - localbaselpsolval);
    4534
    4535 /* update pseudo costs */
    4536 if( downbranching )
    4537 {
    4538 SCIP_CALL( SCIPupdateVarPseudocost(scip, branchvar, 0.0 - branchvalfrac, localgain, 1.0) );
    4539 }
    4540 else
    4541 {
    4542 SCIP_CALL( SCIPupdateVarPseudocost(scip, branchvar, 1.0 - branchvalfrac, localgain, 1.0) );
    4543 }
    4544 }
    4545
    4546 if( solvedlp && !branchingresult->cutoff && !status->lperror && !status->limitreached )
    4547 {
    4548 /* store the warm start information in the candidate, so that it can be reused in a later branching */
    4549 if( config->reusebasis && config->inscoring )
    4550 {
    4551 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Storing warm start information for %s branching on var <%s>\n",
    4552 downbranching ? "down" : "up", SCIPvarGetName(branchvar));
    4553
    4554 SCIP_CALL( candidateStoreWarmStartInfo(scip, candidate, downbranching) );
    4555 }
    4556
    4557 if( recursiondepth > 1 && !config->inscoring )
    4558 {
    4559 CANDIDATELIST* candidatelist;
    4560
    4562 assert(candidatelist != NULL);
    4563
    4564 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "%sbranching has <%i> candidates.\n", downbranching ? "Down" : "Up",
    4565 candidatelist->ncandidates);
    4566
    4567 if( candidatelist->ncandidates > 0 )
    4568 {
    4569 BRANCHINGDECISION* deeperdecision;
    4570 STATUS* deeperstatus;
    4571 PERSISTENTDATA* deeperpersistent = NULL;
    4572 SCIP_Real deeperlpobjval = branchingresult->objval;
    4573#ifdef SCIP_STATISTIC
    4574 LOCALSTATISTICS* deeperlocalstats;
    4575
    4576 SCIP_CALL( localStatisticsAllocate(scip, &deeperlocalstats) );
    4577#endif
    4578 SCIP_CALL( statusCreate(scip, &deeperstatus) );
    4579
    4580 SCIP_CALL( branchingDecisionCreate(scip, &deeperdecision) );
    4581
    4582#ifdef SCIP_STATISTIC
    4583 SCIP_CALL( filterCandidates(scip, deeperstatus, deeperpersistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
    4584 deeperdecision, scorecontainer, level2data, deeperlpobjval,
    4585 statistics, localstats) );
    4586#else
    4587 SCIP_CALL( filterCandidates(scip, deeperstatus, deeperpersistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
    4588 deeperdecision, scorecontainer, level2data, deeperlpobjval) );
    4589#endif
    4590 if( deeperstatus->lperror )
    4591 {
    4592 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "ignoring lperror in filtering call...\n");
    4593 deeperstatus->lperror = FALSE;
    4594 }
    4595 if( deeperstatus->cutoff )
    4596 {
    4597 branchingresult->ndeepestnodes += 2;
    4598 branchingresult->ndeepestcutoffs += 2;
    4599 }
    4600
    4601 /* the status may have changed because of FSB to get the best candidates */
    4602 if( isBranchFurther(deeperstatus, FALSE) )
    4603 {
    4604 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Now the objval is <%.9g>\n", branchingresult->objval);
    4605
    4606#ifdef SCIP_STATISTIC
    4607 deeperlocalstats->ncutoffproofnodes = 0;
    4608 SCIP_CALL( selectVarRecursive(scip, deeperstatus, deeperpersistent, config, baselpsol, domainreductions,
    4609 binconsdata, candidatelist, deeperdecision, scorecontainer, level2data, recursiondepth - 1,
    4610 deeperlpobjval, baselpobjval, &branchingresult->niterations, &branchingresult->ndeepestcutoffs,
    4611 &branchingresult->bestgain, &branchingresult->totalgains, &branchingresult->ntotalgains,
    4612 &branchingresult->ndeepestnodes,
    4613 statistics, deeperlocalstats, NULL, NULL) );
    4614#else
    4615 SCIP_CALL( selectVarRecursive(scip, deeperstatus, deeperpersistent, config, baselpsol, domainreductions,
    4616 binconsdata, candidatelist, deeperdecision, scorecontainer, level2data, recursiondepth - 1,
    4617 deeperlpobjval, baselpobjval, &branchingresult->niterations, &branchingresult->ndeepestcutoffs,
    4618 &branchingresult->bestgain, &branchingresult->totalgains, &branchingresult->ntotalgains,
    4619 &branchingresult->ndeepestnodes) );
    4620#endif
    4621
    4622 assert(deeperstatus->cutoff || deeperstatus->domred || deeperstatus->lperror
    4623 || branchingresult->ndeepestnodes == 8
    4624 || branchingresult->ndeepestnodes == 2 * candidatelist->ncandidates
    4625 || SCIPisStopped(scip));
    4626
    4627 /* the proved dual bound of the deeper branching cannot be less than the current dual bound, as every deeper
    4628 * node has more/tighter constraints and as such cannot be better than the base LP. */
    4629 assert(SCIPisGE(scip, deeperdecision->proveddb, branchingresult->dualbound));
    4630 branchingresult->dualbound = deeperdecision->proveddb;
    4631 branchingresult->deeperscore = deeperdecision->score;
    4632 branchingresult->dualboundvalid = TRUE;
    4633 }
    4634#ifdef SCIP_STATISTIC
    4635 else
    4636 {
    4637 assert(SCIPgetProbingDepth(scip) == probingdepth + 1);
    4638
    4639 statistics->stopafterfsb[probingdepth+1]++;
    4640
    4641 if( deeperstatus->cutoff )
    4642 {
    4643 statistics->cutoffafterfsb[probingdepth+1]++;
    4644 }
    4645 else if( deeperstatus->domred )
    4646 {
    4647 statistics->domredafterfsb[probingdepth+1]++;
    4648 }
    4649 }
    4650#endif
    4651 /* deeperstatus->cutoff is TRUE, if any up/down child pair of the up child were cutoff */
    4652 if( deeperstatus->cutoff )
    4653 {
    4654 branchingresult->cutoff = TRUE;
    4655#ifdef SCIP_STATISTIC
    4656 localstats->ncutoffproofnodes += deeperlocalstats->ncutoffproofnodes;
    4657#endif
    4658 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Both deeper children were cutoff, so the %s branch is "
    4659 "cutoff\n", downbranching ? "down" : "up");
    4660 }
    4661
    4662 branchingDecisionFree(scip, &deeperdecision);
    4663 statusFree(scip, &deeperstatus);
    4664#ifdef SCIP_STATISTIC
    4665 localStatisticsFree(scip, &deeperlocalstats);
    4666#endif
    4667 }
    4668 else
    4669 {
    4670 branchingresult->deeperscore = (branchingresult->dualbound - baselpobjval) * (branchingresult->dualbound - baselpobjval) * 10;
    4671 }
    4672 SCIP_CALL( candidateListFree(scip, &candidatelist) );
    4673 }
    4674 }
    4675
    4676 if( recursiondepth == 1 && !config->inscoring )
    4677 {
    4678 branchingresult->ndeepestnodes++;
    4679 /* this is a cutoff on the lowest tree level */
    4680 if( branchingresult->cutoff )
    4681 {
    4682 branchingresult->ndeepestcutoffs++;
    4683 }
    4684 }
    4685
    4686 if( binconsdata != NULL && varisbinary )
    4687 {
    4688 /* the current branching child is infeasible and we only branched on binary variables in lookahead branching */
    4689 if( solvedlp && branchingresult->cutoff && !status->lperror && SCIPallColsInLP(scip)
    4690 && binconsdata->binaryvars->nbinaryvars == (probingdepth + 1) )
    4691 {
    4692#ifdef SCIP_STATISTIC
    4693 SCIP_CALL( addBinaryConstraint(scip, config, binconsdata, baselpsol, statistics) );
    4694#else
    4695 SCIP_CALL( addBinaryConstraint(scip, config, binconsdata, baselpsol) );
    4696#endif
    4697 }
    4698
    4699 binaryVarListDrop(binconsdata->binaryvars);
    4700 }
    4701
    4702 /* reset the probing depth to undo the previous branching */
    4703 SCIP_CALL( SCIPbacktrackProbing(scip, probingdepth) );
    4704
    4705 return SCIP_OKAY;
    4706}
    4707
    4708/** branches recursively on all given candidates */
    4709static
    4711 SCIP* scip, /**< SCIP data structure */
    4712 STATUS* status, /**< current status */
    4713 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
    4714 CONFIGURATION* config, /**< the configuration of the branching rule */
    4715 SCIP_SOL* baselpsol, /**< base lp solution */
    4716 DOMAINREDUCTIONS* domainreductions, /**< container collecting all domain reductions found; or NULL */
    4717 BINCONSDATA* binconsdata, /**< container collecting all binary constraints; or NULL */
    4718 CANDIDATELIST* candidatelist, /**< list of candidates to branch on */
    4719 BRANCHINGDECISION* decision, /**< struct to store the final decision */
    4720 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
    4721 LEVEL2DATA* level2data, /**< level 2 LP results data */
    4722 int recursiondepth, /**< remaining recursion depth */
    4723 SCIP_Real lpobjval, /**< LP objective value of current probing node*/
    4724 SCIP_Real baselpobjval, /**< LP objective value of focus node (not probing) */
    4725 SCIP_Longint* niterations, /**< pointer to store the total number of iterations for this variable; or NULL*/
    4726 int* ndeepestcutoffs, /**< pointer to store the total number of cutoffs on the deepest level; or NULL */
    4727 SCIP_Real* bestgain, /**< pointer to store the best gain found with these candidates; or NULL */
    4728 SCIP_Real* totalgains, /**< pointer to store the sum over all gains that are valid in both children;
    4729 * or NULL, if bestgain == NULL */
    4730 int* ntotalgains, /**< pointer to store the number of gains summed in totalgains;
    4731 * or NULL, if bestgain == NULL */
    4732 int* ndeepestnodes /**< pointer to store the number of nodes processed in the deepest level */
    4733#ifdef SCIP_STATISTIC
    4734 ,STATISTICS* statistics /**< general statistical data */
    4735 ,LOCALSTATISTICS* localstats /**< local statistics, may be disregarded */
    4736 ,SCIP_Real* firstscoreptr /**< pointer to store score of first candidate, or NULL */
    4737 ,SCIP_Real* bestscoreptr /**< pointer to store best score, or NULL */
    4738#endif
    4739 )
    4740{
    4741 BRANCHINGRESULTDATA* downbranchingresult = NULL;
    4742 BRANCHINGRESULTDATA* upbranchingresult = NULL;
    4743 BRANCHINGRESULTDATA* bestdownbranchingresult = NULL;
    4744 BRANCHINGRESULTDATA* bestupbranchingresult = NULL;
    4745 SCIP_LPI* lpi;
    4746 SCIP_Real bestscore = -SCIPinfinity(scip);
    4747 SCIP_Real bestscorelowerbound;
    4748 SCIP_Real bestscoreupperbound;
    4749 SCIP_Real bestscoringlpobjval = -SCIPinfinity(scip);
    4750 int start = 0;
    4751 int i;
    4752 int c;
    4753 int nlpcands;
    4754 int probingdepth;
    4755 SCIP_Bool stopafterinfeasible = FALSE;
    4756
    4757 assert(scip != NULL);
    4758 assert(status != NULL);
    4759 assert(config != NULL);
    4760 assert(!config->usedomainreduction || domainreductions != NULL);
    4761 assert(candidatelist != NULL);
    4762 assert(candidatelist->ncandidates > 0);
    4763 assert(decision != NULL);
    4764 assert(recursiondepth >= 1);
    4765#ifdef SCIP_STATISTIC
    4766 assert(statistics != NULL);
    4767
    4768 if( firstscoreptr != NULL )
    4769 *firstscoreptr = -1.0;
    4770 if( bestscoreptr != NULL )
    4771 *bestscoreptr = -1.0;
    4772#endif
    4773
    4774 nlpcands = candidatelist->ncandidates;
    4775 probingdepth = SCIPgetProbingDepth(scip);
    4776 assert(probingdepth >= 0 && probingdepth < config->recursiondepth);
    4777
    4778 if( persistent != NULL && (!config->abbreviated || config->inscoring) && probingdepth == 0 )
    4779 start = persistent->restartindex;
    4780
    4781 /* init default decision */
    4782 decision->branchvar = candidatelist->candidates[0]->branchvar;
    4783 decision->branchval = candidatelist->candidates[0]->branchval;
    4784 decision->downdb = lpobjval;
    4785 decision->downdbvalid = FALSE;
    4786 decision->updb = lpobjval;
    4787 decision->updbvalid = FALSE;
    4788 decision->proveddb = lpobjval;
    4789 decision->score = 0.0;
    4790
    4791 bestscorelowerbound = SCIPvarGetLbLocal(decision->branchvar);
    4792 bestscoreupperbound = SCIPvarGetUbLocal(decision->branchvar);
    4793
    4794 SCIP_CALL( branchingResultDataCreate(scip, &downbranchingresult) );
    4795 SCIP_CALL( branchingResultDataCreate(scip, &upbranchingresult) );
    4796
    4797 SCIP_CALL( branchingResultDataCreate(scip, &bestdownbranchingresult) );
    4798 SCIP_CALL( branchingResultDataCreate(scip, &bestupbranchingresult) );
    4799
    4800 assert(downbranchingresult != NULL);
    4801 assert(upbranchingresult != NULL);
    4802
    4803 if( config->inscoring )
    4804 {
    4805 SCIP_CALL( SCIPgetBoolParam(scip, "branching/forceallchildren", &stopafterinfeasible) );
    4806 stopafterinfeasible = !stopafterinfeasible;
    4807 }
    4808
    4809 SCIP_CALL( SCIPgetLPI(scip, &lpi) );
    4810
    4811#ifdef SCIP_DEBUG
    4812 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Started selectVarRecursive with <%i> candidates: ", nlpcands);
    4813 printCandidates(scip, SCIP_VERBLEVEL_HIGH, candidatelist);
    4814#endif
    4815
    4816 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Starting loop from index %d\n", start);
    4817
    4818 /* iterate over all current branching candidates and evaluate their two potential child nodes by:
    4819 * - potentially applying domain propagation at each node before
    4820 * - solving the LP at the nodes to obtain a dual bound
    4821 * - potentially evaluating branching candidates at the potential child node again by applying this method recursively
    4822 *
    4823 * some improvements of the general scheme:
    4824 * - results obtained for a candidate in a previous lookahead branching call at this node may be re-used
    4825 * - while i counts the number of candidates evaluated in this call, we do not always start at the front
    4826 * of the candidate array, but rather store at which index we stopped last time (e.g., because a domain reduction was
    4827 * found and applied) and start from that index next time. Even though the set of branching candidates is probably different
    4828 * it is often reasonably close and we avoid evaluating the same variables again and again.
    4829 */
    4830 for( i = 0, c = start;
    4831 isBranchFurtherLoopDecrement(status, &c) && i < nlpcands && !SCIPisStopped(scip); i++, c++)
    4832 {
    4833 DOMAINREDUCTIONS* downdomainreductions = NULL;
    4834 DOMAINREDUCTIONS* updomainreductions = NULL;
    4835 SCIP_Bool useoldbranching = FALSE;
    4836 SCIP_Real oldlpobjval = -SCIPinfinity(scip);
    4837 CANDIDATE* candidate;
    4838 SCIP_VAR* branchvar;
    4839 SCIP_Real branchval;
    4840 SCIP_Real branchlb;
    4841 SCIP_Real branchub;
    4842
    4843 c = c % nlpcands;
    4844
    4845 candidate = candidatelist->candidates[c];
    4846
    4847 assert(candidate != NULL);
    4848
    4849 branchvar = candidate->branchvar;
    4850 branchval = candidate->branchval;
    4851
    4852 assert(branchvar != NULL);
    4853
    4854 branchlb = SCIPvarGetLbLocal(branchvar);
    4855 branchub = SCIPvarGetUbLocal(branchvar);
    4856
    4857 if( SCIPisEQ(scip, branchlb, branchub) )
    4858 {
    4859 /* if both bounds are equal the variable is fixed and we cannot branch
    4860 * this may happen if domain propagation on other candidates finds better bounds for the current candidate
    4861 */
    4862 status->domred = TRUE;
    4863#ifdef SCIP_STATISTIC
    4864 statistics->npropdomred[probingdepth]++;
    4865#endif
    4866 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Domain Propagation changed the bounds of a branching candidate."
    4867 "\n");
    4868 continue;
    4869 }
    4870
    4871 /* @todo apply already found domainreductions for this candidate? */
    4872
    4873#ifdef SCIP_STATISTIC
    4874 /* Reset the cutoffproofnodes, as the number of proof nodes from previous branching vars (which where not
    4875 * cutoff, as we didn't break the loop) is not relevant for the min total sum of proof nodes.
    4876 */
    4877 localstats->ncutoffproofnodes = 0;
    4878#endif
    4879
    4880 branchingResultDataInit(scip, downbranchingresult);
    4881 branchingResultDataInit(scip, upbranchingresult);
    4882
    4883 /* use old lookahead branching result, if last call on this variable is not too long ago */
    4884 if( persistent != NULL && (config->inscoring || probingdepth == 0) && isUseOldBranching(scip, persistent, config, branchvar) )
    4885 {
    4886 SCIP_CALL( getOldBranching(scip, persistent, config, branchvar, downbranchingresult, upbranchingresult,
    4887 &oldlpobjval) );
    4888 useoldbranching = TRUE;
    4889#ifdef SCIP_STATISTIC
    4890 if( config->inscoring )
    4891 statistics->noldbranchusedfsb[probingdepth]++;
    4892 else
    4893 statistics->noldbranchused[probingdepth]++;
    4894#endif
    4895 }
    4896 else
    4897 {
    4898 SCIP_Bool down;
    4899 int k;
    4900
    4901 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, "Started branching on var <%s> with val <%g> and bounds "
    4902 "[<%g>..<%g>]\n", SCIPvarGetName(branchvar), branchval, SCIPvarGetLbLocal(branchvar),
    4903 SCIPvarGetUbLocal(branchvar));
    4904
    4905 if( config->usedomainreduction )
    4906 {
    4907 SCIP_CALL( domainReductionsCreate(scip, &downdomainreductions) );
    4908 SCIP_CALL( domainReductionsCreate(scip, &updomainreductions) );
    4909 }
    4910
    4911 down = SCIPisStrongbranchDownFirst(scip, branchvar);
    4912
    4913 /* @todo break if result is infeasible (probably only in first layer)? */
    4914 for( k = 0; k < 2; ++k )
    4915 {
    4916 DOMAINREDUCTIONS* localdomainreductions;
    4917 BRANCHINGRESULTDATA* localbranchingresult;
    4918 BRANCHINGRESULTDATA* otherbranchingresult;
    4919
    4920 localdomainreductions = down ? downdomainreductions : updomainreductions;
    4921 localbranchingresult = down ? downbranchingresult : upbranchingresult;
    4922 otherbranchingresult = down ? upbranchingresult : downbranchingresult;
    4923
    4924#ifdef SCIP_STATISTIC
    4925 SCIP_CALL( executeBranchingRecursive(scip, status, config, baselpsol, candidate, lpobjval, baselpobjval,
    4926 recursiondepth, localdomainreductions, binconsdata, level2data, localbranchingresult, scorecontainer,
    4927 down, statistics, localstats) );
    4928#else
    4929
    4930 SCIP_CALL( executeBranchingRecursive(scip, status, config, baselpsol, candidate, lpobjval, baselpobjval,
    4931 recursiondepth, localdomainreductions, binconsdata, level2data, localbranchingresult, scorecontainer,
    4932 down) );
    4933#endif
    4934
    4935 /* check whether a new solutions rendered the previous child infeasible */
    4936 if( SCIPallColsInLP(scip) && !otherbranchingresult->cutoff )
    4937 {
    4938 if( k == 1 && SCIPisGE(scip, otherbranchingresult->dualbound, SCIPgetCutoffbound(scip)) )
    4939 {
    4940 otherbranchingresult->cutoff = TRUE;
    4942 "The %s branching changed the cutoffbound and rendered the %s branching result infeasible.\n",
    4943 down ? "down" : "up", down ? "up" : "down");
    4944 }
    4945 }
    4946 if( stopafterinfeasible && k == 0 && localbranchingresult->cutoff )
    4947 break;
    4948
    4949 /* the second iteration of the loop should branch in the other direction */
    4950 down = !down;
    4951 }
    4952
    4953 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, "-> down=%.9g (gain=%.9g, valid=%u, inf=%u), up=%.9g "
    4954 "(gain=%.9g, valid=%u, inf=%u)\n", downbranchingresult->dualbound,
    4955 downbranchingresult->dualbound - lpobjval, downbranchingresult->dualboundvalid,
    4956 downbranchingresult->cutoff, upbranchingresult->dualbound, upbranchingresult->dualbound - lpobjval,
    4957 upbranchingresult->dualboundvalid, upbranchingresult->cutoff);
    4958
    4959 if( niterations != NULL )
    4960 *niterations += downbranchingresult->niterations + upbranchingresult->niterations;
    4961
    4962 /* store results of branching call */
    4963 if( persistent != NULL && !upbranchingresult->cutoff && !downbranchingresult->cutoff && (config->inscoring || probingdepth == 0) )
    4964 {
    4965 SCIP_CALL( updateOldBranching(scip, persistent, config, branchvar, branchval, downbranchingresult,
    4966 upbranchingresult, lpobjval) );
    4967 }
    4968 }
    4969
    4970 if( ndeepestcutoffs != NULL )
    4971 *ndeepestcutoffs += downbranchingresult->ndeepestcutoffs + upbranchingresult->ndeepestcutoffs;
    4972
    4973 if( ndeepestnodes != NULL )
    4974 *ndeepestnodes += downbranchingresult->ndeepestnodes + upbranchingresult->ndeepestnodes;
    4975
    4976 if( !status->lperror && !status->limitreached )
    4977 {
    4978 SCIP_Real scoringlpobjval = useoldbranching ? oldlpobjval : lpobjval;
    4979 SCIP_Real score = calculateScore(scip, config, branchvar, downbranchingresult, upbranchingresult,
    4980 scoringlpobjval, baselpobjval);
    4981
    4982#ifdef SCIP_STATISTIC
    4983 if( i == 0 && firstscoreptr != NULL )
    4984 *firstscoreptr = score;
    4985#endif
    4986
    4987 if( bestgain != NULL && !config->inscoring && SCIPgetProbingDepth(scip) == 1 && !useoldbranching )
    4988 {
    4989 assert(totalgains != NULL);
    4990 assert(ntotalgains != NULL);
    4991
    4992 *bestgain = MAX(*bestgain, score);
    4993
    4994 if( !downbranchingresult->cutoff && !upbranchingresult->cutoff )
    4995 {
    4996 (*totalgains) += score;
    4997 (*ntotalgains)++;
    4998 }
    4999 }
    5000
    5001 /* both child nodes are infeasible -> the current node is infeasible */
    5002 if( SCIPallColsInLP(scip) && upbranchingresult->cutoff && downbranchingresult->cutoff )
    5003 {
    5004 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, " -> variable <%s> is infeasible in both directions\n",
    5005 SCIPvarGetName(branchvar));
    5006
    5007 /* this cutoff may be transferred to a higher level as a domain reduction/valid bound */
    5008 status->cutoff = TRUE;
    5009#ifdef SCIP_STATISTIC
    5010 statistics->nfullcutoffs[probingdepth]++;
    5011 localstats->ncutoffproofnodes += 2;
    5012#endif
    5013 }
    5014 /* up child is infeasible */
    5015 else if( SCIPallColsInLP(scip) && upbranchingresult->cutoff )
    5016 {
    5017 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, " -> variable <%s> is infeasible in upward branch\n",
    5018 SCIPvarGetName(branchvar));
    5019
    5020 /* apply down branching bound change at current node if we proved that this node is really infeasible and
    5021 * parameters are set accordingly
    5022 */
    5023 if( config->usedomainreduction && !useoldbranching )
    5024 {
    5025#ifdef SCIP_STATISTIC
    5026 assert(localstats->ncutoffproofnodes == 0 || localstats->ncutoffproofnodes == 2);
    5027 addUpperBound(scip, branchvar, branchval, baselpsol, TRUE, domainreductions,
    5028 2 + localstats->ncutoffproofnodes, TRUE);
    5029#else
    5030 addUpperBound(scip, branchvar, branchval, baselpsol, TRUE, domainreductions);
    5031#endif
    5032 }
    5033
    5034 /* the proved bound is given by the bound of the down child alone */
    5035 if( downbranchingresult->dualboundvalid )
    5036 {
    5037 decision->proveddb = MAX(decision->proveddb, downbranchingresult->dualbound);
    5038 }
    5039
    5040#ifdef SCIP_STATISTIC
    5041 statistics->nsinglecutoffs[probingdepth]++;
    5042#endif
    5043 }
    5044 /* down child is infeasible */
    5045 else if( SCIPallColsInLP(scip) && downbranchingresult->cutoff )
    5046 {
    5047 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, " -> variable <%s> is infeasible in downward branch\n",
    5048 SCIPvarGetName(branchvar));
    5049
    5050 /* apply up branching bound change at current node if we proved that this node is really infeasible and
    5051 * parameters are set accordingly
    5052 */
    5053 if( config->usedomainreduction && !useoldbranching )
    5054 {
    5055#ifdef SCIP_STATISTIC
    5056 assert(localstats->ncutoffproofnodes == 0 || localstats->ncutoffproofnodes == 2);
    5057 addLowerBound(scip, branchvar, branchval, baselpsol, TRUE, domainreductions,
    5058 2 + localstats->ncutoffproofnodes, TRUE);
    5059#else
    5060 addLowerBound(scip, branchvar, branchval, baselpsol, TRUE, domainreductions);
    5061#endif
    5062 }
    5063
    5064 /* the proved bound is given by the bound of the up child alone */
    5065 if( upbranchingresult->dualboundvalid )
    5066 {
    5067 decision->proveddb = MAX(decision->proveddb, upbranchingresult->dualbound);
    5068 }
    5069
    5070#ifdef SCIP_STATISTIC
    5071 statistics->nsinglecutoffs[probingdepth]++;
    5072#endif
    5073 }
    5074 /* "normal" case: both child nodes are LP-feasible */
    5075 else
    5076 {
    5077 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Neither branch is cut off and no limit reached.\n");
    5078
    5079 /* the proved dual bound is the minimum of the dual bounds of both child nodes */
    5080 if( upbranchingresult->dualboundvalid && downbranchingresult->dualboundvalid )
    5081 {
    5082 decision->proveddb = MAX(decision->proveddb, MIN(upbranchingresult->dualbound,
    5083 downbranchingresult->dualbound));
    5084 }
    5085 }
    5086
    5087 /* merge domain changes from the two child nodes */
    5088 if( updomainreductions != NULL && config->usedomainreduction && SCIPallColsInLP(scip) )
    5089 {
    5090 int maxstoredomreds = INT_MAX;
    5091
    5092 assert(downdomainreductions != NULL);
    5093
    5094 if( config->enforcemaxdomreds && config->maxnviolateddomreds > 0)
    5095 maxstoredomreds = config->maxnviolateddomreds;
    5096
    5097 if( !upbranchingresult->cutoff && !downbranchingresult->cutoff && config->mergedomainreductions )
    5098 applyDeeperDomainReductions(scip, baselpsol, maxstoredomreds, domainreductions, downdomainreductions,
    5099 updomainreductions);
    5100 else if( upbranchingresult->cutoff && !downbranchingresult->cutoff )
    5101 applySingleDeeperDomainReductions(scip, baselpsol, maxstoredomreds, domainreductions, downdomainreductions);
    5102 else if( downbranchingresult->cutoff && !upbranchingresult->cutoff )
    5103 applySingleDeeperDomainReductions(scip, baselpsol, maxstoredomreds, domainreductions, updomainreductions);
    5104 }
    5105
    5106 if( config->updatebranchingresults && bestscore > -1.0 &&
    5107 (SCIPisGT(scip, decision->proveddb, bestdownbranchingresult->dualbound)
    5108 || SCIPisGT(scip, decision->proveddb, bestupbranchingresult->dualbound)) )
    5109 {
    5110 SCIP_Real newscore;
    5111
    5112 bestdownbranchingresult->dualbound = MAX(bestdownbranchingresult->dualbound, decision->proveddb);
    5113 bestupbranchingresult->dualbound = MAX(bestupbranchingresult->dualbound, decision->proveddb);
    5114
    5115 newscore = calculateScore(scip, config, decision->branchvar, bestdownbranchingresult, bestupbranchingresult,
    5116 bestscoringlpobjval, baselpobjval);
    5117
    5118 if( newscore > bestscore )
    5119 {
    5120 bestscore = newscore;
    5121
    5122#ifdef SCIP_STATISTIC
    5123 if( bestscoreptr != NULL )
    5124 *bestscoreptr = newscore;
    5125#endif
    5126 decision->score = newscore;
    5127 decision->downdb = bestdownbranchingresult->dualbound;
    5128 decision->updb = bestupbranchingresult->dualbound;
    5129 }
    5130 }
    5131
    5132 /* the current candidate variable has a better score than the best candidate investigated so far */
    5133 if( SCIPisRelGT(scip, score, bestscore) )
    5134 {
    5135 int nvars = SCIPgetNVars(scip);
    5136
    5137 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Old best var <%s> with bounds [<%g>..<%g>] and score %.9g\n",
    5138 SCIPvarGetName(decision->branchvar), bestscorelowerbound, bestscoreupperbound, bestscore);
    5139
    5140 bestscore = score;
    5141
    5142#ifdef SCIP_STATISTIC
    5143 if( bestscoreptr != NULL )
    5144 *bestscoreptr = score;
    5145#endif
    5146 decision->branchvar = candidate->branchvar;
    5147 decision->branchval = candidate->branchval;
    5148 decision->downdb = downbranchingresult->dualbound;
    5149 decision->downdbvalid = downbranchingresult->dualboundvalid;
    5150 decision->updb = upbranchingresult->dualbound;
    5151 decision->updbvalid = upbranchingresult->dualboundvalid;
    5152 decision->score = score;
    5153
    5154 branchingResultDataCopy(downbranchingresult, bestdownbranchingresult);
    5155 branchingResultDataCopy(upbranchingresult, bestupbranchingresult);
    5156
    5157 /* store domain reductions found at the child nodes */
    5158 if( !config->inscoring && updomainreductions != NULL )
    5159 {
    5160 assert(downdomainreductions != NULL);
    5161
    5163
    5164 BMScopyMemoryArray(decision->uplowerbounds, updomainreductions->lowerbounds, nvars);
    5165 BMScopyMemoryArray(decision->upupperbounds, updomainreductions->upperbounds, nvars);
    5166 BMScopyMemoryArray(decision->downlowerbounds, downdomainreductions->lowerbounds, nvars);
    5167 BMScopyMemoryArray(decision->downupperbounds, downdomainreductions->upperbounds, nvars);
    5168 decision->boundsvalid = TRUE;
    5169 }
    5170 else
    5171 {
    5172 decision->boundsvalid = FALSE;
    5173 }
    5174
    5175 bestscorelowerbound = branchlb;
    5176 bestscoreupperbound = branchub;
    5177 bestscoringlpobjval = scoringlpobjval;
    5178 assert(!SCIPisEQ(scip, bestscorelowerbound, bestscoreupperbound));
    5179
    5180 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "New best var <%s> with bounds [<%g>..<%g>] and score %.9g\n",
    5181 SCIPvarGetName(decision->branchvar), bestscorelowerbound, bestscoreupperbound, bestscore);
    5182 }
    5183
    5184#ifdef SCIP_DEBUG
    5185 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, " -> cand %d/%d var <%s> (solval=%.9g, downgain=%.9g->%.9g, upgain=%.9g->%.9g,"
    5186 " score=%.9g) -- best: <%s> (%.9g)\n", c, nlpcands, SCIPvarGetName(branchvar), branchval,
    5187 MAX(downbranchingresult->objval - scoringlpobjval, 0), MAX(downbranchingresult->dualbound - scoringlpobjval, 0),
    5188 MAX(upbranchingresult->objval - scoringlpobjval, 0), MAX(upbranchingresult->dualbound - scoringlpobjval, 0),
    5189 score, SCIPvarGetName(decision->branchvar), bestscore);
    5190#endif
    5191
    5192 if( config->inscoring )
    5193 {
    5194 assert(scorecontainer != NULL);
    5195 /* only for abbreviated lookahead branching: we are in the FSB filtering step and store the score for this
    5196 * variable and the warm starting basis to reuse it in the subsequent lookahead evaluation of the best
    5197 * candidates
    5198 */
    5199 SCIP_CALL( scoreContainerSetScore(scip, scorecontainer, candidate, score,
    5200 downbranchingresult->dualbound - scoringlpobjval, upbranchingresult->dualbound - scoringlpobjval) );
    5201 }
    5202
    5203 if( probingdepth == 0 && (binconsdata != NULL || domainreductions != NULL) && !useoldbranching
    5204 && (config->maxnviolatedcons >= 0 || config->maxnviolatedbincons >= 0 || config->maxnviolateddomreds >= 0 ) )
    5205 {
    5206 int nbincons = 0;
    5207 int ndomreds = 0;
    5208
    5209 if( binconsdata != NULL )
    5210 {
    5211 assert(binconsdata != NULL); /* for lint */
    5212 nbincons = binconsdata->conslist->nviolatedcons;
    5213 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Found %d binary constraints (%d violated by the LP solution)\n",
    5214 binconsdata->conslist->nelements, nbincons);
    5215
    5216 if( (config->maxnviolatedbincons > 0) && (nbincons >= config->maxnviolatedbincons) )
    5217 {
    5218 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The max number of violated binary constraints <%i> is "
    5219 "exceeded.\n", config->maxnviolatedbincons);
    5220 status->maxnconsreached = TRUE;
    5221 }
    5222 }
    5223
    5224 if( domainreductions != NULL )
    5225 {
    5226 assert(domainreductions != NULL); /* for lint */
    5227 ndomreds = domainreductions->nviolatedvars;
    5228 if( config->prefersimplebounds && ndomreds > domainreductions->nsimplebounds )
    5229 ndomreds = domainreductions->nsimplebounds;
    5230
    5231 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Found %d bound changes (%d violated by the LP solution)\n",
    5232 domainreductions->nchangedvars, ndomreds);
    5233
    5234 if( (config->maxnviolateddomreds > 0) && (ndomreds >= config->maxnviolateddomreds) )
    5235 {
    5236 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The max number of violated bound changes <%i> is "
    5237 "exceeded.\n", config->maxnviolateddomreds);
    5238 status->maxnconsreached = TRUE;
    5239 }
    5240 }
    5241
    5242 if( config->maxnviolatedcons > 0 && (nbincons + ndomreds >= config->maxnviolatedcons) )
    5243 {
    5244 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The max number of violated binary constraints and bound "
    5245 "changes <%d> is exceeded.\n", config->maxnviolatedcons);
    5246 status->maxnconsreached = TRUE;
    5247 }
    5248 }
    5249 }
    5250
    5251 if( !(status->domred && decision->branchvar == candidate->branchvar) && areBoundsChanged(scip, decision->branchvar, bestscorelowerbound, bestscoreupperbound) )
    5252 {
    5253 /* in case the bounds of the current highest scored solution have changed due to domain propagation during
    5254 * the lookahead branching we can/should not branch on this variable but instead report the domain
    5255 * reduction */
    5256 status->domred = TRUE;
    5257#ifdef SCIP_STATISTIC
    5258 statistics->npropdomred[probingdepth]++;
    5259#endif
    5260 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Domain Propagation changed the bounds of a branching candidate."
    5261 "\n");
    5262 }
    5263
    5264 /* free domain reductions */
    5265 if( updomainreductions != NULL )
    5266 {
    5267 assert(downdomainreductions != NULL);
    5268
    5269 domainReductionsFree(scip, &updomainreductions);
    5270 domainReductionsFree(scip, &downdomainreductions);
    5271 }
    5272 }
    5273
    5274 branchingResultDataFree(scip, &bestupbranchingresult);
    5275 branchingResultDataFree(scip, &bestdownbranchingresult);
    5276
    5277 branchingResultDataFree(scip, &upbranchingresult);
    5278 branchingResultDataFree(scip, &downbranchingresult);
    5279
    5280 if( persistent != NULL && (!config->abbreviated || config->inscoring) && probingdepth == 0 )
    5281 {
    5282 persistent->restartindex = c;
    5283 }
    5284
    5285 return SCIP_OKAY;
    5286}
    5287
    5288/** checks whether the current decision should be stored. This is the case if we found domain reductions
    5289 * or constraints that will be applied, but none of them cuts off the current LP solution.
    5290 * Then our current decision still holds true for the next call and can be reused without further calculations
    5291 */
    5292static
    5294 CONFIGURATION* config, /**< the configuration of the branching rule */
    5295 BINCONSDATA* binconsdata, /**< container collecting all binary constraints; or NULL */
    5296 DOMAINREDUCTIONS* domainreductions /**< container collecting all domain reductions found; or NULL */
    5297 )
    5298{
    5299 assert(config != NULL);
    5300
    5301 if( !config->storeunviolatedsol )
    5302 return FALSE;
    5303
    5304 /* there are violating binary constraints */
    5305 if( binconsdata != NULL && binconsdata->conslist->nviolatedcons > 0 )
    5306 return FALSE;
    5307
    5308 /* there are violating domain changes */
    5309 if( domainreductions != NULL && domainreductions->nviolatedvars > 0 )
    5310 return FALSE;
    5311
    5312 /* return TRUE if there is at least one domain change or binary constraint */
    5313 return (domainreductions != NULL && domainreductions->nchangedvars > 0)
    5314 || (binconsdata != NULL && binconsdata->conslist->nelements > 0);
    5315}
    5316
    5317/** starting point to obtain a branching decision via LAB/ALAB. */
    5318static
    5320 SCIP* scip, /**< SCIP data structure */
    5321 CONFIGURATION* config, /**< the configuration of the branching rule */
    5322 PERSISTENTDATA* persistent, /**< container to store data over multiple calls to the branching rule; or NULL */
    5323 STATUS* status, /**< current status */
    5324 BRANCHINGDECISION* decision, /**< struct to store the final decision */
    5325 SCORECONTAINER* scorecontainer, /**< container to retrieve already calculated scores; or NULL */
    5326 CANDIDATELIST* candidatelist /**< list of candidates to branch on */
    5327#ifdef SCIP_STATISTIC
    5328 ,STATISTICS* statistics /**< general statistical data */
    5329 ,LOCALSTATISTICS* localstats /**< local statistics, may be disregarded */
    5330#endif
    5331 )
    5332{
    5333 int recursiondepth;
    5334 DOMAINREDUCTIONS* domainreductions = NULL;
    5335 BINCONSDATA* binconsdata = NULL;
    5336 LEVEL2DATA* level2data = NULL;
    5337 SCIP_SOL* baselpsol = NULL;
    5338 SCIP_Real lpobjval;
    5339#ifdef SCIP_STATISTIC
    5340 SCIP_Real firstscore = -1.0;
    5341 SCIP_Real bestscore = -1.0;
    5342 int chosencandnr = -1;
    5343 SCIP_Bool performedlab = FALSE;
    5344#endif
    5345
    5346 assert(scip != NULL);
    5347 assert(config != NULL);
    5348 assert(status != NULL);
    5349 assert(decision != NULL);
    5350 assert(candidatelist != NULL);
    5351#ifdef SCIP_STATISTIC
    5352 assert(statistics != NULL);
    5353#endif
    5354
    5355 recursiondepth = config->recursiondepth;
    5356 lpobjval = SCIPgetLPObjval(scip);
    5357
    5358 assert(recursiondepth > 0);
    5359
    5360 if( SCIP_MAXTREEDEPTH <= (SCIPgetDepth(scip) + recursiondepth) )
    5361 {
    5362 /* we need at least 'recursiondepth' space for the branching */
    5363 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Cannot perform probing in selectVarRecursive, depth limit reached. "
    5364 "Current:<%i>, Max:<%i>\n", SCIP_MAXTREEDEPTH, SCIPgetDepth(scip) + recursiondepth);
    5365 status->depthtoosmall = TRUE;
    5366#ifdef SCIP_STATISTIC
    5367 statistics->ndepthreached++;
    5368#endif
    5369 return SCIP_OKAY;
    5370 }
    5371
    5372 assert(!config->inscoring);
    5373
    5374 if( candidatelist->ncandidates == 1 )
    5375 {
    5376 decision->branchvar = candidatelist->candidates[0]->branchvar;
    5377 decision->branchval = candidatelist->candidates[0]->branchval;
    5378 decision->downdb = lpobjval;
    5379 decision->downdbvalid = FALSE;
    5380 decision->updb = lpobjval;
    5381 decision->updbvalid = FALSE;
    5382 decision->proveddb = lpobjval;
    5383
    5384 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Only one candidate (<%s>) is given. This one is chosen without "
    5385 "calculations.\n", SCIPvarGetName(decision->branchvar));
    5386
    5387#ifdef SCIP_STATISTIC
    5388 statistics->nsinglecandidate++;
    5389#endif
    5390 return SCIP_OKAY;
    5391 }
    5392 assert(!SCIPinProbing(scip));
    5393
    5394 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The objective value of the base lp is <%.9g>\n", lpobjval);
    5395
    5396 if( config->usedomainreduction || config->usebincons )
    5397 {
    5398 /* we have to copy the current solution before getting the candidates, as we possibly solve some LPs during
    5399 * the getter and as such would get a wrong LP copied */
    5400 SCIP_CALL( copyCurrentSolution(scip, &baselpsol) );
    5401 }
    5402
    5403 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "About to start probing.\n");
    5406
    5407 /* create the binary constraint data */
    5408 if( config->usebincons )
    5409 {
    5410 SCIP_CALL( binConsDataCreate(scip, &binconsdata, recursiondepth,
    5411 (int)SCIPceil(scip, 0.5*candidatelist->ncandidates)) );
    5412 }
    5413
    5414 /* collect domain reductions in FSB scoring or LAB branching */
    5415 if( config->usedomainreduction )
    5416 {
    5417 SCIP_CALL( domainReductionsCreate(scip, &domainreductions) );
    5418 }
    5419
    5420#ifdef SCIP_STATISTIC
    5421 SCIP_CALL( filterCandidates(scip, status, persistent, config, baselpsol, domainreductions, NULL, candidatelist,
    5422 decision, scorecontainer, level2data, lpobjval,
    5423 statistics, localstats) );
    5424#else
    5425 SCIP_CALL( filterCandidates(scip, status, persistent, config, baselpsol, domainreductions, NULL, candidatelist,
    5426 decision, scorecontainer, level2data, lpobjval) );
    5427#endif
    5428
    5429 if( candidatelist->ncandidates == 1 )
    5430 {
    5431 decision->branchvar = candidatelist->candidates[0]->branchvar;
    5432 decision->branchval = candidatelist->candidates[0]->branchval;
    5433 decision->downdb = lpobjval;
    5434 decision->downdbvalid = FALSE;
    5435 decision->updb = lpobjval;
    5436 decision->updbvalid = FALSE;
    5437 decision->proveddb = lpobjval;
    5438
    5439 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Only one candidate (<%s>) is given. This one is chosen without "
    5440 "calculations.\n", SCIPvarGetName(decision->branchvar));
    5441
    5442#ifdef SCIP_STATISTIC
    5443 statistics->nsingleafterfilter++;
    5444#endif
    5445 goto TERMINATE;
    5446 }
    5447
    5448 /* the status may have changed because of FSB to get the best candidates
    5449 * if that is the case, we already changed the base node and should start again */
    5450 if( isBranchFurther(status, TRUE) && candidatelist->ncandidates > 1 )
    5451 {
    5452 assert(candidatelist->ncandidates > 0);
    5453
    5454 SCIPstatistic(performedlab = TRUE);
    5455
    5456 /* we do not need the level 2 data for FSB scoring, so we do not need to create it before */
    5457 if( recursiondepth == 2 && config->uselevel2data )
    5458 {
    5459 SCIP_CALL( level2dataCreate(scip, &level2data) );
    5460 }
    5461
    5462#ifdef SCIP_STATISTIC
    5463 SCIP_CALL( selectVarRecursive(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
    5464 decision, scorecontainer, level2data, recursiondepth, lpobjval, lpobjval, NULL, NULL, NULL, NULL, NULL, NULL,
    5465 statistics, localstats, &firstscore, &bestscore) );
    5466#else
    5467 SCIP_CALL( selectVarRecursive(scip, status, persistent, config, baselpsol, domainreductions, binconsdata, candidatelist,
    5468 decision, scorecontainer, level2data, recursiondepth, lpobjval, lpobjval, NULL, NULL, NULL, NULL, NULL, NULL) );
    5469#endif
    5470
    5471 if( level2data != NULL )
    5472 {
    5473 level2dataFree(scip, &level2data);
    5474 }
    5475
    5476 /* only unviolating constraints and domain changes: store branching decision */
    5477 if( persistent != NULL && !status->lperror && isStoreDecision(config, binconsdata, domainreductions) )
    5478 {
    5479 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "store decision: lpiters=%lld, cand <%s>[%g,%g - %g]\n",
    5482 SCIPgetSolVal(scip, NULL, decision->branchvar));
    5483
    5484 persistent->oldntotalnodes = SCIPgetNTotalNodes(scip);
    5487 branchingDecisionCopy(decision, persistent->olddecision);
    5488 }
    5489
    5490#ifdef SCIP_STATISTIC
    5491 if( config->abbreviated && !status->cutoff && !status->maxnconsreached
    5492 && !status->addedbinconss && !status->domred)
    5493 {
    5494 if( candidatelist->ncandidates > 0 )
    5495 {
    5496 assert(candidatelist->ncandidates <= statistics->maxnbestcands);
    5497
    5498 /* find the "FSB-index" of the decision */
    5499 for( chosencandnr = 0; chosencandnr < candidatelist->ncandidates; ++chosencandnr )
    5500 {
    5501 if( decision->branchvar == candidatelist->candidates[chosencandnr]->branchvar )
    5502 {
    5503 break;
    5504 }
    5505 }
    5506 assert(chosencandnr < candidatelist->ncandidates);
    5507 }
    5508 }
    5509 }
    5510 else
    5511 {
    5512 int probingdepth = 0;
    5513 if( SCIPinProbing(scip) )
    5514 probingdepth = SCIPgetProbingDepth(scip);
    5515 statistics->stopafterfsb[probingdepth]++;
    5516
    5517 if( status->cutoff )
    5518 {
    5519 statistics->cutoffafterfsb[probingdepth]++;
    5520 }
    5521 else if( status->maxnconsreached )
    5522 {
    5523 statistics->domredafterfsb[probingdepth]++;
    5524 }
    5525#endif
    5526 }
    5527
    5528 TERMINATE:
    5530 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Ended probing.\n");
    5531
    5532 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Applying found data to the base node.\n");
    5533
    5534 /* apply domain reductions */
    5535 if( domainreductions != NULL )
    5536 {
    5537 assert(config->usedomainreduction);
    5538
    5539 if( !status->cutoff )
    5540 {
    5541 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Applying domain reductions to the base node.\n");
    5542#ifdef SCIP_STATISTIC
    5543 SCIP_CALL( applyDomainReductions(scip, config, baselpsol, domainreductions, &status->domredcutoff,
    5544 &status->domred, statistics) );
    5545#else
    5546 SCIP_CALL( applyDomainReductions(scip, config, baselpsol, domainreductions, &status->domredcutoff,
    5547 &status->domred) );
    5548#endif
    5549 }
    5550 domainReductionsFree(scip, &domainreductions);
    5551 }
    5552
    5553 /* apply binary constraints */
    5554 if( binconsdata != NULL )
    5555 {
    5556 assert(config->usebincons);
    5557 assert(binconsdata->binaryvars->nbinaryvars == 0);
    5558
    5559 if( !status->cutoff )
    5560 {
    5561 SCIP_NODE* basenode = SCIPgetCurrentNode(scip);
    5562
    5563 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Applying %d binary constraints to the base node.\n", binconsdata->conslist->nelements);
    5564#ifdef SCIP_STATISTIC
    5565 SCIP_CALL( applyBinaryConstraints(scip, basenode, binconsdata->conslist, config,
    5566 &status->addedbinconss, &status->cutoff, &status->domred, statistics) );
    5567#else
    5568 SCIP_CALL( applyBinaryConstraints(scip, basenode, binconsdata->conslist, config,
    5569 &status->addedbinconss, &status->cutoff, &status->domred) );
    5570#endif
    5571 }
    5572 else
    5573 {
    5574 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Discarding %d binary constraints because the base node is cut off.\n", binconsdata->conslist->nelements);
    5575 }
    5576 binConsDataFree(scip, &binconsdata);
    5577 }
    5578 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Applied found data to the base node.\n");
    5579
    5580#if defined(SCIP_DEBUG) || defined(SCIP_STATISTIC)
    5581 if( config->abbreviated )
    5582 {
    5583 if( status->domred )
    5584 {
    5585 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Lookahead Branching has added domain reductions. LAB restarts.\n");
    5586
    5587#ifdef SCIP_STATISTIC
    5588 if( candidatelist->ncandidates == 1 )
    5589 statistics->nsingleafterfilter--;
    5590#endif
    5591 }
    5592 else if( status->addedbinconss )
    5593 {
    5594 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Lookahead Branching has added binary constraints. LAB restarts.\n");
    5595
    5596#ifdef SCIP_STATISTIC
    5597 if( candidatelist->ncandidates == 1 )
    5598 statistics->nsingleafterfilter--;
    5599#endif
    5600 }
    5601 else if( status->cutoff )
    5602 {
    5603 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Lookahead Branching cut this node off.\n");
    5604 }
    5605 else if( candidatelist->ncandidates > 0 )
    5606 {
    5607 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Strong Branching would branch on variable <%s>\n",
    5608 SCIPvarGetName(candidatelist->candidates[0]->branchvar));
    5609
    5610 if( isBranchFurther(status, FALSE) && branchingDecisionIsValid(decision) )
    5611 {
    5612#ifdef SCIP_STATISTIC
    5613 if( chosencandnr >= 0 )
    5614 {
    5615 ++statistics->chosenfsbcand[chosencandnr];
    5616
    5617 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "node %lld chose candidate %d score %16.9g vs %16.9g FSB: %16.9g vs %16.9g\n",
    5619 scorecontainer->scores[SCIPvarGetProbindex(candidatelist->candidates[chosencandnr]->branchvar)],
    5620 scorecontainer->scores[SCIPvarGetProbindex(candidatelist->candidates[0]->branchvar)],
    5621 bestscore, firstscore);
    5622 }
    5623 else
    5624 assert(!performedlab);
    5625#endif
    5626
    5627 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Lookahead Branching branches on variable <%s>\n",
    5628 SCIPvarGetName(decision->branchvar));
    5629 }
    5630 }
    5631 else
    5632 {
    5633 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Something unexpected happened.");
    5634 SCIPABORT();
    5635 }
    5636 }
    5637#endif
    5638
    5639 if( baselpsol != NULL )
    5640 {
    5641 SCIP_CALL( SCIPfreeSol(scip, &baselpsol) );
    5642 }
    5643
    5644 return SCIP_OKAY;
    5645}
    5646
    5647/**
    5648 * We can use the previous result, stored in the branchruledata, if the branchingvariable (as an indicator) is set and
    5649 * the current lp solution is equal to the previous lp solution.
    5650 *
    5651 * @return \ref TRUE, if we can branch on the previous decision, \ref FALSE, else.
    5652 */
    5653static
    5655 SCIP* scip, /**< SCIP data structure */
    5656 SCIP_BRANCHRULEDATA* branchruledata /**< branching rule data */
    5657 )
    5658{
    5659 PERSISTENTDATA* persistent;
    5660
    5661 assert(scip != NULL);
    5662 assert(branchruledata != NULL);
    5663
    5664 persistent = branchruledata->persistent;
    5665 assert(persistent != NULL);
    5666
    5667 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "check if previous result should be used: valid=%d, "\
    5668 "nodes=%lld (old=%lld), iterations=%lld (old=%lld), lps=%lld (old=%lld)\n",
    5673
    5674 return branchingDecisionIsValid(persistent->olddecision)
    5675 && (persistent->oldntotalnodes == SCIPgetNTotalNodes(scip))
    5678}
    5679
    5680/**
    5681 * Uses the results from the previous run saved in the branchruledata to branch.
    5682 * This is the case, if in the previous run only non-violating constraints were added. In that case we can use the
    5683 * branching decision we would have made then.
    5684 * If everything worked, the result pointer contains SCIP_BRANCHED.
    5685 *
    5686 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
    5687 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
    5688 */
    5689static
    5691 SCIP* scip, /**< SCIP data structure */
    5692 SCIP_BRANCHRULEDATA* branchruledata, /**< branching rule data */
    5693 SCIP_RESULT* result /**< the pointer to the branching result */
    5694 )
    5695{
    5696 assert(scip != NULL);
    5697 assert(branchruledata != NULL);
    5698 assert(result != NULL);
    5699 assert(branchruledata->config != NULL);
    5700 assert(branchruledata->persistent != NULL);
    5701 assert(branchruledata->persistent->olddecision != NULL);
    5702
    5703 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Branching based on previous solution.\n");
    5704
    5705 /* execute the actual branching */
    5706 SCIP_CALL( branchOnVar(scip, branchruledata->config, branchruledata->persistent->olddecision) );
    5707 *result = SCIP_BRANCHED;
    5708
    5709 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Result: Branched based on previous solution. Variable <%s>\n",
    5710 SCIPvarGetName(branchruledata->persistent->olddecision->branchvar));
    5711
    5712 /* reset the var pointer, as this is our indicator whether we should branch on prev data in the next call */
    5713 branchruledata->persistent->olddecision->branchvar = NULL;
    5714
    5715 return SCIP_OKAY;
    5716}
    5717
    5718/** free persistent data structure */
    5719static
    5721 SCIP* scip, /**< SCIP data structure */
    5722 SCIP_BRANCHRULEDATA* branchruledata /**< branching rule data */
    5723 )
    5724{
    5725 PERSISTENTDATA* persistent;
    5726 int nvars;
    5727 int i;
    5728
    5729 assert(scip != NULL);
    5730 assert(branchruledata != NULL);
    5731
    5732 persistent = branchruledata->persistent;
    5733 assert(persistent != NULL);
    5734
    5735 nvars = persistent->nvars;
    5736
    5737 for( i = nvars - 1; i >= 0; i--)
    5738 {
    5739 assert(persistent->lastbranchdownres[i] != NULL);
    5740 assert(persistent->lastbranchupres[i] != NULL);
    5741
    5742 SCIPfreeBlockMemory(scip, &persistent->lastbranchdownres[i]); /*lint !e866*/
    5743 SCIPfreeBlockMemory(scip, &persistent->lastbranchupres[i]); /*lint !e866*/
    5744 }
    5745
    5746 SCIPfreeBlockMemory(scip, &branchruledata->persistent->olddecision);
    5747
    5748 assert(persistent->lastbranchlpobjval != NULL);
    5749 assert(persistent->lastbranchdownres != NULL);
    5750 assert(persistent->lastbranchupres != NULL);
    5751 assert(persistent->lastbranchnlps != NULL);
    5752 assert(persistent->lastbranchid != NULL);
    5753
    5754 SCIPfreeBlockMemoryArray(scip, &persistent->lastbranchlpobjval, nvars);
    5755 SCIPfreeBlockMemoryArray(scip, &persistent->lastbranchdownres, nvars);
    5756 SCIPfreeBlockMemoryArray(scip, &persistent->lastbranchupres, nvars);
    5757 SCIPfreeBlockMemoryArray(scip, &persistent->lastbranchnlps, nvars);
    5758 SCIPfreeBlockMemoryArray(scip, &persistent->lastbranchid, nvars);
    5759
    5760 branchruledata->isinitialized = FALSE;
    5761
    5762 return SCIP_OKAY;
    5763}
    5764
    5765/** initializes the branchruledata and the contained structs */
    5766static
    5768 SCIP* scip, /**< SCIP data structure */
    5769 SCIP_BRANCHRULEDATA* branchruledata /**< the branch rule data to initialize */
    5770 )
    5771{
    5772 int nvars;
    5773 int i;
    5774
    5775 assert(scip != NULL);
    5776 assert(branchruledata != NULL);
    5777
    5778 /* with the SCIPvarGetProbindex() method we can access the index of a given variable in the SCIPgetVars() array and
    5779 * as such we can use it to access our arrays which should only contain binary and integer variables
    5780 */
    5782
    5783 /* the branching rule data is already initialized and no new variables have been added in the meantime */
    5784 if( branchruledata->isinitialized && nvars == branchruledata->persistent->nvars )
    5785 return SCIP_OKAY;
    5786
    5787 if( branchruledata->isinitialized )
    5788 {
    5789 SCIP_CALL( freePersistent(scip, branchruledata) );
    5790 }
    5791
    5792 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->persistent->lastbranchid, nvars) );
    5793 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->persistent->lastbranchnlps, nvars) );
    5794 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->persistent->lastbranchupres, nvars) );
    5795 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->persistent->lastbranchdownres, nvars) );
    5796 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->persistent->lastbranchlpobjval, nvars) );
    5797 branchruledata->persistent->nvars = nvars;
    5798 branchruledata->persistent->oldntotalnodes = -1;
    5799 branchruledata->persistent->oldnnodelpiterations = -1;
    5800 branchruledata->persistent->oldnnodelps = -1;
    5801
    5802 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata->persistent->olddecision) );
    5803 branchingDecisionInit(scip, branchruledata->persistent->olddecision);
    5804
    5805 for( i = 0; i < nvars; i++ )
    5806 {
    5807 branchruledata->persistent->lastbranchid[i] = -1;
    5808 branchruledata->persistent->lastbranchnlps[i] = 0;
    5809
    5810 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata->persistent->lastbranchupres[i]) ); /*lint !e866*/
    5811 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata->persistent->lastbranchdownres[i]) ); /*lint !e866*/
    5812 }
    5813
    5814 branchruledata->isinitialized = TRUE;
    5815
    5816 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Initialized the branchruledata\n");
    5817
    5818 return SCIP_OKAY;
    5819}
    5820
    5821/*
    5822 * Callback methods of branching rule
    5823 */
    5824
    5825/** copy method for branchrule plugins (called when SCIP copies plugins) */
    5826static
    5827SCIP_DECL_BRANCHCOPY(branchCopyLookahead)
    5828{ /*lint --e{715}*/
    5829 assert(scip != NULL);
    5830 assert(branchrule != NULL);
    5831 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
    5832
    5833 /* call inclusion method of branchrule */
    5835
    5836 return SCIP_OKAY;
    5837}
    5838
    5839/** destructor of branching rule to free user data (called when SCIP is exiting) */
    5840static
    5841SCIP_DECL_BRANCHFREE(branchFreeLookahead)
    5842{ /*lint --e{715}*/
    5843 SCIP_BRANCHRULEDATA* branchruledata;
    5844
    5845 branchruledata = SCIPbranchruleGetData(branchrule);
    5846 assert(branchruledata != NULL);
    5847 assert(branchruledata->config != NULL);
    5848 assert(branchruledata->persistent != NULL);
    5849
    5850 SCIPfreeBlockMemory(scip, &branchruledata->persistent);
    5851 SCIPfreeBlockMemory(scip, &branchruledata->config);
    5852 SCIPfreeBlockMemory(scip, &branchruledata);
    5853 SCIPbranchruleSetData(branchrule, NULL);
    5854
    5855 return SCIP_OKAY;
    5856}
    5857
    5858/** initialization method of branching rule (called after problem was transformed) */
    5859static
    5860SCIP_DECL_BRANCHINIT(branchInitLookahead)
    5861{ /*lint --e{715}*/
    5862 SCIP_BRANCHRULEDATA* branchruledata;
    5863
    5864 assert(scip != NULL);
    5865 assert(branchrule != NULL);
    5866
    5867 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Entering branchInitLookahead\n");
    5868
    5869 branchruledata = SCIPbranchruleGetData(branchrule);
    5870 assert(branchruledata != NULL);
    5871 assert(branchruledata->persistent != NULL);
    5872
    5873 branchruledata->persistent->restartindex = 0;
    5874
    5875#ifdef SCIP_STATISTIC
    5876 {
    5877 int recursiondepth;
    5878 int maxncands;
    5879
    5880 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Allocating space for the statistics struct.\n");
    5881
    5882 recursiondepth = branchruledata->config->recursiondepth;
    5884 if( maxncands > branchruledata->config->maxncands )
    5885 maxncands = branchruledata->config->maxncands;
    5886
    5887 SCIP_CALL( SCIPallocMemory(scip, &branchruledata->statistics) );
    5888 /* RESULT enum is 1 based, so use MAXRESULT + 1 as array size with unused 0 element */
    5889 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->nresults, MAXRESULT + 1) );
    5890 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->nsinglecutoffs, recursiondepth) );
    5891 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->nfullcutoffs, recursiondepth) );
    5892 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->nlpssolved, recursiondepth) );
    5893 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->nlpssolvedfsb, recursiondepth) );
    5894 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->nlpiterations, recursiondepth) );
    5895 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->nlpiterationsfsb, recursiondepth) );
    5896 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->nduplicatelps, recursiondepth) );
    5897 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->npropdomred, recursiondepth) );
    5898 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->noldbranchused, recursiondepth) );
    5899 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->noldbranchusedfsb, recursiondepth) );
    5900 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->chosenfsbcand, maxncands) );
    5901 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->domredafterfsb, recursiondepth) );
    5902 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->cutoffafterfsb, recursiondepth) );
    5903 SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->statistics->stopafterfsb, recursiondepth) );
    5904
    5905 branchruledata->statistics->recursiondepth = recursiondepth;
    5906 branchruledata->statistics->maxnbestcands = maxncands;
    5907
    5908 statisticsInit(branchruledata->statistics);
    5909 }
    5910#endif
    5911
    5912 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Leaving branchInitLookahead\n");
    5913
    5914 return SCIP_OKAY;
    5915}
    5916
    5917
    5918/** deinitialization method of branching rule (called before transformed problem is freed) */
    5919static
    5920SCIP_DECL_BRANCHEXIT(branchExitLookahead)
    5921{ /*lint --e{715}*/
    5922#ifdef SCIP_STATISTIC
    5923 SCIP_BRANCHRULEDATA* branchruledata;
    5924 STATISTICS* statistics;
    5925
    5926 branchruledata = SCIPbranchruleGetData(branchrule);
    5927 assert(branchruledata != NULL);
    5928
    5929 statistics = branchruledata->statistics;
    5930 assert(statistics != NULL);
    5931
    5932 statisticsPrint(scip, statistics);
    5933
    5934 SCIPfreeMemoryArray(scip, &statistics->stopafterfsb);
    5935 SCIPfreeMemoryArray(scip, &statistics->cutoffafterfsb);
    5936 SCIPfreeMemoryArray(scip, &statistics->domredafterfsb);
    5937 SCIPfreeMemoryArray(scip, &statistics->chosenfsbcand);
    5938 SCIPfreeMemoryArray(scip, &statistics->noldbranchusedfsb);
    5939 SCIPfreeMemoryArray(scip, &statistics->noldbranchused);
    5940 SCIPfreeMemoryArray(scip, &statistics->npropdomred);
    5941 SCIPfreeMemoryArray(scip, &statistics->nlpiterationsfsb);
    5942 SCIPfreeMemoryArray(scip, &statistics->nlpiterations);
    5943 SCIPfreeMemoryArray(scip, &statistics->nduplicatelps);
    5944 SCIPfreeMemoryArray(scip, &statistics->nlpssolvedfsb);
    5945 SCIPfreeMemoryArray(scip, &statistics->nlpssolved);
    5946 SCIPfreeMemoryArray(scip, &statistics->nfullcutoffs);
    5947 SCIPfreeMemoryArray(scip, &statistics->nsinglecutoffs);
    5948 SCIPfreeMemoryArray(scip, &statistics->nresults);
    5949 SCIPfreeMemory(scip, &statistics);
    5950#endif
    5951
    5952 return SCIP_OKAY;
    5953}
    5954
    5955/** solving process deinitialization method of branching rule (called before branch and bound process data is freed) */
    5956static
    5957SCIP_DECL_BRANCHEXITSOL(branchExitSolLookahead)
    5958{ /*lint --e{715}*/
    5959 SCIP_BRANCHRULEDATA* branchruledata;
    5960
    5961 branchruledata = SCIPbranchruleGetData(branchrule);
    5962 assert(branchruledata != NULL);
    5963
    5964 if( branchruledata->isinitialized )
    5965 {
    5966 SCIP_CALL( freePersistent(scip, branchruledata) );
    5967 }
    5968
    5969 return SCIP_OKAY;
    5970}
    5971
    5972/** branching execution method for fractional LP solutions */
    5973static
    5974SCIP_DECL_BRANCHEXECLP(branchExeclpLookahead)
    5975{ /*lint --e{715}*/
    5976 SCIP_BRANCHRULEDATA* branchruledata;
    5977 CONFIGURATION* config;
    5978 SCIP_Bool userusebincons;
    5979
    5980 assert(branchrule != NULL);
    5981 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
    5982 assert(scip != NULL);
    5983 assert(result != NULL);
    5984
    5985 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Entering branchExeclpLookahead at node %lld.\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip)));
    5986
    5987 branchruledata = SCIPbranchruleGetData(branchrule);
    5988 assert(branchruledata != NULL);
    5989
    5990 config = branchruledata->config;
    5991
    5992 /* we are only allowed to add binary constraints, if the corresponding flag is given */
    5993 userusebincons = config->usebincons;
    5994 config->usebincons = config->usebincons && allowaddcons;
    5995
    5996 SCIP_CALL( initBranchruleData(scip, branchruledata) );
    5997
    5998 if( config->storeunviolatedsol
    5999 && isUsePreviousResult(scip, branchruledata) )
    6000 {
    6001 /* in case we stopped the previous run without a branching decision, we have stored the decision and execute it
    6002 * now */
    6003 SCIP_CALL( usePreviousResult(scip, branchruledata, result) );
    6004
    6005#ifdef SCIP_STATISTIC
    6006 branchruledata->statistics->noldcandidate++;
    6007#endif
    6008 }
    6009 else
    6010 {
    6011 BRANCHINGDECISION* decision;
    6012 SCORECONTAINER* scorecontainer = NULL;
    6013 CANDIDATELIST* candidatelist;
    6014 STATUS* status;
    6015#ifdef SCIP_STATISTIC
    6016 LOCALSTATISTICS* localstats;
    6017#endif
    6018
    6019 /* create a struct to store the algorithm status */
    6020 SCIP_CALL( statusCreate(scip, &status) );
    6021
    6022 /* create a struct to store the branching decision (in case there is one) */
    6023 SCIP_CALL( branchingDecisionCreate(scip, &decision) );
    6024 if( config->abbreviated )
    6025 {
    6026 /* allocate and init the container used to store the FSB scores, later used to filter the candidates */
    6027 SCIP_CALL( scoreContainerCreate(scip, &scorecontainer, config) );
    6028 }
    6029
    6031
    6032 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "The base lp has <%i> variables with fractional value.\n",
    6033 candidatelist->ncandidates);
    6034
    6035 /* execute the main logic */
    6036#ifdef SCIP_STATISTIC
    6037 /* create a struct to store the statistics needed for this single run */
    6038 SCIP_CALL( localStatisticsAllocate(scip, &localstats) );
    6039 SCIP_CALL( selectVarStart(scip, config, branchruledata->persistent, status, decision,
    6040 scorecontainer, candidatelist, branchruledata->statistics, localstats) );
    6041#else
    6042 SCIP_CALL( selectVarStart(scip, config, branchruledata->persistent, status, decision,
    6043 scorecontainer, candidatelist) );
    6044#endif
    6045
    6046 if( status->cutoff || status->domredcutoff )
    6047 {
    6048 *result = SCIP_CUTOFF;
    6049#ifdef SCIP_STATISTIC
    6050 branchruledata->statistics->ncutoffproofnodes += localstats->ncutoffproofnodes;
    6051#endif
    6052 }
    6053 else
    6054 {
    6055 if( status->addedbinconss )
    6056 {
    6057 *result = SCIP_CONSADDED;
    6058 }
    6059 else if( status->domred )
    6060 {
    6061 *result = SCIP_REDUCEDDOM;
    6062 }
    6063 else if( status->lperror )
    6064 {
    6065#ifdef SCIP_STATISTIC
    6066 ++branchruledata->statistics->nlperrorcalls;
    6067#endif
    6068 if( !branchingDecisionIsValid(decision) )
    6069 {
    6070 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "LP error with no valid candidate: select first candidate variable\n");
    6071
    6072 assert(candidatelist->ncandidates > 0);
    6073 decision->branchvar = candidatelist->candidates[0]->branchvar;
    6074 decision->branchval = candidatelist->candidates[0]->branchval;
    6075 }
    6076 }
    6077 else if( status->maxnconsreached )
    6078 {
    6079 /* this case may occure if the domain reductions that reached the limit were already applied via domain
    6080 * propagation
    6081 */
    6082 *result = SCIP_REDUCEDDOM;
    6083 }
    6084#ifdef SCIP_STATISTIC
    6085 else if( status->limitreached )
    6086 {
    6087 ++branchruledata->statistics->nlimitcalls;
    6088 }
    6089#endif
    6090 /* update lower bound of current node */
    6092 {
    6094 }
    6095 }
    6096
    6097 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Result before branching is %s\n", getStatusString(*result));
    6098
    6099 if( *result != SCIP_CUTOFF /* a variable could not be branched in any direction or any of the calculated domain
    6100 * reductions was infeasible */
    6101 && *result != SCIP_REDUCEDDOM /* the domain of a variable was reduced by evaluating the calculated cutoffs */
    6102 && *result != SCIP_CONSADDED /* implicit binary constraints were already added */
    6103 && !status->depthtoosmall /* branching depth wasn't high enough */
    6104 && branchingDecisionIsValid(decision)
    6105 /*&& (0 <= bestcand && bestcand < nlpcands)*/ /* no valid candidate index could be found */
    6106 )
    6107 {
    6108 LABdebugMessage(scip, SCIP_VERBLEVEL_NORMAL, " -> %d candidates, selected variable <%s> (solval=%g, down=%.9g, "
    6109 "up=%.9g)\n", candidatelist->ncandidates, SCIPvarGetName(decision->branchvar), decision->branchval,
    6110 decision->downdb, decision->updb);
    6111
    6112 /* execute the branching as a result of the branching logic */
    6113 SCIP_CALL( branchOnVar(scip, config, decision) );
    6114
    6115 *result = SCIP_BRANCHED;
    6116 }
    6117
    6118#ifdef SCIP_DEBUG
    6119 LABdebugMessage(scip, SCIP_VERBLEVEL_FULL, "Result after branching is %s\n", getStatusString(*result));
    6120
    6121 if( *result == SCIP_BRANCHED )
    6122 {
    6123 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Result: Finished LookaheadBranching by branching.\n");
    6124 }
    6125 else if( *result == SCIP_REDUCEDDOM )
    6126 {
    6127 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Result: Finished LookaheadBranching by reducing domains.\n");
    6128 }
    6129 else if( *result == SCIP_CUTOFF )
    6130 {
    6131 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Result: Finished LookaheadBranching by cutting off, as the current "
    6132 "problem is infeasible.\n");
    6133 }
    6134 else if( *result == SCIP_CONSADDED )
    6135 {
    6136 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Result: Finished LookaheadBranching by adding constraints.\n");
    6137 }
    6138 else if( status->depthtoosmall )
    6139 {
    6140 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Result: The remaining tree depth did not allow for multi level "
    6141 "lookahead branching.\n");
    6142 }
    6143 else
    6144 {
    6145 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Result: Could not find any variable to branch on.\n");
    6146 }
    6147#endif
    6148
    6149#ifdef SCIP_STATISTIC
    6150 localStatisticsFree(scip, &localstats);
    6151#endif
    6152 SCIP_CALL( candidateListFree(scip, &candidatelist) );
    6153
    6154 /* scorecontainer != NULL iff branchruledata->config->abbreviated == TRUE */
    6155 if( scorecontainer != NULL )
    6156 {
    6157 SCIP_CALL( scoreContainerFree(scip, &scorecontainer) );
    6158 }
    6159 branchingDecisionFree(scip, &decision);
    6160 statusFree(scip, &status);
    6161 }
    6162
    6163#ifdef SCIP_STATISTIC
    6164 assert(*result >= 1);
    6165 assert(*result <= MAXRESULT);
    6166 branchruledata->statistics->ntotalresults++;
    6167 branchruledata->statistics->nresults[*result]++;
    6168
    6169 if( config->abbreviated )
    6170 {
    6171 int sum;
    6172 int i;
    6173
    6174 sum = branchruledata->statistics->nsinglecandidate + branchruledata->statistics->nsingleafterfilter
    6175 + branchruledata->statistics->noldcandidate + branchruledata->statistics->nlperrorcalls
    6176 + branchruledata->statistics->nlimitcalls;
    6177
    6178 for( i = 0; i < branchruledata->statistics->maxnbestcands; i++ )
    6179 {
    6180 sum += branchruledata->statistics->chosenfsbcand[i];
    6181 }
    6182 if( sum != branchruledata->statistics->nresults[SCIP_BRANCHED] )
    6183 {
    6184 printf("branched = %d != sum = %d (%d/%d/%d/%d/%d)\n",
    6185 branchruledata->statistics->nresults[SCIP_BRANCHED], sum,
    6186 branchruledata->statistics->nsinglecandidate, branchruledata->statistics->nsingleafterfilter,
    6187 branchruledata->statistics->noldcandidate,
    6188 branchruledata->statistics->nlperrorcalls, branchruledata->statistics->nlimitcalls);
    6189 assert(SCIPisStopped(scip));
    6190 }
    6191 assert(sum == branchruledata->statistics->nresults[SCIP_BRANCHED]);
    6192 }
    6193
    6194 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "#### ncutoffproofnodes: %d ndomredproofnodes: %d\n",
    6195 branchruledata->statistics->ncutoffproofnodes, branchruledata->statistics->ndomredproofnodes);
    6196#endif
    6197
    6198 config->usebincons = userusebincons;
    6199
    6200 LABdebugMessage(scip, SCIP_VERBLEVEL_HIGH, "Exiting branchExeclpLookahead.\n");
    6201 return SCIP_OKAY;
    6202}
    6203
    6204/*
    6205 * branching rule specific interface methods
    6206 */
    6207
    6208/** creates the lookahead branching rule and includes it in SCIP */
    6210 SCIP* scip /**< SCIP data structure */
    6211 )
    6212{
    6213 SCIP_BRANCHRULEDATA* branchruledata;
    6214 SCIP_BRANCHRULE* branchrule;
    6215
    6216 /* create lookahead branching rule data */
    6217 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata) );
    6218 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata->config) );
    6219 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata->persistent) );
    6220 branchruledata->persistent->restartindex = 0;
    6221 branchruledata->isinitialized = FALSE;
    6222 branchruledata->config->inscoring = FALSE;
    6223
    6224 /* include branching rule */
    6226 BRANCHRULE_MAXDEPTH, BRANCHRULE_MAXBOUNDDIST, branchruledata) );
    6227
    6228 assert(branchrule != NULL);
    6229
    6230 /* set non fundamental callbacks via setter functions */
    6231 SCIP_CALL( SCIPsetBranchruleCopy(scip, branchrule, branchCopyLookahead) );
    6232 SCIP_CALL( SCIPsetBranchruleFree(scip, branchrule, branchFreeLookahead) );
    6233 SCIP_CALL( SCIPsetBranchruleInit(scip, branchrule, branchInitLookahead) );
    6234 SCIP_CALL( SCIPsetBranchruleExit(scip, branchrule, branchExitLookahead) );
    6235 SCIP_CALL( SCIPsetBranchruleExitsol(scip, branchrule, branchExitSolLookahead) );
    6236 SCIP_CALL( SCIPsetBranchruleExecLp(scip, branchrule, branchExeclpLookahead) );
    6237
    6238 /* add lookahead branching rule parameters */
    6240 "branching/lookahead/useimpliedbincons",
    6241 "should binary constraints be collected and applied?",
    6242 &branchruledata->config->usebincons, TRUE, DEFAULT_USEBINARYCONSTRAINTS, NULL, NULL) );
    6244 "branching/lookahead/addbinconsrow",
    6245 "should binary constraints be added as rows to the base LP? (0: no, 1: separate, 2: as initial rows)",
    6246 &branchruledata->config->addbinconsrow, TRUE, DEFAULT_ADDBINCONSROW, 0, 2, NULL, NULL) );
    6247 SCIP_CALL( SCIPaddIntParam(scip, "branching/lookahead/maxnviolatedcons",
    6248 "how many constraints that are violated by the base lp solution should be gathered until the rule is stopped and "\
    6249 "they are added? [0 for unrestricted]",
    6250 &branchruledata->config->maxnviolatedcons, TRUE, DEFAULT_MAXNVIOLATEDCONS, 0, INT_MAX, NULL, NULL) );
    6251 SCIP_CALL( SCIPaddIntParam(scip, "branching/lookahead/maxnviolatedbincons",
    6252 "how many binary constraints that are violated by the base lp solution should be gathered until the rule is "\
    6253 "stopped and they are added? [0 for unrestricted]",
    6254 &branchruledata->config->maxnviolatedbincons, TRUE, DEFAULT_MAXNVIOLATEDBINCONS, 0, INT_MAX, NULL, NULL) );
    6255 SCIP_CALL( SCIPaddIntParam(scip, "branching/lookahead/maxnviolateddomreds",
    6256 "how many domain reductions that are violated by the base lp solution should be gathered until the rule is "\
    6257 "stopped and they are added? [0 for unrestricted]",
    6258 &branchruledata->config->maxnviolateddomreds, TRUE, DEFAULT_MAXNVIOLATEDDOMREDS, 0, INT_MAX, NULL, NULL) );
    6260 "branching/lookahead/reevalage",
    6261 "max number of LPs solved after which a previous prob branching results are recalculated",
    6262 &branchruledata->config->reevalage, TRUE, DEFAULT_REEVALAGE, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
    6264 "branching/lookahead/reevalagefsb",
    6265 "max number of LPs solved after which a previous FSB scoring results are recalculated",
    6266 &branchruledata->config->reevalagefsb, TRUE, DEFAULT_REEVALAGEFSB, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
    6267 SCIP_CALL( SCIPaddIntParam(scip, "branching/lookahead/recursiondepth",
    6268 "the max depth of LAB.",
    6269 &branchruledata->config->recursiondepth, TRUE, DEFAULT_RECURSIONDEPTH, 1, INT_MAX, NULL, NULL) );
    6271 "branching/lookahead/usedomainreduction",
    6272 "should domain reductions be collected and applied?",
    6273 &branchruledata->config->usedomainreduction, TRUE, DEFAULT_USEDOMAINREDUCTION, NULL, NULL) );
    6275 "branching/lookahead/mergedomainreductions",
    6276 "should domain reductions of feasible siblings should be merged?",
    6277 &branchruledata->config->mergedomainreductions, TRUE, DEFAULT_MERGEDOMAINREDUCTIONS, NULL, NULL) );
    6279 "branching/lookahead/prefersimplebounds",
    6280 "should domain reductions only be applied if there are simple bound changes?",
    6281 &branchruledata->config->prefersimplebounds, TRUE, DEFAULT_PREFERSIMPLEBOUNDS, NULL, NULL) );
    6283 "branching/lookahead/onlyvioldomreds",
    6284 "should only domain reductions that violate the LP solution be applied?",
    6285 &branchruledata->config->onlyvioldomreds, TRUE, DEFAULT_ONLYVIOLDOMREDS, NULL, NULL) );
    6287 "branching/lookahead/addnonviocons",
    6288 "should binary constraints, that are not violated by the base LP, be collected and added?",
    6289 &branchruledata->config->addnonviocons, TRUE, DEFAULT_ADDNONVIOCONS, NULL, NULL) );
    6291 "branching/lookahead/abbreviated",
    6292 "toggles the abbreviated LAB.",
    6293 &branchruledata->config->abbreviated, TRUE, DEFAULT_ABBREVIATED, NULL, NULL) );
    6294 SCIP_CALL( SCIPaddIntParam(scip, "branching/lookahead/maxncands",
    6295 "if abbreviated: The max number of candidates to consider at the node.",
    6296 &branchruledata->config->maxncands, TRUE, DEFAULT_MAXNCANDS, 1, INT_MAX, NULL, NULL) );
    6297 SCIP_CALL( SCIPaddIntParam(scip, "branching/lookahead/maxndeepercands",
    6298 "if abbreviated: The max number of candidates to consider per deeper node.",
    6299 &branchruledata->config->maxndeepercands, TRUE, DEFAULT_MAXNDEEPERCANDS, 0, INT_MAX, NULL, NULL) );
    6301 "branching/lookahead/reusebasis",
    6302 "if abbreviated: Should the information gathered to obtain the best candidates be reused?",
    6303 &branchruledata->config->reusebasis, TRUE, DEFAULT_REUSEBASIS, NULL, NULL) );
    6305 "branching/lookahead/storeunviolatedsol",
    6306 "if only non violating constraints are added, should the branching decision be stored till the next call?",
    6307 &branchruledata->config->storeunviolatedsol, TRUE, DEFAULT_STOREUNVIOLATEDSOL, NULL, NULL) );
    6309 "branching/lookahead/abbrevpseudo",
    6310 "if abbreviated: Use pseudo costs to estimate the score of a candidate.",
    6311 &branchruledata->config->abbrevpseudo, TRUE, DEFAULT_ABBREVPSEUDO, NULL, NULL) );
    6313 "branching/lookahead/level2avgscore",
    6314 "should the average score be used for uninitialized scores in level 2?",
    6315 &branchruledata->config->level2avgscore, TRUE, DEFAULT_LEVEL2AVGSCORE, NULL, NULL) );
    6317 "branching/lookahead/level2zeroscore",
    6318 "should uninitialized scores in level 2 be set to 0?",
    6319 &branchruledata->config->level2zeroscore, TRUE, DEFAULT_LEVEL2ZEROSCORE, NULL, NULL) );
    6321 "branching/lookahead/addclique",
    6322 "add binary constraints with two variables found at the root node also as a clique",
    6323 &branchruledata->config->addclique, TRUE, DEFAULT_ADDCLIQUE, NULL, NULL) );
    6325 "branching/lookahead/propagate",
    6326 "should domain propagation be executed before each temporary node is solved?",
    6327 &branchruledata->config->propagate, TRUE, DEFAULT_PROPAGATE, NULL, NULL) );
    6329 "branching/lookahead/uselevel2data",
    6330 "should branching data generated at depth level 2 be stored for re-using it?",
    6331 &branchruledata->config->uselevel2data, TRUE, DEFAULT_USELEVEL2DATA, NULL, NULL) );
    6333 "branching/lookahead/applychildbounds",
    6334 "should bounds known for child nodes be applied?",
    6335 &branchruledata->config->applychildbounds, TRUE, DEFAULT_APPLYCHILDBOUNDS, NULL, NULL) );
    6337 "branching/lookahead/enforcemaxdomreds",
    6338 "should the maximum number of domain reductions maxnviolateddomreds be enforced?",
    6339 &branchruledata->config->enforcemaxdomreds, TRUE, DEFAULT_ENFORCEMAXDOMREDS, NULL, NULL) );
    6341 "branching/lookahead/updatebranchingresults",
    6342 "should branching results (and scores) be updated w.r.t. proven dual bounds?",
    6343 &branchruledata->config->updatebranchingresults, TRUE, DEFAULT_UPDATEBRANCHINGRESULTS, NULL, NULL) );
    6345 "branching/lookahead/maxproprounds",
    6346 "maximum number of propagation rounds to perform at each temporary node (-1: unlimited, 0: SCIP default)",
    6347 &branchruledata->config->maxproprounds, TRUE, DEFAULT_MAXPROPROUNDS, -1, INT_MAX, NULL, NULL) );
    6349 "branching/lookahead/scoringfunction",
    6350 "scoring function to be used at the base level",
    6351 &branchruledata->config->scoringfunction, TRUE, DEFAULT_SCORINGFUNCTION, "dfswplcra", NULL, NULL) );
    6353 "branching/lookahead/deeperscoringfunction",
    6354 "scoring function to be used at deeper levels",
    6355 &branchruledata->config->deeperscoringfunction, TRUE, DEFAULT_DEEPERSCORINGFUNCTION, "dfswlcrx", NULL, NULL) );
    6357 "branching/lookahead/scoringscoringfunction",
    6358 "scoring function to be used during FSB scoring",
    6359 &branchruledata->config->scoringscoringfunction, TRUE, DEFAULT_SCORINGSCORINGFUNCTION, "dfswlcr", NULL, NULL) );
    6361 "branching/lookahead/minweight",
    6362 "if scoringfunction is 's', this value is used to weight the min of the gains of two child problems in the convex combination",
    6363 &branchruledata->config->minweight, TRUE, DEFAULT_MINWEIGHT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    6365 "branching/lookahead/worsefactor",
    6366 "if the FSB score is of a candidate is worse than the best by this factor, skip this candidate (-1: disable)",
    6367 &branchruledata->config->worsefactor, TRUE, DEFAULT_WORSEFACTOR, -1.0, SCIP_REAL_MAX, NULL, NULL) );
    6369 "branching/lookahead/filterbymaxgain",
    6370 "should lookahead branching only be applied if the max gain in level 1 is not uniquely that of the best candidate?",
    6371 &branchruledata->config->filterbymaxgain, TRUE, DEFAULT_FILTERBYMAXGAIN, NULL, NULL) );
    6372
    6373 return SCIP_OKAY;
    6374}
    #define BRANCHRULE_DESC
    static SCIP_RETCODE selectVarStart(SCIP *scip, CONFIGURATION *config, PERSISTENTDATA *persistent, STATUS *status, BRANCHINGDECISION *decision, SCORECONTAINER *scorecontainer, CANDIDATELIST *candidatelist)
    static SCIP_Bool isCandidateReliable(SCIP *scip, SCIP_VAR *branchvar)
    static SCIP_DECL_BRANCHFREE(branchFreeLookahead)
    static SCIP_Bool warmStartInfoIsAvailable(WARMSTARTINFO *warmstartinfo)
    static void domainReductionsFree(SCIP *scip, DOMAINREDUCTIONS **domreds)
    #define DEFAULT_USEBINARYCONSTRAINTS
    static SCIP_RETCODE branchingDecisionEnsureBoundArraysSize(SCIP *scip, BRANCHINGDECISION *decision, int nvars)
    static void binConsDataFree(SCIP *scip, BINCONSDATA **consdata)
    static void level2resultFree(SCIP *scip, LEVEL2RESULT **result)
    static SCIP_RETCODE getOldBranching(SCIP *scip, PERSISTENTDATA *persistent, CONFIGURATION *config, SCIP_VAR *branchvar, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult, SCIP_Real *oldlpobjval)
    #define DEFAULT_UPDATEBRANCHINGRESULTS
    #define BRANCHRULE_PRIORITY
    static SCIP_RETCODE scoreContainerCreate(SCIP *scip, SCORECONTAINER **scorecontainer, CONFIGURATION *config)
    static SCIP_RETCODE applyDomainReductions(SCIP *scip, CONFIGURATION *config, SCIP_SOL *baselpsol, DOMAINREDUCTIONS *domreds, SCIP_Bool *domredcutoff, SCIP_Bool *domred)
    #define DEFAULT_PROPAGATE
    static SCIP_Real calculateScaledCutoffScore(BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult)
    static SCIP_DECL_BRANCHINIT(branchInitLookahead)
    static SCIP_RETCODE level2dataEnsureSize(SCIP *scip, LEVEL2DATA *data)
    #define DEFAULT_DEEPERSCORINGFUNCTION
    static SCIP_RETCODE executeBranching(SCIP *scip, CONFIGURATION *config, SCIP_Bool downbranching, CANDIDATE *candidate, BRANCHINGRESULTDATA *resultdata, SCIP_SOL *baselpsol, DOMAINREDUCTIONS *domreds, STATUS *status)
    static SCIP_RETCODE statusCreate(SCIP *scip, STATUS **status)
    static void addLowerBound(SCIP *scip, SCIP_VAR *var, SCIP_Real lowerbound, SCIP_SOL *baselpsol, SCIP_Bool simplechange, DOMAINREDUCTIONS *domainreductions)
    static SCIP_Real calculateScoreFromPseudocosts(SCIP *scip, CANDIDATE *lpcand)
    #define DEFAULT_SCORINGFUNCTION
    static void createBinaryConstraintName(SCIP_VAR **binaryvars, int nbinaryvars, char *constraintname)
    static SCIP_RETCODE executeBranchingRecursive(SCIP *scip, STATUS *status, CONFIGURATION *config, SCIP_SOL *baselpsol, CANDIDATE *candidate, SCIP_Real localbaselpsolval, SCIP_Real baselpobjval, int recursiondepth, DOMAINREDUCTIONS *domainreductions, BINCONSDATA *binconsdata, LEVEL2DATA *level2data, BRANCHINGRESULTDATA *branchingresult, SCORECONTAINER *scorecontainer, SCIP_Bool downbranching)
    static void binaryVarListDrop(BINARYVARLIST *list)
    #define DEFAULT_USELEVEL2DATA
    static SCIP_Bool areBoundsChanged(SCIP *scip, SCIP_VAR *var, SCIP_Real lowerbound, SCIP_Real upperbound)
    static SCIP_Bool isBranchFurther(STATUS *status, SCIP_Bool checkdomreds)
    #define DEFAULT_ENFORCEMAXDOMREDS
    static SCIP_RETCODE branchingResultDataCreate(SCIP *scip, BRANCHINGRESULTDATA **resultdata)
    static SCIP_RETCODE domainReductionsCreate(SCIP *scip, DOMAINREDUCTIONS **domreds)
    static SCIP_RETCODE copyCurrentSolution(SCIP *scip, SCIP_SOL **lpsol)
    static SCIP_DECL_BRANCHEXIT(branchExitLookahead)
    #define DEFAULT_ABBREVIATED
    static SCIP_RETCODE warmStartInfoFree(SCIP *scip, WARMSTARTINFO **warmstartinfo)
    #define DEFAULT_MERGEDOMAINREDUCTIONS
    static void branchingResultDataCopy(BRANCHINGRESULTDATA *sourcedata, BRANCHINGRESULTDATA *targetdata)
    static SCIP_RETCODE applyBinaryConstraints(SCIP *scip, SCIP_NODE *basenode, CONSTRAINTLIST *conslist, CONFIGURATION *config, SCIP_Bool *consadded, SCIP_Bool *cutoff, SCIP_Bool *boundchange)
    static SCIP_RETCODE scoreContainerFree(SCIP *scip, SCORECONTAINER **scorecontainer)
    #define DEFAULT_ADDCLIQUE
    #define DEFAULT_REEVALAGE
    #define DEFAULT_REEVALAGEFSB
    static SCIP_RETCODE constraintListCreate(SCIP *scip, CONSTRAINTLIST **conslist, int startsize)
    static SCIP_Real calculateScoreFromDeeperscoreAndCutoffs(SCIP *scip, SCIP_VAR *branchvar, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult)
    static void scoreContainterResetBestSortedCands(SCORECONTAINER *scorecontainer)
    static SCIP_Bool isUsePreviousResult(SCIP *scip, SCIP_BRANCHRULEDATA *branchruledata)
    static SCIP_DECL_BRANCHEXECLP(branchExeclpLookahead)
    static SCIP_RETCODE ensureScoresPresent(SCIP *scip, STATUS *status, PERSISTENTDATA *persistent, CONFIGURATION *config, SCIP_SOL *baselpsol, DOMAINREDUCTIONS *domainreductions, BINCONSDATA *binconsdata, CANDIDATELIST *allcandidates, BRANCHINGDECISION *decision, SCORECONTAINER *scorecontainer, LEVEL2DATA *level2data, SCIP_Real lpobjval)
    static SCIP_RETCODE candidateCreate(SCIP *scip, CANDIDATE **candidate)
    #define DEFAULT_MAXNDEEPERCANDS
    static SCIP_RETCODE candidateListCreate(SCIP *scip, CANDIDATELIST **candidatelist, int ncandidates)
    static SCIP_Bool isBranchFurtherLoopDecrement(STATUS *status, int *loopcounter)
    #define BRANCHRULE_NAME
    static void binaryVarListAppend(SCIP *scip, BINARYVARLIST *list, SCIP_VAR *vartoadd)
    #define level2resultPrint(scip, result)
    static SCIP_Bool level2resultEqual(LEVEL2RESULT *result1, LEVEL2RESULT *result2)
    static SCIP_Real calculateScore(SCIP *scip, CONFIGURATION *config, SCIP_VAR *branchvar, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult, SCIP_Real lpobjval, SCIP_Real baselpobjval)
    static SCIP_DECL_BRANCHCOPY(branchCopyLookahead)
    static SCIP_RETCODE usePreviousResult(SCIP *scip, SCIP_BRANCHRULEDATA *branchruledata, SCIP_RESULT *result)
    static SCIP_RETCODE level2resultCreateFromData(SCIP *scip, LEVEL2DATA *data, LEVEL2RESULT **result)
    static SCIP_RETCODE candidateListKeep(SCIP *scip, CANDIDATELIST *candidatelist, int nindices)
    static SCIP_RETCODE filterCandidates(SCIP *scip, STATUS *status, PERSISTENTDATA *persistent, CONFIGURATION *config, SCIP_SOL *baselpsol, DOMAINREDUCTIONS *domainreductions, BINCONSDATA *binconsdata, CANDIDATELIST *candidatelist, BRANCHINGDECISION *decision, SCORECONTAINER *scorecontainer, LEVEL2DATA *level2data, SCIP_Real lpobjval)
    #define DEFAULT_APPLYCHILDBOUNDS
    static SCIP_Real calculateScoreFromResult2(SCIP *scip, SCIP_VAR *branchvar, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult, SCIP_Real lpobjval)
    static SCIP_RETCODE initBranchruleData(SCIP *scip, SCIP_BRANCHRULEDATA *branchruledata)
    #define DEFAULT_MINWEIGHT
    static int findInsertionPoint(SCIP *scip, SCORECONTAINER *scorecontainer, SCIP_Real scoretoinsert, CANDIDATE **candidates, int ncandidates)
    static SCIP_RETCODE candidateFree(SCIP *scip, CANDIDATE **candidate)
    static SCIP_RETCODE candidateListGetAllFractionalCandidates(SCIP *scip, CANDIDATELIST **candidatelist)
    #define DEFAULT_ADDBINCONSROW
    static SCIP_RETCODE selectVarRecursive(SCIP *scip, STATUS *status, PERSISTENTDATA *persistent, CONFIGURATION *config, SCIP_SOL *baselpsol, DOMAINREDUCTIONS *domainreductions, BINCONSDATA *binconsdata, CANDIDATELIST *candidatelist, BRANCHINGDECISION *decision, SCORECONTAINER *scorecontainer, LEVEL2DATA *level2data, int recursiondepth, SCIP_Real lpobjval, SCIP_Real baselpobjval, SCIP_Longint *niterations, int *ndeepestcutoffs, SCIP_Real *bestgain, SCIP_Real *totalgains, int *ntotalgains, int *ndeepestnodes)
    static void binaryVarListFree(SCIP *scip, BINARYVARLIST **list)
    static SCIP_RETCODE getNIterationsLastLP(SCIP *scip, SCIP_Longint *iterations)
    static SCIP_RETCODE binConsDataCreate(SCIP *scip, BINCONSDATA **consdata, int maxdepth, int nstartcons)
    static SCIP_RETCODE candidateStoreWarmStartInfo(SCIP *scip, CANDIDATE *candidate, SCIP_Bool down)
    #define DEFAULT_LEVEL2AVGSCORE
    static SCIP_RETCODE branchOnVar(SCIP *scip, CONFIGURATION *config, BRANCHINGDECISION *decision)
    static void statusFree(SCIP *scip, STATUS **status)
    static SCIP_RETCODE level2dataCreate(SCIP *scip, LEVEL2DATA **data)
    static void applyDeeperDomainReductions(SCIP *scip, SCIP_SOL *baselpsol, int maxstoredomreds, DOMAINREDUCTIONS *targetdomreds, DOMAINREDUCTIONS *downdomreds, DOMAINREDUCTIONS *updomreds)
    static void level2dataFree(SCIP *scip, LEVEL2DATA **data)
    static SCIP_Bool isUseOldBranching(SCIP *scip, PERSISTENTDATA *persistent, CONFIGURATION *config, SCIP_VAR *branchvar)
    static SCIP_DECL_BRANCHEXITSOL(branchExitSolLookahead)
    static void addUpperBound(SCIP *scip, SCIP_VAR *var, SCIP_Real upperbound, SCIP_SOL *baselpsol, SCIP_Bool simplechange, DOMAINREDUCTIONS *domainreductions)
    static SCIP_RETCODE freePersistent(SCIP *scip, SCIP_BRANCHRULEDATA *branchruledata)
    static void branchingDecisionFree(SCIP *scip, BRANCHINGDECISION **decision)
    static SCIP_RETCODE level2dataGetResult(SCIP *scip, LEVEL2DATA *data, LEVEL2RESULT **result)
    static SCIP_RETCODE candidateFreeWarmStartInfo(SCIP *scip, CANDIDATE *candidate)
    static SCIP_Real calculateScoreFromDeeperscore(SCIP *scip, SCIP_VAR *branchvar, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult)
    static void branchingDecisionCopy(BRANCHINGDECISION *sourcedecision, BRANCHINGDECISION *targetdecision)
    SCIP_RETCODE SCIPincludeBranchruleLookahead(SCIP *scip)
    static SCIP_RETCODE scoreContainerSetScore(SCIP *scip, SCORECONTAINER *scorecontainer, CANDIDATE *cand, SCIP_Real score, SCIP_Real downgain, SCIP_Real upgain)
    #define DEFAULT_REUSEBASIS
    static void constraintListFree(SCIP *scip, CONSTRAINTLIST **conslist)
    static SCIP_RETCODE addBinaryConstraint(SCIP *scip, CONFIGURATION *config, BINCONSDATA *binconsdata, SCIP_SOL *baselpsol)
    #define DEFAULT_RECURSIONDEPTH
    static SCIP_RETCODE candidateListFree(SCIP *scip, CANDIDATELIST **candidatelist)
    static SCIP_Real calculateWeightedCutoffScore(CONFIGURATION *config, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult)
    #define DEFAULT_USEDOMAINREDUCTION
    static SCIP_RETCODE warmStartInfoCreate(SCIP *scip, WARMSTARTINFO **warmstartinfo)
    static SCIP_Bool isStoreDecision(CONFIGURATION *config, BINCONSDATA *binconsdata, DOMAINREDUCTIONS *domainreductions)
    #define DEFAULT_MAXNVIOLATEDCONS
    static void applySingleDeeperDomainReductions(SCIP *scip, SCIP_SOL *baselpsol, int maxstoredomreds, DOMAINREDUCTIONS *targetdomreds, DOMAINREDUCTIONS *domreds)
    static CANDIDATE * scoreContainerUpdateSortOrder(SCORECONTAINER *scorecontainer, CANDIDATE *candidate, int insertpoint)
    static SCIP_RETCODE constraintListAppend(SCIP *scip, CONSTRAINTLIST *list, SCIP_VAR **consvars, int nconsvars, SCIP_Bool violated)
    static SCIP_RETCODE binaryVarListCreate(SCIP *scip, BINARYVARLIST **list, int startsize)
    static SCIP_RETCODE createBinaryConstraint(SCIP *scip, CONFIGURATION *config, SCIP_CONS **constraint, char *constraintname, SCIP_VAR **consvars, int nconsvars)
    static SCIP_Bool candidateHasWarmStartInfo(CANDIDATE *candidate, SCIP_Bool down)
    #define DEFAULT_SCORINGSCORINGFUNCTION
    static void branchingResultDataFree(SCIP *scip, BRANCHINGRESULTDATA **resultdata)
    #define LABdebugMessage(scip, lvl,...)
    static SCIP_RETCODE updateOldBranching(SCIP *scip, PERSISTENTDATA *persistent, CONFIGURATION *config, SCIP_VAR *branchvar, SCIP_Real branchval, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult, SCIP_Real lpobjval)
    #define DEFAULT_STOREUNVIOLATEDSOL
    static SCIP_Bool isCurrentNodeCutoff(SCIP *scip)
    #define DEFAULT_WORSEFACTOR
    #define DEFAULT_MAXNVIOLATEDBINCONS
    static SCIP_RETCODE level2dataStoreResult(SCIP *scip, LEVEL2DATA *data, SCIP_Real lpobjval, SCIP_Bool cutoff, SCIP_Bool valid, SCIP_Bool *duplicate)
    #define DEFAULT_ABBREVPSEUDO
    #define DEFAULT_PREFERSIMPLEBOUNDS
    static SCIP_Real calculateWeightedGain(SCIP *scip, CONFIGURATION *config, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult, SCIP_Real lpobjval)
    #define DEFAULT_FILTERBYMAXGAIN
    #define DEFAULT_MAXPROPROUNDS
    static void branchingResultDataInit(SCIP *scip, BRANCHINGRESULTDATA *resultdata)
    static SCIP_Real calculateRelCutoffScore(SCIP *scip, SCIP_VAR *branchvar, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult, SCIP_Real lpobjval)
    static SCIP_Real calculateCutoffScore(SCIP *scip, SCIP_VAR *branchvar, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult, SCIP_Real lpobjval)
    static void sortFirstCandidatesByScore(SCIP *scip, CANDIDATELIST *candidatelist, SCORECONTAINER *scorecontainer, int nbestcandidates)
    #define BRANCHRULE_MAXDEPTH
    #define DEFAULT_ONLYVIOLDOMREDS
    static SCIP_RETCODE branchingDecisionCreate(SCIP *scip, BRANCHINGDECISION **decision)
    static SCIP_Real calculateScoreFromResult(SCIP *scip, SCIP_VAR *branchvar, BRANCHINGRESULTDATA *downbranchingresult, BRANCHINGRESULTDATA *upbranchingresult, SCIP_Real lpobjval)
    static SCIP_RETCODE getFSBResult(SCIP *scip, STATUS *status, PERSISTENTDATA *persistent, CONFIGURATION *config, SCIP_SOL *baselpsol, DOMAINREDUCTIONS *domainreductions, BINCONSDATA *binconsdata, CANDIDATELIST *candidatelist, BRANCHINGDECISION *decision, SCORECONTAINER *scorecontainer, LEVEL2DATA *level2data, SCIP_Real lpobjval)
    #define DEFAULT_ADDNONVIOCONS
    static SCIP_Bool branchingDecisionIsValid(BRANCHINGDECISION *decision)
    #define BRANCHRULE_MAXBOUNDDIST
    static void branchingDecisionInit(SCIP *scip, BRANCHINGDECISION *decision)
    static SCIP_RETCODE candidateLoadWarmStartInfo(SCIP *scip, CANDIDATE *candidate, SCIP_Bool down)
    #define DEFAULT_MAXNVIOLATEDDOMREDS
    #define DEFAULT_LEVEL2ZEROSCORE
    #define DEFAULT_MAXNCANDS
    lookahead LP branching rule
    Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
    #define NULL
    Definition: def.h:248
    #define SCIP_MAXSTRLEN
    Definition: def.h:269
    #define SCIP_Longint
    Definition: def.h:141
    #define SCIP_MAXTREEDEPTH
    Definition: def.h:297
    #define SCIP_Shortbool
    Definition: def.h:99
    #define SCIP_REAL_MAX
    Definition: def.h:158
    #define SCIP_INVALID
    Definition: def.h:178
    #define SCIP_Bool
    Definition: def.h:91
    #define MIN(x, y)
    Definition: def.h:224
    #define SCIP_Real
    Definition: def.h:156
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define MAX(x, y)
    Definition: def.h:220
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:148
    #define SCIPABORT()
    Definition: def.h:327
    #define SCIP_LONGINT_MAX
    Definition: def.h:142
    #define SCIP_CALL(x)
    Definition: def.h:355
    SCIP_RETCODE SCIPcreateConsLogicor(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:759
    int SCIPgetNContVars(SCIP *scip)
    Definition: scip_prob.c:2569
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    SCIP_VAR ** SCIPgetVars(SCIP *scip)
    Definition: scip_prob.c:2201
    int SCIPgetNContImplVars(SCIP *scip)
    Definition: scip_prob.c:2522
    SCIP_RETCODE SCIPlpiFreeNorms(SCIP_LPI *lpi, BMS_BLKMEM *blkmem, SCIP_LPINORMS **lpinorms)
    Definition: lpi_clp.cpp:3651
    SCIP_Bool SCIPlpiIsPrimalFeasible(SCIP_LPI *lpi)
    Definition: lpi_clp.cpp:2549
    SCIP_Bool SCIPlpiIsDualFeasible(SCIP_LPI *lpi)
    Definition: lpi_clp.cpp:2637
    SCIP_RETCODE SCIPlpiGetNorms(SCIP_LPI *lpi, BMS_BLKMEM *blkmem, SCIP_LPINORMS **lpinorms)
    Definition: lpi_clp.cpp:3620
    SCIP_RETCODE SCIPlpiFreeState(SCIP_LPI *lpi, BMS_BLKMEM *blkmem, SCIP_LPISTATE **lpistate)
    Definition: lpi_clp.cpp:3531
    SCIP_RETCODE SCIPlpiGetIterations(SCIP_LPI *lpi, int *iterations)
    Definition: lpi_clp.cpp:2949
    SCIP_RETCODE SCIPlpiGetState(SCIP_LPI *lpi, BMS_BLKMEM *blkmem, SCIP_LPISTATE **lpistate)
    Definition: lpi_clp.cpp:3417
    SCIP_RETCODE SCIPupdateNodeLowerbound(SCIP *scip, SCIP_NODE *node, SCIP_Real newbound)
    Definition: scip_prob.c:4354
    SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
    Definition: scip_prob.c:4289
    SCIP_RETCODE SCIPaddConsNode(SCIP *scip, SCIP_NODE *node, SCIP_CONS *cons, SCIP_NODE *validnode)
    Definition: scip_prob.c:3901
    void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:208
    void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:225
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    SCIP_RETCODE SCIPgetBoolParam(SCIP *scip, const char *name, SCIP_Bool *value)
    Definition: scip_param.c:250
    SCIP_RETCODE SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:111
    SCIP_RETCODE SCIPaddCharParam(SCIP *scip, const char *name, const char *desc, char *valueptr, SCIP_Bool isadvanced, char defaultvalue, const char *allowedvalues, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:167
    SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:83
    SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:139
    SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:57
    SCIP_RETCODE SCIPsetBranchruleExit(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHEXIT((*branchexit)))
    Definition: scip_branch.c:208
    SCIP_RETCODE SCIPsetBranchruleExecLp(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHEXECLP((*branchexeclp)))
    Definition: scip_branch.c:256
    SCIP_RETCODE SCIPsetBranchruleCopy(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHCOPY((*branchcopy)))
    Definition: scip_branch.c:160
    SCIP_RETCODE SCIPincludeBranchruleBasic(SCIP *scip, SCIP_BRANCHRULE **branchruleptr, const char *name, const char *desc, int priority, int maxdepth, SCIP_Real maxbounddist, SCIP_BRANCHRULEDATA *branchruledata)
    Definition: scip_branch.c:123
    const char * SCIPbranchruleGetName(SCIP_BRANCHRULE *branchrule)
    Definition: branch.c:2018
    SCIP_BRANCHRULEDATA * SCIPbranchruleGetData(SCIP_BRANCHRULE *branchrule)
    Definition: branch.c:1886
    SCIP_RETCODE SCIPsetBranchruleFree(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHFREE((*branchfree)))
    Definition: scip_branch.c:176
    SCIP_RETCODE SCIPsetBranchruleExitsol(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHEXITSOL((*branchexitsol)))
    Definition: scip_branch.c:240
    SCIP_RETCODE SCIPsetBranchruleInit(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHINIT((*branchinit)))
    Definition: scip_branch.c:192
    void SCIPbranchruleSetData(SCIP_BRANCHRULE *branchrule, SCIP_BRANCHRULEDATA *branchruledata)
    Definition: branch.c:1896
    SCIP_RETCODE SCIPbranchVarVal(SCIP *scip, SCIP_VAR *var, SCIP_Real val, SCIP_NODE **downchild, SCIP_NODE **eqchild, SCIP_NODE **upchild)
    Definition: scip_branch.c:1134
    SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
    Definition: scip_branch.c:402
    SCIP_Real SCIPgetBranchScore(SCIP *scip, SCIP_VAR *var, SCIP_Real downgain, SCIP_Real upgain)
    Definition: scip_branch.c:857
    int SCIPgetNPseudoBranchCands(SCIP *scip)
    Definition: scip_branch.c:766
    SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
    Definition: scip_cons.c:2536
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    SCIP_Bool SCIPisExact(SCIP *scip)
    Definition: scip_exact.c:193
    int SCIPgetNLPRows(SCIP *scip)
    Definition: scip_lp.c:632
    SCIP_RETCODE SCIPgetLPI(SCIP *scip, SCIP_LPI **lpi)
    Definition: scip_lp.c:994
    SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
    Definition: scip_lp.c:174
    SCIP_Bool SCIPallColsInLP(SCIP *scip)
    Definition: scip_lp.c:655
    SCIP_Real SCIPgetLPObjval(SCIP *scip)
    Definition: scip_lp.c:253
    #define SCIPfreeBuffer(scip, ptr)
    Definition: scip_mem.h:134
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    BMS_BLKMEM * SCIPblkmem(SCIP *scip)
    Definition: scip_mem.c:57
    #define SCIPallocMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:64
    #define SCIPallocClearBufferArray(scip, ptr, num)
    Definition: scip_mem.h:126
    int SCIPcalcMemGrowSize(SCIP *scip, int num)
    Definition: scip_mem.c:139
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPallocMemory(scip, ptr)
    Definition: scip_mem.h:60
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #define SCIPfreeMemoryArray(scip, ptr)
    Definition: scip_mem.h:80
    #define SCIPfreeMemory(scip, ptr)
    Definition: scip_mem.h:78
    #define SCIPallocBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:93
    #define SCIPallocBuffer(scip, ptr)
    Definition: scip_mem.h:122
    #define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
    Definition: scip_mem.h:99
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    #define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
    Definition: scip_mem.h:105
    SCIP_Real SCIPnodeGetLowerbound(SCIP_NODE *node)
    Definition: tree.c:8503
    SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
    Definition: tree.c:8483
    SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
    Definition: tree.c:8523
    int SCIPgetProbingDepth(SCIP *scip)
    Definition: scip_probing.c:199
    SCIP_RETCODE SCIPchgVarUbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_probing.c:346
    SCIP_RETCODE SCIPsetProbingLPState(SCIP *scip, SCIP_LPISTATE **lpistate, SCIP_LPINORMS **lpinorms, SCIP_Bool primalfeas, SCIP_Bool dualfeas)
    Definition: scip_probing.c:882
    SCIP_RETCODE SCIPchgVarLbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_probing.c:302
    SCIP_RETCODE SCIPpropagateProbing(SCIP *scip, int maxproprounds, SCIP_Bool *cutoff, SCIP_Longint *ndomredsfound)
    Definition: scip_probing.c:581
    SCIP_RETCODE SCIPbacktrackProbing(SCIP *scip, int probingdepth)
    Definition: scip_probing.c:226
    SCIP_Bool SCIPinProbing(SCIP *scip)
    Definition: scip_probing.c:98
    SCIP_RETCODE SCIPnewProbingNode(SCIP *scip)
    Definition: scip_probing.c:166
    SCIP_RETCODE SCIPsolveProbingLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
    Definition: scip_probing.c:825
    SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
    Definition: scip_sol.c:1252
    SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:608
    SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1506
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1765
    SCIP_Longint SCIPgetNNodeZeroIterationLPs(SCIP *scip)
    SCIP_Longint SCIPgetNNodes(SCIP *scip)
    SCIP_Longint SCIPgetNTotalNodes(SCIP *scip)
    SCIP_Longint SCIPgetNNodeLPIterations(SCIP *scip)
    SCIP_Longint SCIPgetNLPs(SCIP *scip)
    SCIP_Real SCIPgetCutoffbound(SCIP *scip)
    SCIP_Longint SCIPgetNNodeLPs(SCIP *scip)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisRelGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPsumepsilon(SCIP *scip)
    SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisSumLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    int SCIPgetCutoffdepth(SCIP *scip)
    Definition: scip_tree.c:498
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
    Definition: scip_tree.c:91
    SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:6401
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23478
    SCIP_RETCODE SCIPaddClique(SCIP *scip, SCIP_VAR **vars, SCIP_Bool *values, int nvars, SCIP_Bool isequation, SCIP_Bool *infeasible, int *nbdchgs)
    Definition: scip_var.c:8882
    SCIP_Real SCIPgetVarPseudocostCountCurrentRun(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR dir)
    Definition: scip_var.c:11350
    SCIP_RETCODE SCIPendStrongbranch(SCIP *scip)
    Definition: scip_var.c:3488
    SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23498
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24268
    SCIP_RETCODE SCIPchgVarUbNode(SCIP *scip, SCIP_NODE *node, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_var.c:6088
    SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:6651
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23453
    int SCIPvarGetProbindex(SCIP_VAR *var)
    Definition: var.c:23662
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23267
    SCIP_Longint SCIPgetVarStrongbranchNode(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:5019
    SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
    Definition: scip_var.c:5634
    SCIP_Longint SCIPgetVarStrongbranchLPAge(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:5053
    SCIP_RETCODE SCIPsetVarStrongbranchData(SCIP *scip, SCIP_VAR *var, SCIP_Real lpobjval, SCIP_Real primsol, SCIP_Real down, SCIP_Real up, SCIP_Bool downvalid, SCIP_Bool upvalid, SCIP_Longint iter, int itlim)
    Definition: scip_var.c:4903
    SCIP_Real SCIPgetVarPseudocostVal(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta)
    Definition: scip_var.c:11188
    SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
    Definition: scip_var.c:5570
    SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
    Definition: var.c:23490
    SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
    Definition: scip_var.c:2166
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24234
    SCIP_RETCODE SCIPupdateVarPseudocost(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta, SCIP_Real objdelta, SCIP_Real weight)
    Definition: scip_var.c:11122
    SCIP_RETCODE SCIPchgVarLbNode(SCIP *scip, SCIP_NODE *node, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_var.c:6044
    SCIP_RETCODE SCIPtryStrongbranchLPSol(SCIP *scip, SCIP_Bool *foundsol, SCIP_Bool *cutoff)
    Definition: scip_var.c:4938
    SCIP_RETCODE SCIPgetVarStrongbranchLast(SCIP *scip, SCIP_VAR *var, SCIP_Real *down, SCIP_Real *up, SCIP_Bool *downvalid, SCIP_Bool *upvalid, SCIP_Real *solval, SCIP_Real *lpobjval)
    Definition: scip_var.c:4869
    SCIP_Bool SCIPisStrongbranchDownFirst(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:3399
    void SCIPenableVarHistory(SCIP *scip)
    Definition: scip_var.c:11083
    SCIP_RETCODE SCIPstartStrongbranch(SCIP *scip, SCIP_Bool enablepropagation)
    Definition: scip_var.c:3430
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    interface methods for specific LP solvers
    memory allocation routines
    #define BMScopyMemoryArray(ptr, source, num)
    Definition: memory.h:134
    #define BMSclearMemoryArray(ptr, num)
    Definition: memory.h:130
    struct BMS_BlkMem BMS_BLKMEM
    Definition: memory.h:437
    public methods for branching rules
    public methods for message output
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    #define SCIPstatistic(x)
    Definition: pub_message.h:120
    public data structures and miscellaneous methods
    public methods for branch and bound tree
    public methods for problem variables
    public methods for branching rule plugins and branching
    public methods for constraint handler plugins and constraints
    public methods for exact solving
    general public methods
    public methods for the LP relaxation, rows and columns
    public methods for memory management
    public methods for message handling
    public methods for numerical tolerances
    public methods for SCIP parameter handling
    public methods for global and local (sub)problems
    public methods for the probing mode
    public methods for solutions
    public methods for querying solving statistics
    public methods for the branch-and-bound tree
    public methods for SCIP variables
    static SCIP_RETCODE separate(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
    Main separation function.
    Definition: sepa_flower.c:1221
    SCIP_VAR ** binaryvars
    CONSTRAINTLIST * conslist
    BINARYVARLIST * binaryvars
    SCIP_Real * downlowerbounds
    SCIP_Real * upupperbounds
    SCIP_Real * uplowerbounds
    SCIP_Real * downupperbounds
    SCIP_Longint niterations
    CANDIDATE ** candidates
    SCIP_Real fracval
    WARMSTARTINFO * downwarmstartinfo
    SCIP_VAR * branchvar
    SCIP_Real branchval
    WARMSTARTINFO * upwarmstartinfo
    SCIP_Bool usebincons
    SCIP_Bool applychildbounds
    SCIP_Bool usedomainreduction
    SCIP_Bool storeunviolatedsol
    SCIP_Bool level2avgscore
    SCIP_Real worsefactor
    SCIP_Longint reevalagefsb
    SCIP_Bool abbrevpseudo
    SCIP_Bool mergedomainreductions
    SCIP_Bool uselevel2data
    SCIP_Longint reevalage
    SCIP_Bool addnonviocons
    SCIP_Bool onlyvioldomreds
    SCIP_Bool reusebasis
    SCIP_Bool prefersimplebounds
    SCIP_Bool abbreviated
    SCIP_Bool enforcemaxdomreds
    SCIP_Bool updatebranchingresults
    SCIP_Bool level2zeroscore
    SCIP_Bool filterbymaxgain
    SCIP_VAR *** consvars
    SCIP_Bool * violated
    SCIP_Shortbool * baselpviolated
    SCIP_Real * lowerbounds
    SCIP_Real * upperbounds
    unsigned int branchvar1
    unsigned int branchdir2
    unsigned int branchdir1
    LEVEL2RESULT ** level2results
    SCIP_Real branchval2
    SCIP_Real branchval1
    unsigned int branchvar2
    unsigned int branchdir1
    unsigned int branchdir2
    unsigned int valid
    unsigned int cutoff
    SCIP_Real lpobjval
    unsigned int branchvar1
    SCIP_Real branchval1
    unsigned int branchvar2
    SCIP_Real branchval2
    SCIP_Longint * lastbranchid
    SCIP_Longint oldnnodelpiterations
    SCIP_Longint * lastbranchnlps
    BRANCHINGDECISION * olddecision
    SCIP_Real * lastbranchlpobjval
    SCIP_Longint oldntotalnodes
    SCIP_Longint oldnnodelps
    BRANCHINGRESULTDATA ** lastbranchdownres
    BRANCHINGRESULTDATA ** lastbranchupres
    SCIP_Real * scores
    SCIP_Real * downgains
    SCIP_Real * upgains
    CANDIDATE ** bestsortedcands
    SCIP_Bool limitreached
    SCIP_Bool domredcutoff
    SCIP_Bool addedbinconss
    SCIP_Bool cutoff
    SCIP_Bool lperror
    SCIP_Bool domred
    SCIP_Bool maxnconsreached
    SCIP_Bool depthtoosmall
    SCIP_LPISTATE * lpistate
    SCIP_Bool dualfeas
    SCIP_LPINORMS * lpinorms
    SCIP_Bool primalfeas
    struct SCIP_BranchruleData SCIP_BRANCHRULEDATA
    Definition: type_branch.h:57
    @ SCIP_BRANCHDIR_DOWNWARDS
    Definition: type_history.h:43
    @ SCIP_BRANCHDIR_UPWARDS
    Definition: type_history.h:44
    enum SCIP_LPSolStat SCIP_LPSOLSTAT
    Definition: type_lp.h:52
    @ SCIP_LPSOLSTAT_NOTSOLVED
    Definition: type_lp.h:43
    @ SCIP_LPSOLSTAT_TIMELIMIT
    Definition: type_lp.h:49
    @ SCIP_LPSOLSTAT_UNBOUNDEDRAY
    Definition: type_lp.h:46
    @ SCIP_LPSOLSTAT_INFEASIBLE
    Definition: type_lp.h:45
    @ SCIP_LPSOLSTAT_ITERLIMIT
    Definition: type_lp.h:48
    enum SCIP_VerbLevel SCIP_VERBLEVEL
    Definition: type_message.h:64
    @ SCIP_VERBLEVEL_HIGH
    Definition: type_message.h:61
    @ SCIP_VERBLEVEL_NORMAL
    Definition: type_message.h:60
    @ SCIP_VERBLEVEL_FULL
    Definition: type_message.h:62
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_CUTOFF
    Definition: type_result.h:48
    @ SCIP_FEASIBLE
    Definition: type_result.h:45
    @ SCIP_DELAYED
    Definition: type_result.h:43
    @ SCIP_REDUCEDDOM
    Definition: type_result.h:51
    @ SCIP_DIDNOTFIND
    Definition: type_result.h:44
    @ SCIP_CONSCHANGED
    Definition: type_result.h:53
    @ SCIP_CONSADDED
    Definition: type_result.h:52
    @ SCIP_UNBOUNDED
    Definition: type_result.h:47
    @ SCIP_FOUNDSOL
    Definition: type_result.h:56
    @ SCIP_SUSPENDED
    Definition: type_result.h:57
    @ SCIP_BRANCHED
    Definition: type_result.h:54
    @ SCIP_SEPARATED
    Definition: type_result.h:49
    @ SCIP_SOLVELP
    Definition: type_result.h:55
    @ SCIP_NEWROUND
    Definition: type_result.h:50
    @ SCIP_SUCCESS
    Definition: type_result.h:58
    @ SCIP_DELAYNODE
    Definition: type_result.h:59
    @ SCIP_INFEASIBLE
    Definition: type_result.h:46
    enum SCIP_Result SCIP_RESULT
    Definition: type_result.h:61
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    @ SCIP_VARTYPE_BINARY
    Definition: type_var.h:64