Scippy

    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-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_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 <assert.h>
    78#include <string.h>
    79
    80#include "branch_ryanfoster.h"
    81#include "cons_samediff.h"
    82#include "probdata_binpacking.h"
    83#include "vardata_binpacking.h"
    84
    85/**@name Branching rule properties
    86 *
    87 * @{
    88 */
    89
    90#define BRANCHRULE_NAME "RyanFoster"
    91#define BRANCHRULE_DESC "Ryan/Foster branching rule"
    92#define BRANCHRULE_PRIORITY 50000
    93#define BRANCHRULE_MAXDEPTH -1
    94#define BRANCHRULE_MAXBOUNDDIST 1.0
    95
    96/**@} */
    97
    98/**@name Callback methods
    99 *
    100 * @{
    101 */
    102
    103/** branching execution method for fractional LP solutions */
    104static
    105SCIP_DECL_BRANCHEXECLP(branchExeclpRyanFoster)
    106{ /*lint --e{715}*/
    107 SCIP_PROBDATA* probdata;
    108 SCIP_Real** pairweights;
    109 SCIP_VAR** lpcands;
    110 SCIP_Real* lpcandsfrac;
    111 int nlpcands;
    112 SCIP_Real bestvalue;
    113 SCIP_Real value;
    114
    115 SCIP_NODE* childsame;
    116 SCIP_NODE* childdiffer;
    117 SCIP_CONS* conssame;
    118 SCIP_CONS* consdiffer;
    119
    120 SCIP_VARDATA* vardata;
    121 int* consids;
    122 int nconsids;
    123 int nitems;
    124
    125 int id1;
    126 int id2;
    127
    128 int i;
    129 int j;
    130 int v;
    131
    132 assert(scip != NULL);
    133 assert(branchrule != NULL);
    134 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
    135 assert(result != NULL);
    136
    137 SCIPdebugMsg(scip, "start branching at node %"SCIP_LONGINT_FORMAT", depth %d\n", SCIPgetNNodes(scip), SCIPgetDepth(scip));
    138
    139 *result = SCIP_DIDNOTRUN;
    140
    141 probdata = SCIPgetProbData(scip);
    142 assert(probdata != NULL);
    143
    144 nitems = SCIPprobdataGetNItems(probdata);
    145
    146 /* allocate memory for triangle matrix */
    147 SCIP_CALL( SCIPallocBufferArray(scip, &pairweights, nitems) );
    148 for( i = 0; i < nitems; ++i )
    149 {
    150 SCIP_CALL( SCIPallocClearBufferArray(scip, &pairweights[i], i+1) ); /*lint !e866 */
    151 }
    152
    153 /* get fractional LP candidates */
    154 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, NULL, &lpcandsfrac, NULL, &nlpcands, NULL) );
    155 assert(nlpcands > 0);
    156
    157 /* compute weights for each order pair */
    158 for( v = 0; v < nlpcands; ++v )
    159 {
    160 SCIP_Real solval;
    161
    162 assert(lpcands[v] != NULL);
    163
    164 solval = lpcandsfrac[v];
    165
    166 /* get variable data which contains the information to which constraints/items the variable belongs */
    167 vardata = SCIPvarGetData(lpcands[v]);
    168
    169 consids = SCIPvardataGetConsids(vardata);
    170 nconsids = SCIPvardataGetNConsids(vardata);
    171 assert(nconsids > 0);
    172
    173 /* loop over all constraints/items the variable belongs to */
    174 for( i = 0; i < nconsids; ++i )
    175 {
    176 id1 = consids[i];
    177
    178 /* store the LP sum for single items in the diagonal */
    179 pairweights[id1][id1] += solval;
    180
    181 /* update LP sums for all pairs of items */
    182 for( j = i+1; j < nconsids; ++j )
    183 {
    184 id2 = consids[j];
    185 assert(id1 < id2);
    186
    187 pairweights[id2][id1] += solval;
    188
    189 assert( SCIPisFeasGE(scip, pairweights[id2][id1], 0.0) );
    190 }
    191 }
    192 }
    193
    194 /* select branching */
    195 bestvalue = 0.0;
    196 id1 = -1;
    197 id2 = -1;
    198
    199 for( i = 0; i < nitems; ++i )
    200 {
    201 for( j = 0; j < i; ++j )
    202 {
    203 value = MIN(pairweights[i][j], 1-pairweights[i][j]);
    204
    205 if( bestvalue < value )
    206 {
    207 bestvalue = value;
    208 id1 = j;
    209 id2 = i;
    210 }
    211 }
    212 }
    213
    214 assert( SCIPisFeasPositive(scip, bestvalue) );
    215 assert( id1 >= 0 && id1 < nitems);
    216 assert( id2 >= 0 && id2 < nitems);
    217
    218 /* free memory for triangle matrix */
    219 for( i = 0; i < nitems; ++i )
    220 {
    221 SCIPfreeBufferArray(scip, &pairweights[i]);
    222 }
    223 SCIPfreeBufferArray(scip, &pairweights);
    224
    225 SCIPdebugMsg(scip, "branch on order pair <%d,%d> with weight <%g>\n",
    226 SCIPprobdataGetIds(probdata)[id1], SCIPprobdataGetIds(probdata)[id2], bestvalue);
    227
    228 /* create the branch-and-bound tree child nodes of the current node */
    231
    232 /* create corresponding constraints */
    233 SCIP_CALL( SCIPcreateConsSamediff(scip, &conssame, "same", id1, id2, SAME, childsame, TRUE) );
    234 SCIP_CALL( SCIPcreateConsSamediff(scip, &consdiffer, "differ", id1, id2, DIFFER, childdiffer, TRUE) );
    235
    236 /* add constraints to nodes */
    237 SCIP_CALL( SCIPaddConsNode(scip, childsame, conssame, NULL) );
    238 SCIP_CALL( SCIPaddConsNode(scip, childdiffer, consdiffer, NULL) );
    239
    240 /* release constraints */
    241 SCIP_CALL( SCIPreleaseCons(scip, &conssame) );
    242 SCIP_CALL( SCIPreleaseCons(scip, &consdiffer) );
    243
    244 *result = SCIP_BRANCHED;
    245
    246 return SCIP_OKAY;
    247}
    248
    249/**@} */
    250
    251/**@name Interface methods
    252 *
    253 * @{
    254 */
    255
    256/** creates the ryan foster branching rule and includes it in SCIP */
    258 SCIP* scip /**< SCIP data structure */
    259 )
    260{
    261 SCIP_BRANCHRULEDATA* branchruledata;
    262 SCIP_BRANCHRULE* branchrule;
    263
    264 /* create ryan foster branching rule data */
    265 branchruledata = NULL;
    266 branchrule = NULL;
    267 /* include branching rule */
    269 BRANCHRULE_MAXBOUNDDIST, branchruledata) );
    270 assert(branchrule != NULL);
    271
    272 SCIP_CALL( SCIPsetBranchruleExecLp(scip, branchrule, branchExeclpRyanFoster) );
    273
    274 return SCIP_OKAY;
    275}
    276
    277/**@} */
    #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:248
    #define MIN(x, y)
    Definition: def.h:224
    #define SCIP_Real
    Definition: def.h:156
    #define TRUE
    Definition: def.h:93
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:148
    #define SCIP_CALL(x)
    Definition: def.h:355
    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:23287
    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
    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.