SCIP

    Solving Constraint Integer Programs

    branch_ryanfoster.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-2026 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_ryanfoster.c
    26 * @ingroup BRANCHINGRULES
    27 * @brief Ryan/Foster branching rule
    28 * @author Timo Berthold
    29 * @author Stefan Heinz
    30 *
    31 * This file implements the Ryan/Foster branching rule. For more details see \ref BINPACKING_BRANCHING page.
    32 *
    33 * @page BINPACKING_BRANCHING Ryan/Foster branching
    34 *
    35 * Ryan/Foster branching is a very useful branching rule for the integer program model in use. A
    36 * standard variable branching has the disadvantage that the zero branch is more or less useless because
    37 * we only forbid one packing out of exponential many. On the other hand, the branch fixing a packing reduces the problem since
    38 * certain items are packed. This leads to a very unbalanced search tree.
    39 *
    40 * The branching rule of Ryan/Foster was itroduced in@n
    41 * D. M. Ryan and B. A. Foster: An Integer Programming Approach to Scheduling,
    42 * In Computer scheduling of public transport: Urban passenger vehicle and crew scheduling, A. Wren editor, North-Holland 1981, 269-280.
    43 *
    44 * The idea is to select a pair of items which is either a) forced to be packed together or b)
    45 * not allowed to be packed together. Note that in both cases, it is allowed to use packings
    46 * which contain none of the two items.
    47 *
    48 * There are two issues to be taken care off:
    49 * -# How do we select the pair of items?
    50 * -# How do we realize such a branching within \SCIP?
    51 *
    52 * @section BINPACKING_SELECTION How do we select the pair of items?
    53 *
    54 * To select a pair of items, we have to know for each packing the items which are contained. Since every packing is a
    55 * variable and each item is a set covering constraint, we have to know for each variable in which set covering
    56 * constraints it appears (this means, has a coefficient of 1.0). Since \SCIP is constraint based, it is in general
    57 * not possible to get this information directly. To overcome this issue, we use the functionality to add
    58 * \ref vardata_binpacking.c "variable data" to every
    59 * variable. This variable data contains the constraints in which this variable appears (see vardata_binpacking.c for more details).
    60 * With the help of the variable data, it is now possible to get the
    61 * information which items belong to which packing. Therefore, we can use the Ryan/Foster idea to select a pair of
    62 * items.
    63 *
    64 * @section BINPACKING_SAMEDIFFBRANCHING How do we realize such a branching within SCIP?
    65 *
    66 * After having selected a pair of items to branch on, the question now is how to realize such a branching with \SCIP.
    67 * Since \SCIP is
    68 * constraint based, it is really easy to do that. We implement a constraint handler which handles the
    69 * information, see cons_samediff.c. This constraint handler does not only store the branching
    70 * decisions. Furthermore, it also ensures that all packing which are not feasible at a particular node are
    71 * locally fixed to zero. For more details, we refer to the \ref cons_samediff.c "source code of the constraint handler".
    72 *
    73 */
    74
    75/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    76
    77#include "branch_ryanfoster.h"
    78#include "cons_samediff.h"
    79#include "probdata_binpacking.h"
    80#include "vardata_binpacking.h"
    81
    82/**@name Branching rule properties
    83 *
    84 * @{
    85 */
    86
    87#define BRANCHRULE_NAME "RyanFoster"
    88#define BRANCHRULE_DESC "Ryan/Foster branching rule"
    89#define BRANCHRULE_PRIORITY 50000
    90#define BRANCHRULE_MAXDEPTH -1
    91#define BRANCHRULE_MAXBOUNDDIST 1.0
    92
    93/**@} */
    94
    95/**@name Callback methods
    96 *
    97 * @{
    98 */
    99
    100/** branching execution method for fractional LP solutions */
    101static
    102SCIP_DECL_BRANCHEXECLP(branchExeclpRyanFoster)
    103{ /*lint --e{715}*/
    104 SCIP_PROBDATA* probdata;
    105 SCIP_Real** pairweights;
    106 SCIP_VAR** lpcands;
    107 SCIP_Real* lpcandsfrac;
    108 int nlpcands;
    109 SCIP_Real bestvalue;
    110 SCIP_Real value;
    111
    112 SCIP_NODE* childsame;
    113 SCIP_NODE* childdiffer;
    114 SCIP_CONS* conssame;
    115 SCIP_CONS* consdiffer;
    116
    117 SCIP_VARDATA* vardata;
    118 int* consids;
    119 int nconsids;
    120 int nitems;
    121
    122 int id1;
    123 int id2;
    124
    125 int i;
    126 int j;
    127 int v;
    128
    129 assert(scip != NULL);
    130 assert(branchrule != NULL);
    131 assert(result != NULL);
    132
    134
    135 SCIPdebugMsg(scip, "start branching at node %"SCIP_LONGINT_FORMAT", depth %d\n", SCIPgetNNodes(scip), SCIPgetDepth(scip));
    136
    137 *result = SCIP_DIDNOTRUN;
    138
    139 probdata = SCIPgetProbData(scip);
    140 assert(probdata != NULL);
    141
    142 nitems = SCIPprobdataGetNItems(probdata);
    143
    144 /* allocate memory for triangle matrix */
    145 SCIP_CALL( SCIPallocBufferArray(scip, &pairweights, nitems) );
    146 for( i = 0; i < nitems; ++i )
    147 {
    148 SCIP_CALL( SCIPallocClearBufferArray(scip, &pairweights[i], i+1) ); /*lint !e866 */
    149 }
    150
    151 /* get fractional LP candidates */
    152 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, NULL, &lpcandsfrac, NULL, &nlpcands, NULL) );
    153 assert(nlpcands > 0);
    154
    155 /* compute weights for each order pair */
    156 for( v = 0; v < nlpcands; ++v )
    157 {
    158 SCIP_Real solval;
    159
    160 assert(lpcands[v] != NULL);
    161
    162 solval = lpcandsfrac[v];
    163
    164 /* get variable data which contains the information to which constraints/items the variable belongs */
    165 vardata = SCIPvarGetData(lpcands[v]);
    166
    167 consids = SCIPvardataGetConsids(vardata);
    168 nconsids = SCIPvardataGetNConsids(vardata);
    169 assert(nconsids > 0);
    170
    171 /* loop over all constraints/items the variable belongs to */
    172 for( i = 0; i < nconsids; ++i )
    173 {
    174 id1 = consids[i];
    175
    176 /* store the LP sum for single items in the diagonal */
    177 pairweights[id1][id1] += solval;
    178
    179 /* update LP sums for all pairs of items */
    180 for( j = i+1; j < nconsids; ++j )
    181 {
    182 id2 = consids[j];
    183 assert(id1 < id2);
    184
    185 pairweights[id2][id1] += solval;
    186
    187 assert( SCIPisFeasGE(scip, pairweights[id2][id1], 0.0) );
    188 }
    189 }
    190 }
    191
    192 /* select branching */
    193 bestvalue = 0.0;
    194 id1 = -1;
    195 id2 = -1;
    196
    197 for( i = 0; i < nitems; ++i )
    198 {
    199 for( j = 0; j < i; ++j )
    200 {
    201 value = MIN(pairweights[i][j], 1-pairweights[i][j]);
    202
    203 if( bestvalue < value )
    204 {
    205 bestvalue = value;
    206 id1 = j;
    207 id2 = i;
    208 }
    209 }
    210 }
    211
    212 assert( SCIPisFeasPositive(scip, bestvalue) );
    213 assert( id1 >= 0 && id1 < nitems);
    214 assert( id2 >= 0 && id2 < nitems);
    215
    216 /* free memory for triangle matrix */
    217 for( i = 0; i < nitems; ++i )
    218 {
    219 SCIPfreeBufferArray(scip, &pairweights[i]);
    220 }
    221 SCIPfreeBufferArray(scip, &pairweights);
    222
    223 SCIPdebugMsg(scip, "branch on order pair <%d,%d> with weight <%g>\n",
    224 SCIPprobdataGetIds(probdata)[id1], SCIPprobdataGetIds(probdata)[id2], bestvalue);
    225
    226 /* create the branch-and-bound tree child nodes of the current node */
    229
    230 /* create corresponding constraints */
    231 SCIP_CALL( SCIPcreateConsSamediff(scip, &conssame, "same", id1, id2, SAME, childsame, TRUE) );
    232 SCIP_CALL( SCIPcreateConsSamediff(scip, &consdiffer, "differ", id1, id2, DIFFER, childdiffer, TRUE) );
    233
    234 /* add constraints to nodes */
    235 SCIP_CALL( SCIPaddConsNode(scip, childsame, conssame, NULL) );
    236 SCIP_CALL( SCIPaddConsNode(scip, childdiffer, consdiffer, NULL) );
    237
    238 /* release constraints */
    239 SCIP_CALL( SCIPreleaseCons(scip, &conssame) );
    240 SCIP_CALL( SCIPreleaseCons(scip, &consdiffer) );
    241
    242 *result = SCIP_BRANCHED;
    243
    244 return SCIP_OKAY;
    245}
    246
    247/**@} */
    248
    249/**@name Interface methods
    250 *
    251 * @{
    252 */
    253
    254/** creates the ryan foster branching rule and includes it in SCIP */
    256 SCIP* scip /**< SCIP data structure */
    257 )
    258{
    259 SCIP_BRANCHRULEDATA* branchruledata;
    260 SCIP_BRANCHRULE* branchrule;
    261
    262 /* create ryan foster branching rule data */
    263 branchruledata = NULL;
    264 branchrule = NULL;
    265 /* include branching rule */
    267 BRANCHRULE_MAXBOUNDDIST, branchruledata) );
    268 assert(branchrule != NULL);
    269
    270 SCIP_CALL( SCIPsetBranchruleExecLp(scip, branchrule, branchExeclpRyanFoster) );
    271
    272 return SCIP_OKAY;
    273}
    274
    275/**@} */
    #define BRANCHRULE_DESC
    static SCIP_DECL_BRANCHEXECLP(branchExeclpRyanFoster)
    SCIP_RETCODE SCIPincludeBranchruleRyanFoster(SCIP *scip)
    #define BRANCHRULE_PRIORITY
    #define BRANCHRULE_NAME
    #define BRANCHRULE_MAXDEPTH
    #define BRANCHRULE_MAXBOUNDDIST
    Ryan/Foster branching rule.
    SCIP_RETCODE SCIPcreateConsSamediff(SCIP *scip, SCIP_CONS **cons, const char *name, int itemid1, int itemid2, CONSTYPE type, SCIP_NODE *node, SCIP_Bool local)
    Constraint handler stores the local branching decision data.
    @ SAME
    Definition: cons_samediff.h:47
    @ DIFFER
    Definition: cons_samediff.h:46
    #define NULL
    Definition: def.h:257
    #define MIN(x, y)
    Definition: def.h:233
    #define SCIP_STRINGEQ(name, reference, retcode)
    Definition: def.h:454
    #define SCIP_Real
    Definition: def.h:165
    #define TRUE
    Definition: def.h:102
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:157
    #define SCIP_CALL(x)
    Definition: def.h:364
    SCIP_PROBDATA * SCIPgetProbData(SCIP *scip)
    Definition: scip_prob.c:1139
    SCIP_RETCODE SCIPaddConsNode(SCIP *scip, SCIP_NODE *node, SCIP_CONS *cons, SCIP_NODE *validnode)
    Definition: scip_prob.c:3901
    SCIP_Real SCIPgetLocalTransEstimate(SCIP *scip)
    Definition: scip_prob.c:4139
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    SCIP_RETCODE SCIPsetBranchruleExecLp(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHEXECLP((*branchexeclp)))
    Definition: scip_branch.c:256
    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_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_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
    Definition: scip_branch.c:1025
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    #define SCIPallocClearBufferArray(scip, ptr, num)
    Definition: scip_mem.h:126
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    SCIP_Longint SCIPgetNNodes(SCIP *scip)
    SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    SCIP_VARDATA * SCIPvarGetData(SCIP_VAR *var)
    Definition: var.c:23319
    int * SCIPprobdataGetIds(SCIP_PROBDATA *probdata)
    int SCIPprobdataGetNItems(SCIP_PROBDATA *probdata)
    Problem data for binpacking problem.
    struct SCIP_BranchruleData SCIP_BRANCHRULEDATA
    Definition: type_branch.h:57
    struct SCIP_ProbData SCIP_PROBDATA
    Definition: type_prob.h:53
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_BRANCHED
    Definition: type_result.h:54
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    struct SCIP_VarData SCIP_VARDATA
    Definition: type_var.h:167
    int * SCIPvardataGetConsids(SCIP_VARDATA *vardata)
    int SCIPvardataGetNConsids(SCIP_VARDATA *vardata)
    Variable data containing the ids of constraints in which the variable appears.