Scippy

    SCIP

    Solving Constraint Integer Programs

    branch_fullstrong.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_fullstrong.c
    26 * @ingroup DEFPLUGINS_BRANCH
    27 * @brief full strong LP branching rule
    28 * @author Tobias Achterberg
    29 * @author Gerald Gamrath
    30 */
    31
    32/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    33
    36#include "scip/pub_branch.h"
    37#include "scip/pub_message.h"
    38#include "scip/pub_tree.h"
    39#include "scip/pub_var.h"
    40#include "scip/scip_branch.h"
    41#include "scip/scip_exact.h"
    42#include "scip/scip_general.h"
    43#include "scip/scip_lp.h"
    44#include "scip/scip_mem.h"
    45#include "scip/scip_message.h"
    46#include "scip/scip_numerics.h"
    47#include "scip/scip_param.h"
    48#include "scip/scip_prob.h"
    50#include "scip/scip_tree.h"
    51#include "scip/scip_var.h"
    52#include <string.h>
    53
    54
    55#define BRANCHRULE_NAME "fullstrong"
    56#define BRANCHRULE_DESC "full strong branching"
    57#define BRANCHRULE_PRIORITY 0
    58#define BRANCHRULE_MAXDEPTH -1
    59#define BRANCHRULE_MAXBOUNDDIST 1.0
    60
    61#define DEFAULT_REEVALAGE 10LL /**< number of intermediate LPs solved to trigger reevaluation of strong branching
    62 * value for a variable that was already evaluated at the current node */
    63#define DEFAULT_MAXPROPROUNDS -2 /**< maximum number of propagation rounds to be performed during strong branching
    64 * before solving the LP (-1: no limit, -2: parameter settings) */
    65#define DEFAULT_PROBINGBOUNDS TRUE /**< should valid bounds be identified in a probing-like fashion during strong
    66 * branching (only with propagation)? */
    67#define DEFAULT_FORCESTRONGBRANCH FALSE /**< should strong branching be applied even if there is just a single candidate? */
    68
    69
    70/** branching rule data */
    71struct SCIP_BranchruleData
    72{
    73 SCIP_Longint reevalage; /**< number of intermediate LPs solved to trigger reevaluation of strong branching
    74 * value for a variable that was already evaluated at the current node */
    75 int maxproprounds; /**< maximum number of propagation rounds to be performed during strong branching
    76 * before solving the LP (-1: no limit, -2: parameter settings) */
    77 SCIP_Bool probingbounds; /**< should valid bounds be identified in a probing-like fashion during strong
    78 * branching (only with propagation)? */
    79 SCIP_Bool forcestrongbranch; /**< should strong branching be applied even if there is just a single candidate? */
    80 int lastcand; /**< last evaluated candidate of last branching rule execution */
    81 int skipsize; /**< size of skipdown and skipup array */
    82 SCIP_Bool* skipdown; /**< should be branching on down child be skipped? */
    83 SCIP_Bool* skipup; /**< should be branching on up child be skipped? */
    84};
    85
    86
    87/*
    88 * Callback methods
    89 */
    90
    91/** copy method for branchrule plugins (called when SCIP copies plugins) */
    92static
    93SCIP_DECL_BRANCHCOPY(branchCopyFullstrong)
    94{ /*lint --e{715}*/
    95 assert(scip != NULL);
    96 assert(branchrule != NULL);
    97 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
    98
    99 /* call inclusion method of branchrule */
    101
    102 return SCIP_OKAY;
    103}
    104
    105/** destructor of branching rule to free user data (called when SCIP is exiting) */
    106static
    107SCIP_DECL_BRANCHFREE(branchFreeFullstrong)
    108{ /*lint --e{715}*/
    109 SCIP_BRANCHRULEDATA* branchruledata;
    110
    111 /* free branching rule data */
    112 branchruledata = SCIPbranchruleGetData(branchrule);
    113 assert(branchruledata != NULL);
    114
    115 SCIPfreeBlockMemoryArrayNull(scip, &branchruledata->skipdown, branchruledata->skipsize);
    116 SCIPfreeBlockMemoryArrayNull(scip, &branchruledata->skipup, branchruledata->skipsize);
    117
    118 SCIPfreeBlockMemory(scip, &branchruledata);
    119 SCIPbranchruleSetData(branchrule, NULL);
    120
    121 return SCIP_OKAY;
    122}
    123
    124
    125/** initialization method of branching rule (called after problem was transformed) */
    126static
    127SCIP_DECL_BRANCHINIT(branchInitFullstrong)
    128{ /*lint --e{715}*/
    129 SCIP_BRANCHRULEDATA* branchruledata;
    130
    131 /* initialize branching rule data */
    132 branchruledata = SCIPbranchruleGetData(branchrule);
    133 assert(branchruledata != NULL);
    134
    135 branchruledata->lastcand = 0;
    136
    137 return SCIP_OKAY;
    138}
    139
    140/** deinitialization method of branching rule (called before transformed problem is freed) */
    141static
    142SCIP_DECL_BRANCHEXIT(branchExitFullstrong)
    143{ /*lint --e{715}*/
    144 SCIP_BRANCHRULEDATA* branchruledata;
    145
    146 /* initialize branching rule data */
    147 branchruledata = SCIPbranchruleGetData(branchrule);
    148 assert(branchruledata != NULL);
    149 assert((branchruledata->skipdown != NULL) == (branchruledata->skipup != NULL));
    150
    151 if( branchruledata->skipdown != NULL )
    152 {
    153 SCIPfreeBlockMemoryArray(scip, &branchruledata->skipup, branchruledata->skipsize);
    154 SCIPfreeBlockMemoryArray(scip, &branchruledata->skipdown, branchruledata->skipsize);
    155 branchruledata->skipdown = NULL;
    156 branchruledata->skipup = NULL;
    157 branchruledata->skipsize = 0;
    158 }
    159
    160 return SCIP_OKAY;
    161}
    162
    163/**
    164 * Selects a variable from a set of candidates by strong branching
    165 *
    166 * @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
    167 * SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
    168 *
    169 * @note The variables in the lpcands array must have a fractional value in the current LP solution
    170 */
    172 SCIP* scip, /**< original SCIP data structure */
    173 SCIP_VAR** lpcands, /**< branching candidates */
    174 SCIP_Real* lpcandssol, /**< solution values of the branching candidates */
    175 SCIP_Real* lpcandsfrac, /**< fractional values of the branching candidates */
    176 SCIP_Bool* skipdown, /**< should down branchings be skipped? */
    177 SCIP_Bool* skipup, /**< should up branchings be skipped? */
    178 int nlpcands, /**< number of branching candidates */
    179 int npriolpcands, /**< number of priority branching candidates */
    180 int ncomplete, /**< number of branching candidates without skip */
    181 int* start, /**< starting index in lpcands */
    182 int maxproprounds, /**< maximum number of propagation rounds to be performed during strong
    183 * branching before solving the LP (-1: no limit, -2: parameter settings) */
    184 SCIP_Bool probingbounds, /**< should valid bounds be identified in a probing-like fashion during
    185 * strong branching (only with propagation)? */
    186 SCIP_Bool forcestrongbranch, /**< should strong branching be applied even if there is just a single candidate? */
    187 int* bestcand, /**< best candidate for branching */
    188 SCIP_Real* bestdown, /**< objective value of the down branch for bestcand */
    189 SCIP_Real* bestup, /**< objective value of the up branch for bestcand */
    190 SCIP_Real* bestscore, /**< score for bestcand */
    191 SCIP_Bool* bestdownvalid, /**< is bestdown a valid dual bound for the down branch? */
    192 SCIP_Bool* bestupvalid, /**< is bestup a valid dual bound for the up branch? */
    193 SCIP_Real* provedbound, /**< proved dual bound for current subtree */
    194 SCIP_RESULT* result /**< result pointer */
    195 )
    196{ /*lint --e{715}*/
    197 SCIP_VAR** vars = NULL;
    198 SCIP_Real* newlbs = NULL;
    199 SCIP_Real* newubs = NULL;
    200 SCIP_BRANCHRULE* branchrule;
    201 SCIP_BRANCHRULEDATA* branchruledata;
    202 SCIP_Longint reevalage;
    203 SCIP_Longint nodenum;
    204 SCIP_Real down;
    205 SCIP_Real up;
    206 SCIP_Real downgain;
    207 SCIP_Real upgain;
    208 SCIP_Real score;
    209 SCIP_Real lpobjval;
    210 SCIP_Bool exactsolve;
    211 SCIP_Bool lperror;
    212 SCIP_Bool allcolsinlp;
    213 SCIP_Bool downvalid;
    214 SCIP_Bool upvalid;
    215 SCIP_Bool downinf;
    216 SCIP_Bool upinf;
    217 SCIP_Bool downconflict;
    218 SCIP_Bool upconflict;
    219 SCIP_Bool bothgains;
    220 SCIP_Bool propagate;
    221 int nvars = 0;
    222 int nsbcalls;
    223 int i;
    224 int c;
    225
    226 assert(scip != NULL);
    227 assert(lpcands != NULL);
    228 assert(lpcandssol != NULL);
    229 assert(lpcandsfrac != NULL);
    230 assert(bestcand != NULL);
    231 assert(skipdown != NULL);
    232 assert(skipup != NULL);
    233 assert(bestdown != NULL);
    234 assert(bestup != NULL);
    235 assert(bestscore != NULL);
    236 assert(bestdownvalid != NULL);
    237 assert(bestupvalid != NULL);
    238 assert(provedbound != NULL);
    239 assert(result != NULL);
    240 assert(nlpcands > 0);
    241
    242 /* check, if we want to solve the problem exactly, meaning that strong branching information is not useful
    243 * for cutting off sub problems and improving lower bounds of children
    244 */
    245 exactsolve = SCIPisExact(scip);
    246
    247 /* check, if all existing columns are in LP, and thus the strong branching results give lower bounds */
    248 allcolsinlp = SCIPallColsInLP(scip);
    249
    250 /* get current node number */
    251 nodenum = SCIPgetNNodes(scip);
    252
    253 /* get current LP objective bound of the local sub problem and global cutoff bound */
    254 lpobjval = SCIPgetLPObjval(scip);
    255 *provedbound = lpobjval;
    256
    257 *bestcand = 0;
    258 *bestdown = lpobjval;
    259 *bestup = lpobjval;
    260 *bestdownvalid = FALSE;
    261 *bestupvalid = FALSE;
    262 *bestscore = -SCIPinfinity(scip);
    263
    264 /* if only one candidate exists, choose this one without applying strong branching; also, when SCIP is about to be
    265 * stopped, all strongbranching evaluations will be aborted anyway, thus we can return immediately
    266 */
    267 if( (!forcestrongbranch && nlpcands == 1) || SCIPisStopped(scip) )
    268 return SCIP_OKAY;
    269
    270 /* this assert may not hold if SCIP is stopped, thus we only check it here */
    272
    273 /* get branching rule */
    275 assert(branchrule != NULL);
    276
    277 /* get branching rule data */
    278 branchruledata = SCIPbranchruleGetData(branchrule);
    279 assert(branchruledata != NULL);
    280
    281 /* auto-setting for reevalage */
    282 reevalage = branchruledata->reevalage;
    283
    284 /* check whether propagation should be performed */
    285 propagate = (maxproprounds != 0);
    286
    287 /* if we don't do propagation, we cannot identify valid bounds in a probing-like fashion */
    288 if( !propagate && maxproprounds > -3 )
    289 probingbounds = FALSE;
    290
    291 /* create arrays for probing-like bound tightening */
    292 if( probingbounds )
    293 {
    294 vars = SCIPgetVars(scip);
    295 nvars = SCIPgetNVars(scip);
    296
    297 SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
    298 SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
    299 }
    300
    301 /* initialize strong branching */
    302 SCIP_CALL( SCIPstartStrongbranch(scip, propagate) );
    303
    304 /* search the full strong candidate
    305 * cycle through the candidates, starting with the position evaluated in the last run
    306 */
    307 nsbcalls = 0;
    308 bothgains = FALSE;
    309 for( i = 0, c = *start; i < nlpcands && (!bothgains || i < ncomplete); ++i, ++c )
    310 {
    311 c = c % nlpcands;
    312 assert(lpcands[c] != NULL);
    313
    314 /* don't use strong branching on variables that have already been initialized at the current node,
    315 * and that were evaluated not too long ago
    316 */
    317 if( SCIPgetVarStrongbranchNode(scip, lpcands[c]) == nodenum
    318 && SCIPgetVarStrongbranchLPAge(scip, lpcands[c]) < reevalage )
    319 {
    320 SCIP_Real lastlpobjval;
    321
    322 /* use the score of the strong branching call at the current node */
    323 SCIP_CALL( SCIPgetVarStrongbranchLast(scip, lpcands[c], &down, &up, NULL, NULL, NULL, &lastlpobjval) );
    324 downgain = MAX(down - lastlpobjval, 0.0);
    325 upgain = MAX(up - lastlpobjval, 0.0);
    326 downvalid = FALSE;
    327 upvalid = FALSE;
    328 downinf = FALSE;
    329 upinf = FALSE;
    330 downconflict = FALSE;
    331 upconflict = FALSE;
    332 lperror = FALSE;
    333 SCIPdebugMsg(scip, "strong branching on variable <%s> already performed (lpage=%" SCIP_LONGINT_FORMAT ", down=%g (%+g), up=%g (%+g))\n",
    334 SCIPvarGetName(lpcands[c]), SCIPgetVarStrongbranchLPAge(scip, lpcands[c]), down, downgain, up, upgain);
    335 }
    336 else
    337 {
    338 SCIPdebugMsg(scip, "applying strong branching%s on variable <%s> with solution %g\n",
    339 propagate ? "with propagation" : "", SCIPvarGetName(lpcands[c]), lpcandssol[c]);
    340 assert(i >= ncomplete || (!skipdown[i] && !skipup[i]));
    341
    342 /* apply strong branching */
    343 up = -SCIPinfinity(scip);
    344 down = -SCIPinfinity(scip);
    345
    346 if( propagate )
    347 {
    348 SCIP_CALL( SCIPgetVarStrongbranchWithPropagation(scip, lpcands[c], lpcandssol[c], lpobjval, INT_MAX,
    349 maxproprounds, skipdown[i] ? NULL : &down, skipup[i] ? NULL : &up, &downvalid,
    350 &upvalid, NULL, NULL, &downinf, &upinf, &downconflict, &upconflict, &lperror, newlbs, newubs) );
    351
    352 SCIPdebugMsg(scip, "-> down=%.9g (gain=%.9g, valid=%u, inf=%u, conflict=%u), up=%.9g (gain=%.9g, valid=%u, inf=%u, conflict=%u)\n",
    353 down, down - lpobjval, downvalid, downinf, downconflict, up, up - lpobjval, upvalid, upinf, upconflict);
    354 }
    355 else
    356 {
    357 SCIP_CALL( SCIPgetVarStrongbranchFrac(scip, lpcands[c], INT_MAX, FALSE,
    358 skipdown[i] ? NULL : &down, skipup[i] ? NULL : &up, &downvalid, &upvalid, &downinf, &upinf,
    359 &downconflict, &upconflict, &lperror) );
    360 }
    361 nsbcalls++;
    362
    363 /* display node information line */
    364 if( SCIPgetDepth(scip) == 0 && nsbcalls % 100 == 0 )
    365 {
    367 }
    368
    369 /* check for an error in strong branching */
    370 if( lperror )
    371 {
    373 "(node %" SCIP_LONGINT_FORMAT ") error in strong branching call%s for variable <%s> with solution %g\n",
    374 SCIPgetNNodes(scip), propagate ? " with propagation" : "", SCIPvarGetName(lpcands[c]), lpcandssol[c]);
    375 break;
    376 }
    377
    378 /* evaluate strong branching */
    379 down = MAX(down, lpobjval);
    380 up = MAX(up, lpobjval);
    381 downgain = down - lpobjval;
    382 upgain = up - lpobjval;
    383 if( !SCIPisFeasZero(scip,downgain) && !SCIPisFeasZero(scip,upgain) )
    384 bothgains = TRUE;
    385
    386 assert(!allcolsinlp || exactsolve || !downvalid || downinf == SCIPisGE(scip, down, SCIPgetCutoffbound(scip)));
    387 assert(!allcolsinlp || exactsolve || !upvalid || upinf == SCIPisGE(scip, up, SCIPgetCutoffbound(scip)));
    388 assert(downinf || !downconflict);
    389 assert(upinf || !upconflict);
    390
    391 /* update pseudo cost values */
    392 if( !downinf && downvalid )
    393 {
    394 SCIP_CALL( SCIPupdateVarPseudocost(scip, lpcands[c], 0.0-lpcandsfrac[c], downgain, 1.0) );
    395 }
    396 if( !upinf && upvalid )
    397 {
    398 SCIP_CALL( SCIPupdateVarPseudocost(scip, lpcands[c], 1.0-lpcandsfrac[c], upgain, 1.0) );
    399 }
    400
    401 /* check if there are infeasible roundings */
    402 if( downinf || upinf )
    403 {
    404 /* if we didn't do propagation, we can only detect infeasibility if the LP is a valid relaxation */
    405 assert(allcolsinlp || propagate);
    406 assert(!exactsolve);
    407
    408 if( downinf && upinf )
    409 {
    410 /* both roundings are infeasible -> node is infeasible */
    411 *result = SCIP_CUTOFF;
    412 SCIPdebugMsg(scip, " -> variable <%s> is infeasible in both directions\n", SCIPvarGetName(lpcands[c]));
    413 break; /* terminate initialization loop, because node is infeasible */
    414 }
    415 else if( downinf )
    416 {
    417 SCIP_Bool infeasible;
    418 SCIP_Bool tightened;
    419
    420 /* downwards rounding is infeasible -> change lower bound of variable to upward rounding */
    421 SCIP_CALL( SCIPtightenVarLb(scip, lpcands[c], SCIPfeasCeil(scip, lpcandssol[c]), TRUE, &infeasible, &tightened) );
    422 assert(!infeasible);
    423
    424 /* if we did propagation, the bound change might already have been added */
    425 assert(tightened || propagate);
    426
    427 *result = SCIP_REDUCEDDOM;
    428 SCIPdebugMsg(scip, " -> variable <%s> is infeasible in downward branch\n", SCIPvarGetName(lpcands[c]));
    429 break; /* terminate initialization loop, because LP was changed */
    430 }
    431 else
    432 {
    433 SCIP_Bool infeasible;
    434 SCIP_Bool tightened;
    435
    436 /* upwards rounding is infeasible -> change upper bound of variable to downward rounding */
    437 assert(upinf);
    438 SCIP_CALL( SCIPtightenVarUb(scip, lpcands[c], SCIPfeasFloor(scip, lpcandssol[c]), TRUE, &infeasible, &tightened) );
    439 assert(!infeasible);
    440
    441 /* if we did propagation, the bound change might already have been added */
    442 assert(tightened || propagate);
    443
    444 *result = SCIP_REDUCEDDOM;
    445 SCIPdebugMsg(scip, " -> variable <%s> is infeasible in upward branch\n", SCIPvarGetName(lpcands[c]));
    446 break; /* terminate initialization loop, because LP was changed */
    447 }
    448 }
    449 else if( allcolsinlp && !exactsolve && downvalid && upvalid )
    450 {
    451 SCIP_Real minbound;
    452
    453 /* the minimal lower bound of both children is a proved lower bound of the current subtree */
    454 minbound = MIN(down, up);
    455 *provedbound = MAX(*provedbound, minbound);
    456
    457 /* apply probing-like bounds detected during strong branching */
    458 if( probingbounds )
    459 {
    460 int nboundchgs;
    461 int v;
    462
    463 assert(vars != NULL);
    464 assert(nvars > 0);
    465 assert(newlbs != NULL);
    466 assert(newubs != NULL);
    467
    468 nboundchgs = 0;
    469
    470 for( v = 0; v < nvars; ++v )
    471 {
    472 if( SCIPisGT(scip, newlbs[v], SCIPvarGetLbLocal(vars[v])) )
    473 {
    474 SCIPdebugMsg(scip, "better lower bound for variable <%s>: %.9g -> %.9g (strongbranching on var <%s>\n",
    475 SCIPvarGetName(vars[v]), SCIPvarGetLbLocal(vars[v]), newlbs[v], SCIPvarGetName(lpcands[c]));
    476
    477 SCIP_CALL( SCIPchgVarLb(scip, vars[v], newlbs[v]) );
    478 ++nboundchgs;
    479 }
    480 if( SCIPisLT(scip, newubs[v], SCIPvarGetUbLocal(vars[v])) )
    481 {
    482 SCIPdebugMsg(scip, "better upper bound for variable <%s>: %.9g -> %.9g (strongbranching on var <%s>\n",
    483 SCIPvarGetName(vars[v]), SCIPvarGetUbLocal(vars[v]), newubs[v], SCIPvarGetName(lpcands[c]));
    484
    485 SCIP_CALL( SCIPchgVarUb(scip, vars[v], newubs[v]) );
    486 ++nboundchgs;
    487 }
    488 }
    489
    490 if( nboundchgs > 0 )
    491 {
    492 *result = SCIP_REDUCEDDOM;
    493 SCIPdebugMsg(scip, " -> strong branching with propagation on variable <%s> led to %d bound changes\n",
    494 SCIPvarGetName(lpcands[c]), nboundchgs);
    495 break; /* terminate initialization loop, because LP was changed */
    496 }
    497 }
    498 }
    499 }
    500
    501 /* check for a better score, if we are within the maximum priority candidates */
    502 if( c < npriolpcands )
    503 {
    504 score = SCIPgetBranchScore(scip, lpcands[c], downgain, upgain);
    505 if( score > *bestscore )
    506 {
    507 *bestcand = c;
    508 *bestdown = down;
    509 *bestup = up;
    510 *bestdownvalid = downvalid;
    511 *bestupvalid = upvalid;
    512 *bestscore = score;
    513 }
    514 }
    515 else
    516 {
    517 SCIPdebug(score = 0.0;)
    518 }
    519
    520 SCIPdebugMsg(scip, " -> cand %d/%d (prio:%d) var <%s> (solval=%g, downgain=%g, upgain=%g, score=%g) -- best: <%s> (%g)\n",
    521 c, nlpcands, npriolpcands, SCIPvarGetName(lpcands[c]), lpcandssol[c], downgain, upgain, score,
    522 SCIPvarGetName(lpcands[*bestcand]), *bestscore);
    523 }
    524
    525 /* end strong branching */
    527
    528 *start = c;
    529
    530 if( probingbounds )
    531 {
    532 assert(newlbs != NULL);
    533 assert(newubs != NULL);
    534
    535 SCIPfreeBufferArray(scip, &newlbs);
    536 SCIPfreeBufferArray(scip, &newubs);
    537 }
    538
    539 return SCIP_OKAY;
    540}
    541
    542/** branching execution method for fractional LP solutions */
    543static
    544SCIP_DECL_BRANCHEXECLP(branchExeclpFullstrong)
    545{ /*lint --e{715}*/
    546 SCIP_BRANCHRULEDATA* branchruledata;
    547 SCIP_VAR** tmplpcands;
    548 SCIP_VAR** lpcands;
    549 SCIP_Real* tmplpcandssol;
    550 SCIP_Real* lpcandssol;
    551 SCIP_Real* tmplpcandsfrac;
    552 SCIP_Real* lpcandsfrac;
    553 SCIP_Real bestdown;
    554 SCIP_Real bestup;
    555 SCIP_Real bestscore;
    556 SCIP_Real provedbound;
    557 SCIP_Bool bestdownvalid;
    558 SCIP_Bool bestupvalid;
    559 int nlpcands;
    560 int npriolpcands;
    561 int bestcand;
    562
    563 assert(branchrule != NULL);
    564 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
    565 assert(scip != NULL);
    566 assert(result != NULL);
    567
    568 SCIPdebugMsg(scip, "Execlp method of fullstrong branching\n");
    569
    570 *result = SCIP_DIDNOTRUN;
    571
    572 /* get branching rule data */
    573 branchruledata = SCIPbranchruleGetData(branchrule);
    574 assert(branchruledata != NULL);
    575
    576 /* get branching candidates */
    577 SCIP_CALL( SCIPgetLPBranchCands(scip, &tmplpcands, &tmplpcandssol, &tmplpcandsfrac, &nlpcands, &npriolpcands, NULL) );
    578 assert(nlpcands > 0);
    579 assert(npriolpcands > 0);
    580
    581 /* copy LP banching candidates and solution values, because they will be updated w.r.t. the strong branching LP
    582 * solution
    583 */
    584 SCIP_CALL( SCIPduplicateBufferArray(scip, &lpcands, tmplpcands, nlpcands) );
    585 SCIP_CALL( SCIPduplicateBufferArray(scip, &lpcandssol, tmplpcandssol, nlpcands) );
    586 SCIP_CALL( SCIPduplicateBufferArray(scip, &lpcandsfrac, tmplpcandsfrac, nlpcands) );
    587
    588 if( branchruledata->skipdown == NULL )
    589 {
    590 assert(branchruledata->skipup == NULL);
    591
    592 branchruledata->skipsize = SCIPgetNVars(scip);
    593 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->skipdown, branchruledata->skipsize) );
    594 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->skipup, branchruledata->skipsize) );
    595 BMSclearMemoryArray(branchruledata->skipdown, branchruledata->skipsize);
    596 BMSclearMemoryArray(branchruledata->skipup, branchruledata->skipsize);
    597 }
    598
    599 SCIP_CALL( SCIPselectVarStrongBranching(scip, lpcands, lpcandssol, lpcandsfrac, branchruledata->skipdown,
    600 branchruledata->skipup, nlpcands, npriolpcands, nlpcands, &branchruledata->lastcand,
    601 branchruledata->maxproprounds, branchruledata->probingbounds, branchruledata->forcestrongbranch, &bestcand,
    602 &bestdown, &bestup, &bestscore, &bestdownvalid, &bestupvalid, &provedbound, result) );
    603
    604 if( *result != SCIP_CUTOFF )
    605 {
    606 SCIP_Bool allcolsinlp;
    607 SCIP_Bool exactsolve;
    608
    609 /* check, if we want to solve the problem exactly, meaning that strong branching information is not useful
    610 * for cutting off sub problems and improving lower bounds of children
    611 */
    612 exactsolve = SCIPisExact(scip);
    613
    614 /* check, if all existing columns are in LP, and thus the strong branching results give lower bounds */
    615 allcolsinlp = SCIPallColsInLP(scip);
    616
    617 /* update lower bound of current node */
    618 if( allcolsinlp && !exactsolve )
    619 {
    621 }
    622
    623 if( *result != SCIP_REDUCEDDOM && *result != SCIP_CONSADDED )
    624 {
    625 SCIP_NODE* downchild;
    626 SCIP_NODE* upchild;
    627 SCIP_VAR* var;
    628 SCIP_Real val;
    629
    630 assert(*result == SCIP_DIDNOTRUN);
    631 assert(0 <= bestcand && bestcand < nlpcands);
    632 assert(SCIPisLT(scip, provedbound, SCIPgetCutoffbound(scip)));
    633
    634 var = lpcands[bestcand];
    635 val = lpcandssol[bestcand];
    636
    637 /* perform the branching */
    638 SCIPdebugMsg(scip, " -> %d candidates, selected candidate %d: variable <%s> (solval=%g, down=%g, up=%g, score=%g)\n",
    639 nlpcands, bestcand, SCIPvarGetName(var), lpcandssol[bestcand], bestdown, bestup, bestscore);
    640 SCIP_CALL( SCIPbranchVarVal(scip, var, val, &downchild, NULL, &upchild) );
    641
    642 /* update the lower bounds in the children */
    643 if( allcolsinlp && !exactsolve )
    644 {
    645 if( downchild != NULL && bestdownvalid )
    646 {
    647 SCIP_CALL( SCIPupdateNodeLowerbound(scip, downchild, bestdown) );
    648 SCIPdebugMsg(scip, " -> down child's lowerbound: %g\n", SCIPnodeGetLowerbound(downchild));
    649 }
    650 if( upchild != NULL && bestupvalid )
    651 {
    652 SCIP_CALL( SCIPupdateNodeLowerbound(scip, upchild, bestup) );
    653 SCIPdebugMsg(scip, " -> up child's lowerbound: %g\n", SCIPnodeGetLowerbound(upchild));
    654 }
    655 }
    656
    657 *result = SCIP_BRANCHED;
    658 }
    659 }
    660
    661 SCIPfreeBufferArray(scip, &lpcandsfrac);
    662 SCIPfreeBufferArray(scip, &lpcandssol);
    663 SCIPfreeBufferArray(scip, &lpcands);
    664
    665 return SCIP_OKAY;
    666}
    667
    668
    669/*
    670 * branching specific interface methods
    671 */
    672
    673/** creates the full strong LP branching rule and includes it in SCIP */
    675 SCIP* scip /**< SCIP data structure */
    676 )
    677{
    678 SCIP_BRANCHRULEDATA* branchruledata;
    679 SCIP_BRANCHRULE* branchrule;
    680
    681 /* create fullstrong branching rule data */
    682 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata) );
    683 branchruledata->lastcand = 0;
    684 branchruledata->skipsize = 0;
    685 branchruledata->skipup = NULL;
    686 branchruledata->skipdown = NULL;
    687
    688 /* include branching rule */
    691
    692 assert(branchrule != NULL);
    693
    694 /* set non-fundamental callbacks via specific setter functions*/
    695 SCIP_CALL( SCIPsetBranchruleCopy(scip, branchrule, branchCopyFullstrong) );
    696 SCIP_CALL( SCIPsetBranchruleFree(scip, branchrule, branchFreeFullstrong) );
    697 SCIP_CALL( SCIPsetBranchruleInit(scip, branchrule, branchInitFullstrong) );
    698 SCIP_CALL( SCIPsetBranchruleExit(scip, branchrule, branchExitFullstrong) );
    699 SCIP_CALL( SCIPsetBranchruleExecLp(scip, branchrule, branchExeclpFullstrong) );
    700
    701 /* fullstrong branching rule parameters */
    703 "branching/fullstrong/reevalage",
    704 "number of intermediate LPs solved to trigger reevaluation of strong branching value for a variable that was already evaluated at the current node",
    705 &branchruledata->reevalage, TRUE, DEFAULT_REEVALAGE, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
    707 "branching/fullstrong/maxproprounds",
    708 "maximum number of propagation rounds to be performed during strong branching before solving the LP (-1: no limit, -2: parameter settings)",
    709 &branchruledata->maxproprounds, TRUE, DEFAULT_MAXPROPROUNDS, -3, INT_MAX, NULL, NULL) );
    711 "branching/fullstrong/probingbounds",
    712 "should valid bounds be identified in a probing-like fashion during strong branching (only with propagation)?",
    713 &branchruledata->probingbounds, TRUE, DEFAULT_PROBINGBOUNDS, NULL, NULL) );
    715 "branching/fullstrong/forcestrongbranch",
    716 "should strong branching be applied even if there is just a single candidate?",
    717 &branchruledata->forcestrongbranch, TRUE, DEFAULT_FORCESTRONGBRANCH, NULL, NULL) );
    718
    719 return SCIP_OKAY;
    720}
    #define BRANCHRULE_DESC
    #define BRANCHRULE_PRIORITY
    #define DEFAULT_PROBINGBOUNDS
    static SCIP_DECL_BRANCHEXIT(branchExitFullstrong)
    #define DEFAULT_REEVALAGE
    static SCIP_DECL_BRANCHINIT(branchInitFullstrong)
    #define BRANCHRULE_NAME
    static SCIP_DECL_BRANCHFREE(branchFreeFullstrong)
    #define DEFAULT_FORCESTRONGBRANCH
    #define DEFAULT_MAXPROPROUNDS
    #define BRANCHRULE_MAXDEPTH
    static SCIP_DECL_BRANCHCOPY(branchCopyFullstrong)
    #define BRANCHRULE_MAXBOUNDDIST
    static SCIP_DECL_BRANCHEXECLP(branchExeclpFullstrong)
    full strong LP branching rule
    #define NULL
    Definition: def.h:248
    #define SCIP_Longint
    Definition: def.h:141
    #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 SCIP_LONGINT_MAX
    Definition: def.h:142
    #define SCIP_CALL(x)
    Definition: def.h:355
    SCIP_RETCODE SCIPselectVarStrongBranching(SCIP *scip, SCIP_VAR **lpcands, SCIP_Real *lpcandssol, SCIP_Real *lpcandsfrac, SCIP_Bool *skipdown, SCIP_Bool *skipup, int nlpcands, int npriolpcands, int ncomplete, int *start, int maxproprounds, SCIP_Bool probingbounds, SCIP_Bool forcestrongbranch, int *bestcand, SCIP_Real *bestdown, SCIP_Real *bestup, SCIP_Real *bestscore, SCIP_Bool *bestdownvalid, SCIP_Bool *bestupvalid, SCIP_Real *provedbound, SCIP_RESULT *result)
    SCIP_RETCODE SCIPincludeBranchruleFullstrong(SCIP *scip)
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:759
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    SCIP_VAR ** SCIPgetVars(SCIP *scip)
    Definition: scip_prob.c:2201
    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
    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 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 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 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_BRANCHRULE * SCIPfindBranchrule(SCIP *scip, const char *name)
    Definition: scip_branch.c:304
    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 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
    SCIP_Bool SCIPisExact(SCIP *scip)
    Definition: scip_exact.c:193
    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 SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #define SCIPduplicateBufferArray(scip, ptr, source, num)
    Definition: scip_mem.h:132
    #define SCIPallocBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:93
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
    Definition: scip_mem.h:111
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    SCIP_Real SCIPnodeGetLowerbound(SCIP_NODE *node)
    Definition: tree.c:8503
    SCIP_Longint SCIPgetNNodes(SCIP *scip)
    SCIP_Real SCIPgetCutoffbound(SCIP *scip)
    SCIP_RETCODE SCIPprintDisplayLine(SCIP *scip, FILE *file, SCIP_VERBLEVEL verblevel, SCIP_Bool endline)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    SCIP_RETCODE SCIPgetVarStrongbranchFrac(SCIP *scip, SCIP_VAR *var, int itlim, SCIP_Bool idempotent, SCIP_Real *down, SCIP_Real *up, SCIP_Bool *downvalid, SCIP_Bool *upvalid, SCIP_Bool *downinf, SCIP_Bool *upinf, SCIP_Bool *downconflict, SCIP_Bool *upconflict, SCIP_Bool *lperror)
    Definition: scip_var.c:3664
    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_RETCODE SCIPendStrongbranch(SCIP *scip)
    Definition: scip_var.c:3488
    SCIP_RETCODE SCIPchgVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_var.c:5697
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24268
    SCIP_RETCODE SCIPchgVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_var.c:5875
    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
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23267
    SCIP_Longint SCIPgetVarStrongbranchNode(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:5019
    SCIP_Longint SCIPgetVarStrongbranchLPAge(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:5053
    SCIP_RETCODE SCIPgetVarStrongbranchWithPropagation(SCIP *scip, SCIP_VAR *var, SCIP_Real solval, SCIP_Real lpobjval, int itlim, int maxproprounds, SCIP_Real *down, SCIP_Real *up, SCIP_Bool *downvalid, SCIP_Bool *upvalid, SCIP_Longint *ndomredsdown, SCIP_Longint *ndomredsup, SCIP_Bool *downinf, SCIP_Bool *upinf, SCIP_Bool *downconflict, SCIP_Bool *upconflict, SCIP_Bool *lperror, SCIP_Real *newlbs, SCIP_Real *newubs)
    Definition: scip_var.c:4138
    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 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_RETCODE SCIPstartStrongbranch(SCIP *scip, SCIP_Bool enablepropagation)
    Definition: scip_var.c:3430
    memory allocation routines
    #define BMSclearMemoryArray(ptr, num)
    Definition: memory.h:130
    public methods for branching rules
    public methods for message output
    #define SCIPdebug(x)
    Definition: pub_message.h:93
    public methods for branch and bound tree
    public methods for problem variables
    public methods for branching rule plugins and branching
    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 querying solving statistics
    public methods for the branch-and-bound tree
    public methods for SCIP variables
    struct SCIP_BranchruleData SCIP_BRANCHRULEDATA
    Definition: type_branch.h:57
    @ SCIP_LPSOLSTAT_OPTIMAL
    Definition: type_lp.h:44
    @ SCIP_VERBLEVEL_HIGH
    Definition: type_message.h:61
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_CUTOFF
    Definition: type_result.h:48
    @ SCIP_REDUCEDDOM
    Definition: type_result.h:51
    @ SCIP_CONSADDED
    Definition: type_result.h:52
    @ SCIP_BRANCHED
    Definition: type_result.h:54
    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