Scippy

    SCIP

    Solving Constraint Integer Programs

    branch_multaggr.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/**@file branch_multaggr.c
    25 * @ingroup DEFPLUGINS_BRANCH
    26 * @brief fullstrong branching on fractional and multi-aggregated variables
    27 * @author Anna Melchiori
    28 * @author Gerald Gamrath
    29 *
    30 * This branching rule uses all fractional binary and integer variables as candidates,
    31 * as well as fractional multiaggregated binary and integer variables. Although not
    32 * directly contained in the presolved problem anymore, the multi-aggregation provides
    33 * an affine linear sum of integer variables, on which branching can be performed.
    34 *
    35 * For more details, see
    36 * G.Gamrath, A.Melchiori, T.Berthold, A.M.Gleixner, D.Salvagnin: Branching on Multi-aggregated Variables
    37 * (http://dx.doi.org/10.1007/978-3-319-18008-3_10)
    38 */
    39/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    40
    44#include "scip/cons_linear.h"
    45#include "scip/pub_branch.h"
    46#include "scip/pub_cons.h"
    47#include "scip/pub_message.h"
    48#include "scip/pub_tree.h"
    49#include "scip/pub_var.h"
    50#include "scip/scip_branch.h"
    51#include "scip/scip_cons.h"
    52#include "scip/scip_exact.h"
    53#include "scip/scip_general.h"
    54#include "scip/scip_lp.h"
    55#include "scip/scip_mem.h"
    56#include "scip/scip_message.h"
    57#include "scip/scip_numerics.h"
    58#include "scip/scip_param.h"
    59#include "scip/scip_prob.h"
    60#include "scip/scip_probing.h"
    62#include "scip/scip_timing.h"
    63#include "scip/scip_tree.h"
    64#include "scip/scip_var.h"
    65#include <string.h>
    66
    67#define BRANCHRULE_NAME "multaggr"
    68#define BRANCHRULE_DESC "fullstrong branching on fractional and multi-aggregated variables"
    69#define BRANCHRULE_PRIORITY 0
    70#define BRANCHRULE_MAXDEPTH -1
    71#define BRANCHRULE_MAXBOUNDDIST 1.0
    72
    73
    74#define DEFAULT_REEVALAGE 0LL /**< number of intermediate LPs solved to trigger reevaluation of strong branching
    75 * value for a variable that was already evaluated at the current node */
    76#define DEFAULT_MAXPROPROUNDS 0 /**< maximum number of propagation rounds to be performed during multaggr branching
    77 * before solving the LP (-1: no limit, -2: parameter settings) */
    78#define DEFAULT_PROBINGBOUNDS TRUE /**< should valid bounds be identified in a probing-like fashion during multi-aggr
    79 * branching (only with propagation)? */
    80
    81/*
    82 * Data structures
    83 */
    84
    85/** branching rule data */
    86struct SCIP_BranchruleData
    87{
    88 SCIP_Longint reevalage; /**< number of intermediate LPs solved to trigger reevaluation of strong branching
    89 * value for a variable that was already evaluated at the current node */
    90 SCIP_Bool probingbounds; /**< should valid bounds be identified in a probing-like fashion during strong
    91 * branching (only with propagation)? */
    92 int lastcand; /**< last evaluated candidate of last branching rule execution */
    93 int maxproprounds; /**< maximum number of propagation rounds to be performed during strong branching
    94 * before solving the LP (-1: no limit, -2: parameter settings) */
    95 int skipsize; /**< size of skipdown and skipup array */
    96 SCIP_Bool* skipdown; /**< should be branching on down child be skipped? */
    97 SCIP_Bool* skipup; /**< should be branching on up child be skipped? */
    98#ifdef SCIP_STATISTIC
    99 SCIP_CLOCK* clckstrongbr; /**< clock to store the time spent inside the strong branching function on fractional variables */
    100 SCIP_CLOCK* clckmultaggrbr; /**< clock to store the time spent inside the strong branching function on multi-aggragated variables */
    101 SCIP_Real* ratioggain; /**< for each occurence of a branching on a multi-aggregated variable we store the ratio of the gain that
    102 * we would have obtained branching on the best fractional variable over the gain obtained
    103 * branching on the current multi-aggregated variable */
    104 SCIP_Real ameanratio; /**< arithmetic mean of the ratioggain array */
    105 SCIP_Bool noupdate; /**< pointer to store if the probing LP has not been solved so we do not want to
    106 * update statistics */
    107 int firstmultaggrdepth; /**< depth of the first branching on a multi-aggregated variable */
    108 int rundepth; /**< the run of the first multi-aggregated branching */
    109 int nmultaggrbranch; /**< number of branchings on multi-aggregated variables */
    110 int nfracbranch; /**< number of branchings on fractional variables */
    111 int nEscore; /**< number of times that the bestscore over all multi-aggregated variables is equal to the best
    112 * fractional variables score and thus we do not branch on the multi-aggregate variable */
    113 int nmultaggrcutoff; /**< number of cutoffs detected during the probing mode on multi-aggregated variables */
    114 int nmultaggrconsadd; /**< number of times that a probing constraint of a multi-aggregated variable has been
    115 * added to the original problem */
    116 int nfractcutoff; /**< number of cutoffs detected during strong branching on fractional variables */
    117 int nfractconsadd; /**< number of times that during strong branching on fractional variables a constraint has been
    118 * added to the original problem or a variables domain has been reduced */
    119 int nmultaggrvars; /**< number of multi-aggregated variables in the problem of the last run */
    120 int nrun; /**< number of restarts */
    121 int size; /**< size of the provided array to store the ratio gain */
    122 int nstrongbrcall; /**< number of times that the selectVarstrongBranching function has been called */
    123 int nmultaggrbrcall; /**< number of times that the selectVarMultAggrBranching function has been called */
    124 int totallpcands; /**< total number of observed lpcands over all selectVarstrongBranching function calls */
    125 int totalmultaggrcands; /**< total number of observed multi-aggregregated candidates over all selectVarMultAggrBranching
    126 * function calls */
    127#endif
    128};
    129
    130
    131/*
    132 * Local methods
    133 */
    134
    135/* this function ensures that the allocated memory is enough to store statistics data */
    136#ifdef SCIP_STATISTIC
    137static
    138SCIP_RETCODE ensureArraySize(
    139 SCIP* scip, /**< original SCIP data structure */
    140 SCIP_BRANCHRULEDATA* branchruledata /**< branching rule data */
    141 )
    142{
    143 assert(scip != NULL);
    144 assert(branchruledata != NULL);
    145 assert(branchruledata->ratioggain != NULL);
    146 assert(branchruledata->nmultaggrbranch >= 0);
    147 assert(branchruledata->size >= 0);
    148
    149 /* check whether the size of the array is big enough; reallocate memory if needed */
    150 if( branchruledata->nmultaggrbranch + 1 > branchruledata->size )
    151 {
    152 int newsize = SCIPcalcMemGrowSize(scip, branchruledata->nmultaggrbranch + 1);
    153 assert(newsize >= branchruledata->nmultaggrbranch + 1);
    154 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &branchruledata->ratioggain, branchruledata->size, newsize) );
    155 branchruledata->size = newsize;
    156 }
    157 return SCIP_OKAY;
    158}
    159#endif
    160
    161/* this function gives us the best candidate for branching among the multi-aggregated variables of the problem
    162 * and the best fractional integer variable already selected by strong branching
    163*/
    164static
    166 SCIP* scip, /**< original SCIP data structure */
    167 SCIP_VAR** bestcand, /**< the best candidate variable selected by strong branching */
    168 SCIP_Real* bestscore, /**< score of the best branching candidate */
    169 SCIP_Real* bestsol, /**< solution value of the best branching candidate */
    170 SCIP_Real* bestdown, /**< objective value of the down node when branching on bestcand */
    171 SCIP_Real* bestup, /**< objective value of the up node when branching on bestcand */
    172 SCIP_Bool* bestdownvalid, /**< is bestdown a valid dual bound for the down branch? */
    173 SCIP_Bool* bestupvalid, /**< is bestup a valid dual bound for the up branch? */
    174 SCIP_Real* provedbound, /**< proved dual bound for the current subtree */
    175 SCIP_Real* estimatedown, /**< pointer to store the down child nodes estimate */
    176 SCIP_Real* estimateup, /**< pointer to store the up child nodes estimate */
    177#ifdef SCIP_STATISTIC
    178 SCIP_Real* bestmultaggrscore, /**< pointer to store the multi aggregated score */
    179#endif
    180 SCIP_RESULT* result /**< pointer to store results of branching */
    181 )
    182{
    183 SCIP_VAR** fixvars;
    184 SCIP_CONS* probingconsdown;
    185 SCIP_CONS* probingconsup;
    186 SCIP_NODE* node;
    187 SCIP_Real* fixvarssols;
    188 SCIP_Real fixvarssol;
    189 SCIP_Real lpobjval;
    190 SCIP_Bool exactsolve;
    191 SCIP_Bool allcolsinlp;
    192 SCIP_Bool downnodeinf = FALSE;
    193 SCIP_Bool startprobing = TRUE;
    194 SCIP_Bool endprobing = FALSE;
    195 int nfixvars;
    196 int i;
    197 int j;
    198 int k;
    199
    200 /* import branchrule data for statistics */
    201#ifdef SCIP_STATISTIC
    202 SCIP_BRANCHRULE* branchrule;
    203 SCIP_BRANCHRULEDATA* branchruledata;
    204
    206 assert(branchrule != NULL);
    207
    208 branchruledata = SCIPbranchruleGetData(branchrule);
    209 assert(branchruledata != NULL);
    210#endif
    211
    212 assert(scip != NULL);
    213 assert(bestcand != NULL);
    214 assert(bestscore != NULL);
    215
    216 /* check, if we want to solve the problem exactly, meaning that strong branching information is not useful
    217 * for cutting off sub problems and improving lower bounds of children
    218 */
    219 exactsolve = SCIPisExact(scip);
    220
    221 /* check, if all existing columns are in LP, and thus the strong branching results give lower bounds */
    222 allcolsinlp = SCIPallColsInLP(scip);
    223
    224 /* get fixed variables */
    225 fixvars = SCIPgetFixedVars(scip);
    226 nfixvars = SCIPgetNFixedVars(scip);
    227 SCIPdebugMsg(scip, " fractional variable: <%s> with value: %f is selected by strong branching\n", SCIPvarGetName(*bestcand), *bestsol);
    228
    229 /* check if we would exceed the depth limit */
    231 {
    232 SCIPdebugMsg(scip, "cannot perform probing in selectVarMultAggrBranching, depth limit reached.\n");
    233 *result = SCIP_DIDNOTRUN;
    234 return SCIP_OKAY;
    235 }
    236
    237 if( nfixvars != 0 )
    238 {
    239 assert(fixvars != NULL);
    240
    241 SCIP_CALL( SCIPallocBufferArray(scip, &fixvarssols, nfixvars) );
    242 lpobjval = SCIPgetLPObjval(scip);
    243
    244 /* store the values of the fixed variables at the current optimal solution */
    245 for( i = 0; i < nfixvars; i++ )
    246 {
    247 assert(fixvars[i] != NULL);
    248 fixvarssols[i] = SCIPvarGetLPSol(fixvars[i]);
    249 }
    250
    251 for( i = 0; i < nfixvars; i++ )
    252 {
    253 assert(fixvars[i] != NULL);
    254
    255 /* only integer and binary multi-aggregated variables are potential branching candidates */
    257 {
    258 fixvarssol = fixvarssols[i];
    259
    260 /* start probing mode for the fractional multi-aggregated variable */
    261 if( !SCIPisFeasIntegral(scip, fixvarssol) )
    262 {
    263 SCIP_VAR** downvars = NULL;
    264 SCIP_VAR** upvars = NULL;
    265 SCIP_Real* downvarssols = NULL;
    266 SCIP_Real* upvarssols = NULL;
    267 SCIP_LPSOLSTAT solstatdown;
    268 SCIP_LPSOLSTAT solstatup;
    269 SCIP_Real downobjval;
    270 SCIP_Real upobjval;
    271 SCIP_Real estimateprobdown = 0.0;
    272 SCIP_Real estimateprobup = 0.0;
    273 SCIP_Bool downinf;
    274 SCIP_Bool upinf;
    275 SCIP_Bool lperror;
    276 int ndownvars;
    277 int nupvars;
    278
    279 /* start the probing mode if this is the first entrance */
    280 if( startprobing )
    281 {
    283 startprobing = FALSE;
    284 endprobing = TRUE;
    285
    286 SCIPdebugMsg(scip, "PROBING MODE:\n");
    287 }
    288
    289 SCIPdebugMsg(scip, " multi-aggregated variable: <%s> with value: %f\n", SCIPvarGetName(fixvars[i]), fixvarssol);
    290
    291 SCIPstatistic(branchruledata->totalmultaggrcands += 1);
    292
    293 /* create the multi-aggregated rounded down constraint */
    294 SCIP_CALL( SCIPcreateConsLinear(scip, &probingconsdown, "probingconsdown", SCIPvarGetMultaggrNVars(fixvars[i]),
    296 SCIPfeasFloor(scip, fixvarssol) - SCIPvarGetMultaggrConstant(fixvars[i]), TRUE, TRUE, FALSE, FALSE,
    297 TRUE, TRUE, FALSE, FALSE, FALSE, TRUE) );
    298 assert(probingconsdown != NULL);
    299
    300 /* create the down child probing node */
    302 node = SCIPgetCurrentNode(scip);
    303 assert(node != NULL);
    304
    305 SCIP_CALL( SCIPaddConsNode(scip, node, probingconsdown, NULL) );
    306 SCIP_CALL( SCIPreleaseCons(scip, &probingconsdown) );
    307
    308#ifdef PRINTNODECONS
    309 SCIPdebugMsg(scip, " created down probing node with constraint:\n");
    310 SCIP_CALL( SCIPprintCons(scip, probingconsdown, NULL) );
    311 SCIPinfoMessage(scip, NULL, "\n");
    312#endif
    313
    314 /* solve the down child probing node */
    315 SCIP_CALL( SCIPsolveProbingLP(scip, -1, &lperror, &downinf) );
    316 solstatdown = SCIPgetLPSolstat(scip);
    317 lperror = lperror || (solstatdown == SCIP_LPSOLSTAT_NOTSOLVED && downinf == 0) || (solstatdown == SCIP_LPSOLSTAT_ITERLIMIT) ||
    318 (solstatdown == SCIP_LPSOLSTAT_TIMELIMIT);
    319 assert(solstatdown != SCIP_LPSOLSTAT_UNBOUNDEDRAY);
    320
    321 /* break the branching rule if an error occurred, problem was not solved, iteration or time limit was reached */
    322 if( lperror )
    323 {
    324 SCIPdebugMsg(scip, "error solving down node probing LP: status=%d\n", solstatdown);
    325 SCIPstatistic(branchruledata->noupdate = TRUE);
    326 break;
    327 }
    328
    329 downobjval = SCIPgetLPObjval(scip);
    330 downinf = downinf || SCIPisGE(scip, downobjval, SCIPgetCutoffbound(scip));
    331 assert(((solstatdown != SCIP_LPSOLSTAT_INFEASIBLE) && (solstatdown != SCIP_LPSOLSTAT_OBJLIMIT)) || downinf);
    332
    333 if( !downinf )
    334 {
    335 /* when an optimal solution has been found calculate down child's estimate based on pseudo costs */
    336 /* estimate = lowerbound + sum(min{f_j * pscdown_j, (1-f_j) * pscup_j}) */
    337 estimateprobdown = SCIPnodeGetLowerbound(node);
    338 SCIP_CALL( SCIPgetLPBranchCands(scip, &downvars, &downvarssols, NULL, &ndownvars, NULL, NULL) );
    339
    340 for( j = 0 ; j < ndownvars; j++ )
    341 {
    342 SCIP_Real estimateincr;
    343 SCIP_Real pscdown;
    344 SCIP_Real pscup;
    345
    346 assert(downvars != NULL);
    347 assert(downvars[j] != NULL);
    348
    349 pscdown = SCIPgetVarPseudocostVal(scip, downvars[j], SCIPfeasFloor(scip, downvarssols[j]) - downvarssols[j]);
    350 pscup = SCIPgetVarPseudocostVal(scip, downvars[j], SCIPfeasCeil(scip, downvarssols[j]) - downvarssols[j]);
    351 estimateincr = MIN(pscdown, pscup);
    352
    353 estimateprobdown += estimateincr;
    354 }
    355 }
    357
    358 /* create the multi-aggregated rounded up constraint */
    359 SCIP_CALL( SCIPcreateConsLinear(scip, &probingconsup, "probingconsup", SCIPvarGetMultaggrNVars(fixvars[i]), SCIPvarGetMultaggrVars(fixvars[i]),
    362 assert(probingconsup != NULL);
    363
    364 /* create the up child probing node */
    366 node = SCIPgetCurrentNode(scip);
    367
    368 SCIP_CALL( SCIPaddConsNode(scip, node, probingconsup, NULL) );
    369 SCIP_CALL( SCIPreleaseCons(scip, &probingconsup) );
    370
    371#ifdef PRINTNODECONS
    372 SCIPdebugMsg(scip, " created up probing node with constraint:\n");
    373 SCIP_CALL( SCIPprintCons(scip, probingconsup, NULL) );
    374 SCIPinfoMessage(scip, NULL, "\n");
    375#endif
    376 /* solve the up child probing node */
    377 SCIP_CALL( SCIPsolveProbingLP(scip, -1, &lperror, &upinf) );
    378 solstatup = SCIPgetLPSolstat(scip);
    379 lperror = lperror || (solstatup == SCIP_LPSOLSTAT_NOTSOLVED && upinf == 0) || (solstatup == SCIP_LPSOLSTAT_ITERLIMIT) ||
    380 (solstatup == SCIP_LPSOLSTAT_TIMELIMIT);
    381 assert(solstatup != SCIP_LPSOLSTAT_UNBOUNDEDRAY);
    382
    383 /* break the branching rule if an error occurred, problem was not solved, iteration or time limit was reached */
    384 if( lperror )
    385 {
    386 SCIPdebugMsg(scip, "error solving up node probing LP: status=%d\n", solstatup);
    387 SCIPstatistic(branchruledata->noupdate = TRUE);
    388 break;
    389 }
    390
    391 upobjval = SCIPgetLPObjval(scip);
    392 upinf = upinf || SCIPisGE(scip, upobjval, SCIPgetCutoffbound(scip));
    393 assert(((solstatup != SCIP_LPSOLSTAT_INFEASIBLE) && (solstatup != SCIP_LPSOLSTAT_OBJLIMIT)) || upinf);
    394
    395 SCIPdebugMsg(scip, " down node objval: %g up node objval: %g\n", downobjval, upobjval);
    396
    397 if( !upinf )
    398 {
    399 /* when an optimal solution has been found calculate up child's estimate based on pseudo costs */
    400 /* estimate = lowerbound + sum(min{f_j * pscdown_j, (1-f_j) * pscup_j}) */
    401 estimateprobup = SCIPnodeGetLowerbound(node);
    402 SCIP_CALL( SCIPgetLPBranchCands(scip, &upvars, &upvarssols, NULL, &nupvars, NULL, NULL) );
    403
    404 for( k = 0 ; k < nupvars; k++ )
    405 {
    406 SCIP_Real estimateincr;
    407 SCIP_Real pscdown;
    408 SCIP_Real pscup;
    409
    410 assert(upvars != NULL);
    411 assert(upvars[k] != NULL);
    412
    413 pscdown = SCIPgetVarPseudocostVal(scip, upvars[k], SCIPfeasFloor(scip, upvarssols[k]) - upvarssols[k]);
    414 pscup = SCIPgetVarPseudocostVal(scip, upvars[k], SCIPfeasCeil(scip, upvarssols[k]) - upvarssols[k]);
    415 estimateincr = MIN(pscdown, pscup);
    416 estimateprobup += estimateincr;
    417 }
    418 }
    420
    421 /* check whether the children nodes are solved to optimality and give a valid new lower bound or not */
    422 if( downinf || upinf )
    423 {
    424 /* check if the LP is a valid relaxation and we can then collect new information */
    425 if( allcolsinlp )
    426 {
    427 /* cut off the node either when both children are infeasible or the objective limit was reached;
    428 * if only one child is feasible with LP value smaller than objective limit, add the corresponding
    429 * constraint to the problem and break the branching rule in order to solve the updated LP
    430 */
    431 if( downinf && upinf )
    432 {
    433 SCIPdebugMsg(scip, "node can be cut off due to strong branching on multi-aggregated variable <%s>\n",
    434 SCIPvarGetName(fixvars[i]));
    435 SCIPstatistic(branchruledata->nmultaggrcutoff += 1);
    436
    437 *result = SCIP_CUTOFF;
    438 break;
    439 }
    440 else
    441 {
    442 assert(!lperror);
    443
    444 if( downinf )
    445 downnodeinf = TRUE;
    446
    447 SCIPdebugMsg(scip, "%s child of multi-aggregated variable <%s> is infeasible\n",
    448 downinf ? "down" : "up", SCIPvarGetName(fixvars[i]) );
    449 SCIPstatistic(branchruledata->nmultaggrconsadd += 1);
    450
    451 *result = SCIP_CONSADDED;
    452 break;
    453 }
    454 }
    455 }
    456 else
    457 {
    458 /* if both children are solved to optimality and they both give a new valid bound, calculate the score of the
    459 * multi-aggregated variable
    460 */
    461 SCIP_Real downgain;
    462 SCIP_Real upgain;
    463 SCIP_Real down;
    464 SCIP_Real up;
    465 SCIP_Real score;
    466 SCIP_Real minbound;
    467
    468 assert(!downinf);
    469 assert(!upinf);
    470 assert(!lperror);
    471
    472 SCIPdebugMsg(scip, " both probing nodes are valid while branching on multi-aggregated variable: <%s>\n ", SCIPvarGetName(fixvars[i]));
    473
    474 down = MAX(downobjval, lpobjval);
    475 up = MAX(upobjval, lpobjval);
    476 downgain = down - lpobjval;
    477 upgain = up - lpobjval;
    478 score = SCIPgetBranchScore(scip, NULL, downgain, upgain);
    479
    480 if( allcolsinlp && !exactsolve )
    481 {
    482 /* the minimal lower bound of both children is a proved lower bound of the current subtree */
    483 minbound = MIN(downobjval, upobjval);
    484 *provedbound = MAX(*provedbound, minbound);
    485 }
    486
    488 if( score > *bestmultaggrscore )
    489 *bestmultaggrscore = score;
    490 );
    491
    492 /* update the best branching candidate and all its values if a strictly greater score has been found */
    493 if( score > *bestscore )
    494 {
    496 if( branchruledata->nmultaggrbranch == 0 )
    497 {
    498 branchruledata->rundepth = SCIPgetNRuns(scip);
    499 branchruledata->firstmultaggrdepth = SCIPgetFocusDepth(scip);
    500 }
    501 )
    502
    503 SCIPdebugMsg(scip, " <%s> is a better candidate for branching\n", SCIPvarGetName(fixvars[i]));
    504
    505 *bestscore = MAX(score, *bestscore);
    506 *bestcand = fixvars[i];
    507 *bestsol = fixvarssol;
    508 *bestdown = downobjval;
    509 *bestup = upobjval;
    510 *bestdownvalid = TRUE;
    511 *bestupvalid = TRUE;
    512 *estimatedown = estimateprobdown;
    513 *estimateup = estimateprobup;
    514 }
    515 assert(bestscore != NULL);
    516 assert(bestcand != NULL);
    517 assert(bestup != NULL);
    518 assert(bestdown != NULL);
    519 }
    520 }
    521 }
    522 }
    523
    524 /* end probing mode */
    525 if( endprobing )
    526 {
    528 }
    529
    530 SCIPdebugMsg(scip, "\n");
    531
    532 /* one of the child nodes was infeasible, add the other constraint to the current node */
    533 if( *result == SCIP_CONSADDED )
    534 {
    535 node = SCIPgetCurrentNode(scip);
    536 if( downnodeinf )
    537 {
    538 SCIP_CALL( SCIPcreateConsLinear(scip, &probingconsup, "infconsup", SCIPvarGetMultaggrNVars(fixvars[i]),
    539 SCIPvarGetMultaggrVars(fixvars[i]), SCIPvarGetMultaggrScalars(fixvars[i]),
    540 SCIPfeasCeil(scip, fixvarssols[i]) - SCIPvarGetMultaggrConstant(fixvars[i]), SCIPinfinity(scip),
    542 assert(probingconsup != NULL);
    543 SCIP_CALL( SCIPaddConsNode(scip, node, probingconsup, NULL) );
    544 SCIPdebugMsg(scip, " <%s> new valid constraint has been added to the original problem\n", SCIPconsGetName(probingconsup));
    545 SCIP_CALL( SCIPreleaseCons(scip, &probingconsup) );
    546 }
    547 else
    548 {
    549 SCIP_CALL( SCIPcreateConsLinear(scip, &probingconsdown, "infconsdown", SCIPvarGetMultaggrNVars(fixvars[i]),
    551 SCIPfeasFloor(scip, fixvarssols[i]) - SCIPvarGetMultaggrConstant(fixvars[i]), TRUE, TRUE, FALSE, FALSE,
    552 TRUE, TRUE, FALSE, FALSE, FALSE, TRUE) );
    553 assert(probingconsdown != NULL);
    554 SCIP_CALL( SCIPaddConsNode(scip, node, probingconsdown, NULL) );
    555 SCIPdebugMsg(scip, " <%s> new valid constraint has been added to the original problem\n", SCIPconsGetName(probingconsdown));
    556 SCIP_CALL( SCIPreleaseCons(scip, &probingconsdown) );
    557 }
    558 }
    559 SCIPfreeBufferArray(scip, &fixvarssols);
    560 }
    561 return SCIP_OKAY;
    562}
    563
    564
    565/*
    566 * Callback methods of branching rule
    567 */
    568
    569/** copy method for branchrule plugins (called when SCIP copies plugins) */
    570static
    571SCIP_DECL_BRANCHCOPY(branchCopyMultAggr)
    572{ /*lint --e{715}*/
    573 assert(scip != NULL);
    574 assert(branchrule != NULL);
    575 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
    576
    577 /* call inclusion method of branchrule */
    579
    580 return SCIP_OKAY;
    581}
    582
    583/** destructor of branching rule to free user data (called when SCIP is exiting) */
    584static
    585SCIP_DECL_BRANCHFREE(branchFreeMultAggr)
    586{ /*lint --e{715}*/
    587 SCIP_BRANCHRULEDATA* branchruledata;
    588
    589 /* free branching rule data */
    590 branchruledata = SCIPbranchruleGetData(branchrule);
    591 assert(branchruledata != NULL);
    592
    593 SCIPstatistic(SCIPfreeBlockMemoryArrayNull(scip , &branchruledata->ratioggain, branchruledata->size));
    594 SCIPfreeBlockMemoryArrayNull(scip, &branchruledata->skipdown, branchruledata->skipsize);
    595 SCIPfreeBlockMemoryArrayNull(scip, &branchruledata->skipup, branchruledata->skipsize);
    596
    597 SCIPfreeBlockMemory(scip, &branchruledata);
    598 SCIPbranchruleSetData(branchrule, NULL);
    599
    600 return SCIP_OKAY;
    601}
    602
    603/** initialization method of branching rule (called after problem was transformed) */
    604static
    605SCIP_DECL_BRANCHINIT(branchInitMultAggr)
    606{ /*lint --e{715}*/
    607 SCIP_BRANCHRULEDATA* branchruledata;
    608
    609 branchruledata = SCIPbranchruleGetData(branchrule);
    610 assert(branchruledata != NULL);
    611
    612 branchruledata->lastcand = 0;
    614 branchruledata->firstmultaggrdepth = 0;
    615 branchruledata->nmultaggrbranch = 0;
    616 branchruledata->nfracbranch = 0;
    617 branchruledata->nEscore = 0;
    618 branchruledata->nmultaggrcutoff = 0;
    619 branchruledata->nmultaggrconsadd = 0;
    620 branchruledata->nfractcutoff = 0;
    621 branchruledata->nfractconsadd = 0;
    622 branchruledata->nrun = 0;
    623 branchruledata->size = 100;
    624 branchruledata->ameanratio = 0.0;
    625 branchruledata->noupdate = FALSE;
    626 branchruledata->clckstrongbr = NULL;
    627 branchruledata->clckmultaggrbr = NULL;
    628 branchruledata->nstrongbrcall = 0;
    629 branchruledata->nmultaggrbrcall = 0;
    630 branchruledata->totalmultaggrcands = 0;
    631 branchruledata->totallpcands = 0;
    632 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->ratioggain, branchruledata->size) );
    633 BMSclearMemoryArray(branchruledata->ratioggain, branchruledata->size);
    634 SCIP_CALL( SCIPcreateClock(scip, &branchruledata->clckstrongbr) );
    635 SCIP_CALL( SCIPcreateClock(scip, &branchruledata->clckmultaggrbr) );
    636 )
    637 return SCIP_OKAY;
    638}
    639
    640/** deinitialization method of branching rule (called before transformed problem is freed) */
    641static
    642SCIP_DECL_BRANCHEXIT(branchExitMultAggr)
    643{ /*lint --e{715}*/
    644 SCIP_BRANCHRULEDATA* branchruledata;
    645
    646 /* initialize branching rule data */
    647 branchruledata = SCIPbranchruleGetData(branchrule);
    648 assert(branchruledata != NULL);
    649 assert((branchruledata->skipdown != NULL) == (branchruledata->skipup != NULL));
    650
    651 /* print statistics */
    654 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Multi-aggregated branching stats : \n");
    655 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " nmultaggrvars : %d (last run)\n",
    656 branchruledata->nmultaggrvars);
    657 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " firstmultaggrbranchdepth : %d (in run %d)\n",
    658 branchruledata->firstmultaggrdepth,
    659 branchruledata->rundepth);
    660 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " nmultaggrbranch : %d (tot %d)\n",
    661 branchruledata->nmultaggrbranch, branchruledata->nmultaggrbranch + branchruledata->nfracbranch);
    662 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " nmultaggrcutoff : %d\n", branchruledata->nmultaggrcutoff);
    663 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " nmultaggrconsadd : %d\n", branchruledata->nmultaggrconsadd);
    664 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " nfractcutoff : %d\n", branchruledata->nfractcutoff);
    665 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " nfractconsadd : %d\n", branchruledata->nfractconsadd);
    666 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " nEscore : %d\n", branchruledata->nEscore);
    667
    668 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " Branching Time : \n");
    669 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " nstrongbrcall : %d\n", branchruledata->nstrongbrcall);
    670 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " totalstrongbrtime : %g\n",
    671 SCIPgetClockTime(scip, branchruledata->clckstrongbr));
    672 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " totallpcands : %d\n", branchruledata->totallpcands);
    673
    674 if( branchruledata->totallpcands != 0 )
    675 {
    676 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " averagetimestrongbr : %g\n",
    677 SCIPgetClockTime(scip, branchruledata->clckstrongbr) / branchruledata->totallpcands);
    678 }
    679 else
    680 {
    681 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " averagetimestrongbr : %s\n", "--");
    682 }
    683
    684 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " nmultaggrbrcall : %d\n", branchruledata->nmultaggrbrcall);
    685 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " totalmultaggrbrtime : %g\n",
    686 SCIPgetClockTime(scip, branchruledata->clckmultaggrbr));
    687 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " totalmultaggrcands : %d\n", branchruledata->totalmultaggrcands);
    688
    689 if( branchruledata->totalmultaggrcands != 0 )
    690 {
    691 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " averagetimemultaggrbr : %g\n",
    692 SCIPgetClockTime(scip, branchruledata->clckmultaggrbr) / branchruledata->totalmultaggrcands);
    693 }
    694 else
    695 {
    696 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " averagetimemultaggrbr : %s\n", "--");
    697 }
    698
    699 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " Ratioggain :\n");
    700 if( branchruledata->nmultaggrbranch != 0 )
    701 {
    702 int j;
    703 for( j = 0; j < branchruledata->nmultaggrbranch; j++ )
    704 {
    705 branchruledata->ameanratio += branchruledata->ratioggain[j];
    706 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " %g", branchruledata->ratioggain[j]);
    707 }
    708
    710 branchruledata->ameanratio = branchruledata->ameanratio / branchruledata->nmultaggrbranch;
    712 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " ameanratio : %4.2f\n", branchruledata->ameanratio);
    713 }
    714 else
    715 {
    716 SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " ameanratio : %s\n", "--");
    717 }
    718
    720
    721 /* free arrays */
    722 SCIPfreeBlockMemoryArrayNull(scip, &branchruledata->ratioggain, branchruledata->size);
    723 SCIP_CALL( SCIPfreeClock(scip, &branchruledata->clckstrongbr) );
    724 SCIP_CALL( SCIPfreeClock(scip, &branchruledata->clckmultaggrbr) );
    725 )
    726 if( branchruledata->skipdown != NULL )
    727 {
    728 SCIPfreeBlockMemoryArray(scip, &branchruledata->skipup, branchruledata->skipsize);
    729 SCIPfreeBlockMemoryArray(scip, &branchruledata->skipdown, branchruledata->skipsize);
    730 branchruledata->skipdown = NULL;
    731 branchruledata->skipup = NULL;
    732 branchruledata->skipsize = 0;
    733 }
    734 return SCIP_OKAY;
    735}
    736
    737/** branching execution method for fractional LP solutions */
    738static
    739SCIP_DECL_BRANCHEXECLP(branchExeclpMultAggr)
    740{ /*lint --e{715}*/
    741 SCIP_BRANCHRULEDATA* branchruledata;
    742 SCIP_VAR** lpcands;
    743 SCIP_VAR** tmplpcands;
    744 SCIP_Real* lpcandssol;
    745 SCIP_Real* lpcandsfrac;
    746 SCIP_Real* tmplpcandssol;
    747 SCIP_Real* tmplpcandsfrac;
    748 SCIP_NODE* downchild;
    749 SCIP_NODE* upchild;
    750 SCIP_Real bestup;
    751 SCIP_Real bestdown;
    752 SCIP_Real bestscore;
    753 SCIP_Real provedbound;
    754 SCIP_Real estimatedown = 0.0;
    755 SCIP_Real estimateup = 0.0;
    756 SCIP_Bool bestdownvalid;
    757 SCIP_Bool bestupvalid;
    758 SCIP_Longint oldreevalage;
    759 int bestcandpos;
    760 int nlpcands;
    761 int npriolpcands;
    763 SCIP_Real lpobjval;
    765 )
    766
    767 assert(branchrule != NULL);
    768 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
    769 assert(scip != NULL);
    770 assert(result != NULL);
    771
    772 SCIPdebugMsg(scip, "Execlp method of mult-aggreg branching\n ");
    773 *result = SCIP_DIDNOTRUN;
    774
    775 /* get branching rule data */
    776 branchruledata = SCIPbranchruleGetData(branchrule);
    777 assert(branchruledata != NULL);
    778
    779 SCIP_CALL( SCIPgetLongintParam(scip, "branching/fullstrong/reevalage", &oldreevalage) );
    780 SCIP_CALL( SCIPsetLongintParam(scip, "branching/fullstrong/reevalage", branchruledata->reevalage) );
    781
    782 /* get the lpobjval and the number of multi aggregated variables of the problem as a statistic counter */
    785 lpobjval = SCIPgetLPObjval(scip);
    786
    787 if( SCIPgetNRuns(scip) != branchruledata->nrun )
    788 {
    789 SCIP_VAR** fixvars;
    790 int nfixvars;
    791 int i;
    792
    793 branchruledata->nmultaggrvars = 0;
    794 fixvars = SCIPgetFixedVars(scip);
    795 nfixvars = SCIPgetNFixedVars(scip);
    796
    797 if( nfixvars != 0 )
    798 {
    799 for( i = 0; i < nfixvars; i++ )
    800 {
    802 {
    803 branchruledata->nmultaggrvars += 1;
    804 }
    805 }
    806 }
    807 branchruledata->nrun = SCIPgetNRuns(scip);
    808 }
    809 )
    810
    811 /* get all branching candidates */
    812 SCIP_CALL( SCIPgetLPBranchCands(scip, &tmplpcands, &tmplpcandssol, &tmplpcandsfrac, &nlpcands, &npriolpcands, NULL) );
    813 assert(nlpcands > 0);
    814 assert(npriolpcands > 0);
    815
    816 /* copy LP branching candidates and solution values, because they will be updated w.r.t. the strong branching LP
    817 * solution
    818 */
    819 SCIP_CALL( SCIPduplicateBufferArray(scip, &lpcands, tmplpcands, nlpcands) );
    820 SCIP_CALL( SCIPduplicateBufferArray(scip, &lpcandssol, tmplpcandssol, nlpcands) );
    821 SCIP_CALL( SCIPduplicateBufferArray(scip, &lpcandsfrac, tmplpcandsfrac, nlpcands) );
    822
    823 if( branchruledata->skipdown == NULL )
    824 {
    825 assert(branchruledata->skipup == NULL);
    826
    827 branchruledata->skipsize = SCIPgetNVars(scip);
    828 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->skipdown, branchruledata->skipsize) );
    829 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &branchruledata->skipup, branchruledata->skipsize) );
    830 BMSclearMemoryArray(branchruledata->skipdown, branchruledata->skipsize);
    831 BMSclearMemoryArray(branchruledata->skipup, branchruledata->skipsize);
    832 }
    833
    834 /* start the clock to get the time spent inside the function */
    836 SCIP_CALL( SCIPstartClock(scip, branchruledata->clckstrongbr) );
    837 );
    838
    839 /* compute strong branching among the array of fractional variables in order to get the best one */
    840 SCIP_CALL( SCIPselectVarStrongBranching(scip, lpcands, lpcandssol, lpcandsfrac, branchruledata->skipdown,
    841 branchruledata->skipup, nlpcands, npriolpcands, nlpcands, &branchruledata->lastcand,
    842 branchruledata->maxproprounds, branchruledata->probingbounds, TRUE,
    843 &bestcandpos, &bestdown, &bestup, &bestscore, &bestdownvalid, &bestupvalid, &provedbound, result) );
    844
    846 SCIP_CALL( SCIPstopClock(scip, branchruledata->clckstrongbr) );
    847 branchruledata->totallpcands += SCIPgetNLPBranchCands(scip);
    848 branchruledata->nstrongbrcall += 1;
    849 )
    850
    851 if( *result != SCIP_CUTOFF && *result != SCIP_REDUCEDDOM && *result != SCIP_CONSADDED )
    852 {
    853 SCIP_VAR* bestcand = lpcands[bestcandpos];
    854 SCIP_Real bestsol = lpcandssol[bestcandpos];
    855 SCIPstatistic( SCIP_Real bestmultaggrscore = -SCIPinfinity(scip); )
    856
    858 SCIP_Real fdowngain = 0.0;
    859 SCIP_Real fupgain = 0.0;
    860
    861 /* reoptimize is set to true if strong branching on fractional variables did not explicitly evaluate the objective
    862 * values of the probing child nodes and thus we do not have updated information
    863 */
    864 if( SCIPisLT(scip, SCIPgetVarStrongbranchLPAge(scip, bestcand), branchruledata->reevalage)
    865 || branchruledata->maxproprounds != 0 )
    867
    868 /* store values needed for the ratioggain statistic */
    869 if( !reoptimize )
    870 {
    871 SCIP_Real fdown;
    872 SCIP_Real fup;
    873
    874 fdown = MAX(bestdown, lpobjval);
    875 fup = MAX(bestup, lpobjval);
    876 fdowngain = fdown - lpobjval;
    877 fupgain = fup - lpobjval;
    878 }
    879
    880 /* start and then stop the clock to get the time spent inside the function */
    881 SCIP_CALL( SCIPstartClock(scip, branchruledata->clckmultaggrbr) );
    882 )
    883
    884 /* compute strong branching among the multi-aggregated variables and the best fractional variable */
    885#ifdef SCIP_STATISTIC
    886 SCIP_CALL( selectVarMultAggrBranching(scip, &bestcand, &bestscore, &bestsol, &bestdown, &bestup, &bestdownvalid, &bestupvalid, &provedbound,
    887 &estimatedown, &estimateup, &bestmultaggrscore, result) );
    888#else
    889 SCIP_CALL( selectVarMultAggrBranching(scip, &bestcand, &bestscore, &bestsol, &bestdown, &bestup, &bestdownvalid, &bestupvalid, &provedbound,
    890 &estimatedown, &estimateup, result) );
    891#endif
    893 SCIP_CALL( SCIPstopClock(scip, branchruledata->clckmultaggrbr) );
    894 branchruledata->nmultaggrbrcall += 1;
    895 )
    896
    897 if( *result != SCIP_CUTOFF && *result != SCIP_CONSADDED )
    898 {
    900 if( !(branchruledata->noupdate) )
    901 {
    902 if( SCIPisEQ(scip, bestmultaggrscore, bestscore) )
    903 branchruledata->nEscore += 1;
    904 }
    905 )
    906
    907 assert(bestcand != NULL);
    908 SCIPdebugMsg(scip, "BRANCHING MODE:\n");
    909
    910 /* perform branching on the best found candidate */
    912 {
    913 SCIP_CONS* multaggrconsdown;
    914 SCIP_CONS* multaggrconsup;
    915
    917 if( !(branchruledata->noupdate) )
    918 {
    919 branchruledata->nmultaggrbranch += 1;
    920
    921 if( !reoptimize )
    922 {
    923 SCIP_Real gfractbranch;
    924 SCIP_Real gmultaggrbranch;
    925 SCIP_Real downgain;
    926 SCIP_Real upgain;
    927 SCIP_Real down;
    928 SCIP_Real up;
    929 int nmultaggrbranch;
    930
    931 down = MAX(bestdown, lpobjval);
    932 up = MAX(bestup, lpobjval);
    933 downgain = down - lpobjval;
    934 upgain = up - lpobjval;
    935
    936 SCIP_CALL( ensureArraySize(scip, branchruledata) );
    937
    938 gfractbranch= sqrt(MAX(fdowngain,1e-06) * MAX(fupgain,1e-06));
    939 gmultaggrbranch = sqrt(MAX(downgain,1e-06) * MAX(upgain,1e-06));
    940
    941 nmultaggrbranch = branchruledata->nmultaggrbranch;
    942
    943 if( gmultaggrbranch == 0.0 )
    944 {
    945 branchruledata->ratioggain[nmultaggrbranch - 1] = 1;
    946 }
    947 else
    948 {
    949 branchruledata->ratioggain[nmultaggrbranch - 1] = gfractbranch / gmultaggrbranch;
    950 }
    951 }
    952 }
    953 )
    954
    955 /* create the multi-aggregated constraints rounded up and down */
    956 SCIP_CALL( SCIPcreateConsLinear(scip, &multaggrconsdown, "consdown", SCIPvarGetMultaggrNVars(bestcand),
    958 SCIPfeasFloor(scip, bestsol) - SCIPvarGetMultaggrConstant(bestcand),
    960
    961 SCIP_CALL( SCIPcreateConsLinear(scip, &multaggrconsup, "consup", SCIPvarGetMultaggrNVars(bestcand),
    965
    966 /* create the child nodes */
    967 SCIP_CALL( SCIPcreateChild(scip, &downchild, 1.0, estimatedown) );
    968 SCIPdebugMsg(scip, " down node: lowerbound %f estimate %f\n", SCIPnodeGetLowerbound(downchild), SCIPnodeGetEstimate(downchild));
    969
    970 SCIP_CALL( SCIPcreateChild(scip, &upchild, 1.0, estimateup) );
    971 SCIPdebugMsg(scip, " up node: lowerbound %f estimate %f\n", SCIPnodeGetLowerbound(upchild), SCIPnodeGetEstimate(upchild));
    972
    973 assert(downchild != NULL);
    974 assert(upchild != NULL);
    975
    976 SCIP_CALL( SCIPaddConsNode(scip, downchild, multaggrconsdown, NULL) );
    977 SCIP_CALL( SCIPaddConsNode(scip, upchild, multaggrconsup, NULL) );
    978
    979#ifdef PRINTNODECONS
    980 SCIPdebugMsg(scip, "branching at node %lld\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip)));
    981
    982 SCIPdebugMsg(scip, "created child node %lld with constraint:\n", SCIPnodeGetNumber(downchild));
    983 SCIP_CALL( SCIPprintCons(scip, multaggrconsdown, NULL) );
    984 SCIPinfoMessage(scip, NULL, "\n");
    985
    986 SCIPdebugMsg(scip, "created child node %lld with constraint:\n", SCIPnodeGetNumber(upchild));
    987 SCIP_CALL( SCIPprintCons(scip, multaggrconsup, NULL) );
    988 SCIPinfoMessage(scip, NULL, "\n");
    989#endif
    990
    991 /* relase constraints */
    992 SCIP_CALL( SCIPreleaseCons(scip, &multaggrconsdown) );
    993 SCIP_CALL( SCIPreleaseCons(scip, &multaggrconsup) );
    994
    995 SCIPdebugMsg(scip, "BRANCHED on multi-aggregated variable <%s>\n", SCIPvarGetName(bestcand));
    996
    997 *result = SCIP_BRANCHED;
    998 }
    999 else
    1000 {
    1002 if( !(branchruledata->noupdate) )
    1003 branchruledata->nfracbranch += 1
    1004 );
    1005
    1006 assert(*result == SCIP_DIDNOTRUN);
    1007 assert(SCIPisLT(scip, provedbound, SCIPgetCutoffbound(scip)));
    1008
    1009 SCIP_CALL( SCIPbranchVarVal(scip, bestcand, bestsol, &downchild, NULL, &upchild) );
    1010
    1011 assert(downchild != NULL);
    1012 assert(upchild != NULL);
    1013
    1014 SCIPdebugMsg(scip, "BRANCHED on fractional variable <%s>\n", SCIPvarGetName(bestcand));
    1015
    1016 *result = SCIP_BRANCHED;
    1017 }
    1018
    1019 /* update the lower bounds in the children; we must not do this if columns are missing in the LP
    1020 * (e.g., because we are doing branch-and-price) or the problem should be solved exactly
    1021 */
    1023 {
    1024 SCIP_CALL( SCIPupdateNodeLowerbound(scip, downchild, bestdownvalid ? MAX(bestdown, provedbound) : provedbound) );
    1025 SCIP_CALL( SCIPupdateNodeLowerbound(scip, upchild, bestupvalid ? MAX(bestup, provedbound) : provedbound) );
    1026 }
    1027 SCIPdebugMsg(scip, " -> down child's lowerbound: %g\n", SCIPnodeGetLowerbound(downchild));
    1028 SCIPdebugMsg(scip, " -> up child's lowerbound: %g\n", SCIPnodeGetLowerbound(upchild));
    1029 }
    1030 }
    1031 else
    1032 {
    1033 SCIPdebugMsg(scip, "strong branching breaks\n" );
    1034
    1036 if( *result == SCIP_CUTOFF )
    1037 {
    1038 branchruledata->nfractcutoff += 1;
    1039 }
    1040 else
    1041 {
    1042 branchruledata->nfractconsadd += 1;
    1043 }
    1044 )
    1045 }
    1046
    1047 SCIPfreeBufferArray(scip, &lpcandsfrac);
    1048 SCIPfreeBufferArray(scip, &lpcandssol);
    1049 SCIPfreeBufferArray(scip, &lpcands);
    1050
    1051 SCIP_CALL( SCIPsetLongintParam(scip, "branching/fullstrong/reevalage", oldreevalage) );
    1052
    1053 return SCIP_OKAY;
    1054}
    1055
    1056/*
    1057 * branching rule specific interface methods
    1058 */
    1059
    1060/** creates the multi-aggregated branching rule and includes it in SCIP */
    1062 SCIP* scip /**< SCIP data structure */
    1063 )
    1064{
    1065 SCIP_BRANCHRULEDATA* branchruledata;
    1066 SCIP_BRANCHRULE* branchrule;
    1067
    1068 /* create multaggr branching rule data */
    1069 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata) );
    1070 branchruledata->lastcand = 0;
    1071 branchruledata->skipsize = 0;
    1072 branchruledata->skipup = NULL;
    1073 branchruledata->skipdown = NULL;
    1074 SCIPstatistic(branchruledata->ratioggain = NULL);
    1075
    1076 /* include branching rule */
    1078 BRANCHRULE_MAXDEPTH, BRANCHRULE_MAXBOUNDDIST, branchruledata) );
    1079
    1080 assert(branchrule != NULL);
    1081
    1082 /* set non fundamental callbacks via setter functions */
    1083 SCIP_CALL( SCIPsetBranchruleCopy(scip, branchrule, branchCopyMultAggr) );
    1084 SCIP_CALL( SCIPsetBranchruleFree(scip, branchrule, branchFreeMultAggr) );
    1085 SCIP_CALL( SCIPsetBranchruleInit(scip, branchrule, branchInitMultAggr) );
    1086 SCIP_CALL( SCIPsetBranchruleExit(scip, branchrule, branchExitMultAggr) );
    1087 SCIP_CALL( SCIPsetBranchruleExecLp(scip, branchrule, branchExeclpMultAggr) );
    1088
    1089 /* multi-aggregated branching rule parameters */
    1091 "branching/multaggr/reevalage",
    1092 "number of intermediate LPs solved to trigger reevaluation of strong branching value for a variable that was already evaluated at the current node",
    1093 &branchruledata->reevalage, TRUE, DEFAULT_REEVALAGE, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
    1095 "branching/multaggr/maxproprounds",
    1096 "maximum number of propagation rounds to be performed during multaggr branching before solving the LP (-1: no limit, -2: parameter settings)",
    1097 &branchruledata->maxproprounds, TRUE, DEFAULT_MAXPROPROUNDS, -2, INT_MAX, NULL, NULL) );
    1099 "branching/multaggr/probingbounds",
    1100 "should valid bounds be identified in a probing-like fashion during multaggr branching (only with propagation)?",
    1101 &branchruledata->probingbounds, TRUE, DEFAULT_PROBINGBOUNDS, NULL, NULL) );
    1102
    1103 return SCIP_OKAY;
    1104}
    full strong LP branching rule
    #define BRANCHRULE_DESC
    #define BRANCHRULE_PRIORITY
    #define DEFAULT_PROBINGBOUNDS
    #define DEFAULT_REEVALAGE
    static SCIP_RETCODE selectVarMultAggrBranching(SCIP *scip, SCIP_VAR **bestcand, SCIP_Real *bestscore, SCIP_Real *bestsol, SCIP_Real *bestdown, SCIP_Real *bestup, SCIP_Bool *bestdownvalid, SCIP_Bool *bestupvalid, SCIP_Real *provedbound, SCIP_Real *estimatedown, SCIP_Real *estimateup, SCIP_RESULT *result)
    #define BRANCHRULE_NAME
    static SCIP_DECL_BRANCHINIT(branchInitMultAggr)
    static SCIP_DECL_BRANCHCOPY(branchCopyMultAggr)
    static SCIP_DECL_BRANCHEXECLP(branchExeclpMultAggr)
    #define DEFAULT_MAXPROPROUNDS
    static SCIP_DECL_BRANCHFREE(branchFreeMultAggr)
    #define BRANCHRULE_MAXDEPTH
    #define BRANCHRULE_MAXBOUNDDIST
    static SCIP_DECL_BRANCHEXIT(branchExitMultAggr)
    fullstrong branching on fractional and multi-aggregated variables
    Constraint handler for linear constraints in their most general form, .
    #define NULL
    Definition: def.h:248
    #define SCIP_Longint
    Definition: def.h:141
    #define SCIP_MAXTREEDEPTH
    Definition: def.h:297
    #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_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 SCIPincludeBranchruleMultAggr(SCIP *scip)
    SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, 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)
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    int SCIPgetNFixedVars(SCIP *scip)
    Definition: scip_prob.c:2705
    SCIP_VAR ** SCIPgetFixedVars(SCIP *scip)
    Definition: scip_prob.c:2662
    SCIP_RETCODE SCIPupdateNodeLowerbound(SCIP *scip, SCIP_NODE *node, SCIP_Real newbound)
    Definition: scip_prob.c:4354
    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 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 SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
    Definition: scip_param.c:545
    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 SCIPgetLongintParam(SCIP *scip, const char *name, SCIP_Longint *value)
    Definition: scip_param.c:288
    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
    int SCIPgetNLPBranchCands(SCIP *scip)
    Definition: scip_branch.c:436
    SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
    Definition: scip_branch.c:1025
    SCIP_Real SCIPgetBranchScore(SCIP *scip, SCIP_VAR *var, SCIP_Real downgain, SCIP_Real upgain)
    Definition: scip_branch.c:857
    SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
    Definition: scip_cons.c:2536
    const char * SCIPconsGetName(SCIP_CONS *cons)
    Definition: cons.c:8389
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    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
    int SCIPcalcMemGrowSize(SCIP *scip, int num)
    Definition: scip_mem.c:139
    #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 SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
    Definition: scip_mem.h:99
    #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 SCIPnodeGetNumber(SCIP_NODE *node)
    Definition: tree.c:8483
    SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
    Definition: tree.c:8523
    SCIP_RETCODE SCIPbacktrackProbing(SCIP *scip, int probingdepth)
    Definition: scip_probing.c:226
    SCIP_RETCODE SCIPstartProbing(SCIP *scip)
    Definition: scip_probing.c:120
    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 SCIPendProbing(SCIP *scip)
    Definition: scip_probing.c:261
    int SCIPgetNRuns(SCIP *scip)
    SCIP_Real SCIPgetCutoffbound(SCIP *scip)
    SCIP_RETCODE SCIPcreateClock(SCIP *scip, SCIP_CLOCK **clck)
    Definition: scip_timing.c:76
    SCIP_RETCODE SCIPstopClock(SCIP *scip, SCIP_CLOCK *clck)
    Definition: scip_timing.c:178
    SCIP_RETCODE SCIPfreeClock(SCIP *scip, SCIP_CLOCK **clck)
    Definition: scip_timing.c:127
    SCIP_Real SCIPgetClockTime(SCIP *scip, SCIP_CLOCK *clck)
    Definition: scip_timing.c:319
    SCIP_RETCODE SCIPstartClock(SCIP *scip, SCIP_CLOCK *clck)
    Definition: scip_timing.c:161
    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_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
    Definition: scip_tree.c:91
    SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
    Definition: var.c:23843
    SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
    Definition: var.c:23386
    SCIP_Bool SCIPvarIsNonimpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23506
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23267
    SCIP_Longint SCIPgetVarStrongbranchLPAge(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:5053
    SCIP_Real SCIPgetVarPseudocostVal(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta)
    Definition: scip_var.c:11188
    SCIP_Real SCIPvarGetLPSol(SCIP_VAR *var)
    Definition: var.c:24664
    SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
    Definition: var.c:23806
    int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
    Definition: var.c:23794
    SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
    Definition: var.c:23818
    static SCIP_RETCODE reoptimize(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol, BLOCKPROBLEM **blockproblem, int nblocks, SCIP_Bool limits, SCIP_SOL **newsol, SCIP_Bool *success)
    Definition: heur_dps.c:1514
    memory allocation routines
    #define BMSclearMemoryArray(ptr, num)
    Definition: memory.h:130
    public methods for branching rules
    public methods for managing constraints
    public methods for message output
    #define SCIPstatistic(x)
    Definition: pub_message.h:120
    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 querying solving statistics
    public methods for timing
    public methods for the branch-and-bound tree
    public methods for SCIP variables
    struct SCIP_BranchruleData SCIP_BRANCHRULEDATA
    Definition: type_branch.h:57
    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_OBJLIMIT
    Definition: type_lp.h:47
    @ SCIP_LPSOLSTAT_ITERLIMIT
    Definition: type_lp.h:48
    @ SCIP_VERBLEVEL_NORMAL
    Definition: type_message.h:60
    @ 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
    @ SCIP_VARSTATUS_MULTAGGR
    Definition: type_var.h:56