Scippy

    SCIP

    Solving Constraint Integer Programs

    branch_coloring.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_coloring.c
    26 * @brief default branching rule for the vertex coloring problem
    27 * @author Gerald Gamrath
    28 * @author Julian Meffert
    29 *
    30 * This file implements the standard branching rule for the coloring algorithm.
    31 *
    32 * As we use column generation, we may not branch on the variables themselves,
    33 * but on some sort of constraints that we introduce in the pricing problem.
    34 *
    35 * In our case, we choose two nodes v and w, which are not adjacent in the current graph, and
    36 * consider the following two constraints: SAME(v,w) and DIFFER(v,w). SAME(v,w) requires that both
    37 * nodes v and w get the same color, whereas DIFFER(v,w) forbids this. For each pair of nodes, each
    38 * feasible solution fulfills exactly one of these constraints. Hence, splitting the solution space
    39 * into two parts, one fulfilling SAME(v,w) and the other DIFFER(v,w), does not cut off any feasible
    40 * solution and can therefore be used as the branching rule.
    41 *
    42 * The branching is done as follows: Given the optimal (fractional) solution of the current
    43 * branch-and-bound node, choose the least/most fractional variable and the corresponding stable set
    44 * s1. Now choose two nodes v, w and another stable set s2, such that v is part of both stable sets,
    45 * whereas w is part of exactly one of the stable sets. Create two children of the current node,
    46 * one with the restriction SAME(v,w), the other one with restriction DIFFER(v,w). Therefore, each
    47 * node gets a constraint of type @c cons_storeGraph, which enforces the branching decision and
    48 * assures that each coloring of the nodes in the respective subgraph assigns to both nodes the same
    49 * color/different colors by fixing stable sets to 0 that violate this constraint.
    50 */
    51
    52/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    53#include <assert.h>
    54#include <string.h>
    55
    56#include "branch_coloring.h"
    57
    58#define BRANCHRULE_NAME "coloring"
    59#define BRANCHRULE_DESC "branching rule template"
    60#define BRANCHRULE_PRIORITY 50000
    61#define BRANCHRULE_MAXDEPTH -1
    62#define BRANCHRULE_MAXBOUNDDIST 1.0
    63
    64#define BRANCHRULE_STRATEGIES "ml" /**< possible variable selection strategies m=most fractional, l=least fractional */
    65#define BRANCHRULE_STRATEGY_DEFAULT 'l' /**< default variable selection strategy */
    66
    67
    68/*
    69 * Data structures
    70 */
    71
    72/** branching rule data */
    73struct SCIP_BranchruleData
    74{
    75 char strategy; /* determines the variable selection,
    76 l: for least fractional variable,
    77 m: for most fractional variable */
    78};
    79
    80
    81/*
    82 * Callback methods of branching rule
    83 */
    84
    85/** branching execution method for fractional LP solutions */
    86static
    87SCIP_DECL_BRANCHEXECLP(branchExeclpColoring)
    88{
    89 /* array of candidates for branching + fractionalities of candidates + length of array */
    90 SCIP_VAR** lpcands;
    91 SCIP_Real* lpcandsfrac;
    92 int nlpcands;
    93 /* variables for finding the most fractional column */
    94 SCIP_Real fractionality;
    95 SCIP_Real bestfractionality;
    96 int bestcand;
    97 /* array of variables in a constraint + length of array */
    98 SCIP_VAR** vars;
    99 int nvars;
    100 /* the variables for 2 stable sets, needed to find the two nodes for branching */
    101 SCIP_VAR* s1;
    102 SCIP_VAR* s2;
    103 /* the 2 stable sets: array with all nodes and arraylength for each of them */
    104 int* set1;
    105 int setlength1;
    106 int* set2;
    107 int setlength2;
    108 /* the 2 nodes, for which the branching is done by DIFFER and SAME */
    109 int node1;
    110 int node2;
    111 /* the constraint belonging to node1 */
    112 SCIP_CONS* cons1;
    113 /* the nodes in the branch&bound-tree which are created */
    114 SCIP_NODE* childsame;
    115 SCIP_NODE* childdiffer;
    116 /* the constraints for the created b&b-nodes */
    117 SCIP_CONS* conssame;
    118 SCIP_CONS* consdiffer;
    119 /* the constraint of the processed b&b-node */
    120 SCIP_CONS* currentcons;
    121 /* the variable selection strategy */
    122 char strategy;
    123 /* the branching rule data */
    124 SCIP_BRANCHRULEDATA* branchruledata;
    125
    126 int i;
    127 int j;
    128 int k;
    129 int l;
    130 int setindex;
    131
    132 assert(scip != NULL);
    133 assert(branchrule != NULL);
    134 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
    135 assert(result != NULL);
    136
    137 *result = SCIP_DIDNOTRUN;
    138
    139 /* get branching candidates */
    140 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, NULL, &lpcandsfrac, NULL, &nlpcands, NULL) );
    141 assert(nlpcands > 0);
    142
    143 branchruledata = SCIPbranchruleGetData(branchrule);
    144 strategy = branchruledata->strategy;
    145
    146 bestcand = -1;
    147
    148 switch( strategy )
    149 {
    150 case 'l':
    151 /* search the least fractional candidate */
    152 bestfractionality = 1;
    153 for( i = 0; i < nlpcands; ++i )
    154 {
    155 assert(lpcands[i] != NULL);
    156 fractionality = lpcandsfrac[i];
    157 fractionality = MIN( fractionality, 1.0-fractionality );
    158 if ( fractionality < bestfractionality )
    159 {
    160 bestfractionality = fractionality;
    161 bestcand = i;
    162 }
    163 }
    164 break;
    165
    166 case 'm':
    167 /* search the most fractional candidate */
    168 bestfractionality = 0;
    169 for( i = 0; i < nlpcands; ++i ) {
    170 assert(lpcands[i] != NULL);
    171 fractionality = lpcandsfrac[i];
    172 fractionality = MIN( fractionality, 1.0-fractionality );
    173 if ( fractionality > bestfractionality )
    174 {
    175 bestfractionality = fractionality;
    176 bestcand = i;
    177 }
    178 }
    179 break;
    180 default:
    181 SCIPABORT();
    183 }
    184
    185 assert(bestcand >= 0);
    186 assert(SCIPisFeasPositive(scip, bestfractionality));
    187
    188 /* s1 = column belonging to bestcand */
    189 s1 = lpcands[bestcand];
    190 setindex = (int)(size_t) SCIPvarGetData(s1);
    191
    192 /* get stable set corresponding to variable s1 */
    193 COLORprobGetStableSet(scip, setindex, &set1, &setlength1);
    194
    195 node1 = -1;
    196 node2 = -1;
    197 s2 = NULL;
    198 /* search for two nodes node1, node2 and column s2 (s2 != s1) such that:
    199 the node1-constraint is covered by s1 and s2
    200 the node2-constraint is covered by exactly one of the columns s1,s2 */
    201 for ( i = 0; ((i < setlength1) && (node2 == -1)); i++ )
    202 {
    203 node1 = COLORconsGetRepresentative(scip, set1[i]);
    204 /* search for other set containing the node */
    205 cons1 = COLORprobGetConstraint(scip, node1);
    206 vars = SCIPgetVarsSetppc(scip, cons1);
    207 nvars = SCIPgetNVarsSetppc(scip, cons1);
    208 for ( j = 0; j < nvars; j++ )
    209 {
    210 if ( vars[j] != s1 && !SCIPisFeasZero(scip, SCIPvarGetUbLocal(vars[j])) )
    211 {
    212 s2 = vars[j];
    213 setindex = (int)(size_t) SCIPvarGetData(s2);
    214 /* get Stable Set corresponding to Variable s2 */
    215 COLORprobGetStableSet(scip, setindex, &set2, &setlength2);
    216 /* for all nodes in set1 */
    217 for ( k = 0; k < setlength1; k++ )
    218 {
    219 /* set node2 = current node in set1 */
    220 node2 = COLORconsGetRepresentative(scip, set1[k]);
    221 if ( node2 == node1)
    222 {
    223 node2 = -1;
    224 }
    225 else
    226 {
    227 /* check whether node2 is in set2 */
    228 for ( l = 0; l < setlength2; l++ )
    229 {
    230 if ( COLORconsGetRepresentative(scip, set2[l]) == node2 )
    231 {
    232 /* node2 is in both sets -> no branching-candidate */
    233 node2 = -1;
    234 break; /* for l */
    235 }
    236 }
    237 /* if node2 found, get out of for-loops */
    238 if ( node2 != -1 )
    239 {
    240 break; /* for k */
    241 }
    242 }
    243 }
    244 if ( node2 != -1 )
    245 {
    246 break; /* for j */
    247 }
    248 for ( k = 0; k < setlength2; k++ )
    249 {
    250 /* set node2 = current node in set1 */
    251 node2 = COLORconsGetRepresentative(scip, set2[k]);
    252 if ( node2 == node1)
    253 {
    254 node2 = -1;
    255 }
    256 else
    257 {
    258 /* check whether node2 is in set2 */
    259 for ( l = 0; l < setlength1; l++ )
    260 {
    261 if ( COLORconsGetRepresentative(scip, set1[l]) == node2 )
    262 {
    263 /* node2 is in both sets -> no branching-candidate */
    264 node2 = -1;
    265 break; /* for l */
    266 }
    267 }
    268 /* if node2 found, get out of for-loops */
    269 if ( node2 != -1 )
    270 {
    271 break; /* for k */
    272 }
    273 }
    274 }
    275 if ( node2 != -1 )
    276 {
    277 break; /* for j */
    278 }
    279 }
    280 }
    281 }
    282
    283 assert(node2 != -1);
    284 assert(node1 != -1);
    285 assert(node1 == COLORconsGetRepresentative(scip, node1));
    286 assert(node2 == COLORconsGetRepresentative(scip, node2));
    289 assert(!tcliqueIsEdge(COLORconsGetCurrentGraph(scip), node1, node2));
    290
    291 /* create the b&b-tree child-nodes of the current node */
    294
    295 /* create corresponding constraints */
    297 SCIP_CALL( COLORcreateConsStoreGraph(scip, &conssame, "same", currentcons, COLOR_CONSTYPE_SAME, node1, node2, childsame) );
    298 SCIP_CALL( COLORcreateConsStoreGraph(scip, &consdiffer, "differ", currentcons, COLOR_CONSTYPE_DIFFER, node1, node2, childdiffer) );
    299
    300 /* add constraints to nodes */
    301 SCIP_CALL( SCIPaddConsNode(scip, childsame, conssame, NULL) );
    302 SCIP_CALL( SCIPaddConsNode(scip, childdiffer, consdiffer, NULL) );
    303
    304 /* release constraints */
    305 SCIP_CALL( SCIPreleaseCons(scip, &conssame) );
    306 SCIP_CALL( SCIPreleaseCons(scip, &consdiffer) );
    307
    308 *result = SCIP_BRANCHED;
    309
    310 return SCIP_OKAY;
    311}/*lint !e715*/
    312
    313
    314/** branching execution method for not completely fixed pseudo solutions */
    315static
    316SCIP_DECL_BRANCHEXECPS(branchExecpsColoring)
    317{
    318 /* the 2 nodes, for which the branching is done by DIFFER and SAME */
    319 int node1;
    320 int node2;
    321 /* the nodes in the branch&bound-tree which are created */
    322 SCIP_NODE* childsame;
    323 SCIP_NODE* childdiffer;
    324 /* the constraints for the created b&b-nodes */
    325 SCIP_CONS* conssame;
    326 SCIP_CONS* consdiffer;
    327 /* the constraint of the processed b&b-node */
    328 SCIP_CONS* currentcons;
    329
    330 assert(scip != NULL);
    331 assert(branchrule != NULL);
    332 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
    333 assert(result != NULL);
    334
    335 *result = SCIP_DIDNOTRUN;
    336
    337 /* search for two nodes node1, node2 such that:
    338 node1 and node2 are neither in the same union nor adjacent */
    339 for ( node1 = 0; node1 < COLORprobGetNNodes(scip); ++node1 )
    340 {
    341 if ( node1 != COLORconsGetRepresentative(scip, node1) )
    342 {
    343 continue;
    344 }
    345 for ( node2 = node1+1; node2 < COLORprobGetNNodes(scip); ++node2 )
    346 {
    347 if ( node2 != COLORconsGetRepresentative(scip, node2) )
    348 {
    349 continue;
    350 }
    351 if ( (node2 != node1) && !tcliqueIsEdge(COLORconsGetCurrentGraph(scip), node1, node2))
    352 {
    353 /* create the b&b-tree child-nodes of the current node */
    356
    357 /* create corresponding constraints */
    359 SCIP_CALL( COLORcreateConsStoreGraph(scip, &conssame, "same", currentcons, COLOR_CONSTYPE_SAME, node1, node2, childsame) );
    360 SCIP_CALL( COLORcreateConsStoreGraph(scip, &consdiffer, "differ", currentcons, COLOR_CONSTYPE_DIFFER, node1, node2, childdiffer) );
    361
    362 /* add constraints to nodes */
    363 SCIP_CALL( SCIPaddConsNode(scip, childsame, conssame, NULL) );
    364 SCIP_CALL( SCIPaddConsNode(scip, childdiffer, consdiffer, NULL) );
    365
    366 /* release constraints */
    367 SCIP_CALL( SCIPreleaseCons(scip, &conssame) );
    368 SCIP_CALL( SCIPreleaseCons(scip, &consdiffer) );
    369
    370 *result = SCIP_BRANCHED;
    371
    372 return SCIP_OKAY;
    373 }
    374 }
    375 }
    376
    378 *result = SCIP_BRANCHED;
    379
    380 return SCIP_OKAY;
    381}
    382
    383
    384/** copy method for branchrule plugins (called when SCIP copies plugins) */
    385static
    386SCIP_DECL_BRANCHCOPY(branchCopyColoring)
    387{ /*lint --e{715}*/
    388 assert(scip != NULL);
    389 assert(branchrule != NULL);
    390 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
    391
    392 return SCIP_OKAY;
    393}
    394
    395
    396/** destructor of branching rule to free user data (called when SCIP is exiting) */
    397static
    398SCIP_DECL_BRANCHFREE(branchFreeColoring)
    399{
    400 SCIP_BRANCHRULEDATA* branchruledata;
    401
    402 /* free branching rule data */
    403 branchruledata = SCIPbranchruleGetData(branchrule);
    404 SCIPfreeBlockMemory(scip, &branchruledata);
    405 SCIPbranchruleSetData(branchrule, NULL);
    406
    407 return SCIP_OKAY;
    408}/*lint !e715*/
    409
    410
    411
    412/*
    413 * branching rule specific interface methods
    414 */
    415
    416/** creates the coloring branching rule and includes it in SCIP */
    418 SCIP* scip /**< SCIP data structure */
    419 )
    420{
    421 SCIP_BRANCHRULEDATA* branchruledata;
    422 SCIP_BRANCHRULE* branchrule;
    423
    424 assert(scip != NULL);
    425
    426 /* create branching rule data */
    427 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata) );
    428
    429 branchrule = NULL;
    430 /* include branching rule */
    432 BRANCHRULE_MAXBOUNDDIST, branchruledata) );
    433 assert(branchrule != NULL);
    434
    435 SCIP_CALL( SCIPsetBranchruleExecLp(scip, branchrule, branchExeclpColoring) );
    436 SCIP_CALL( SCIPsetBranchruleExecPs(scip, branchrule, branchExecpsColoring) );
    437 SCIP_CALL( SCIPsetBranchruleCopy(scip, branchrule, branchCopyColoring) );
    438 SCIP_CALL( SCIPsetBranchruleFree(scip, branchrule, branchFreeColoring) );
    439
    440 SCIP_CALL( SCIPaddCharParam(scip, "branching/" BRANCHRULE_NAME "/strategy",
    441 "variable selection strategy, 'l'east fractional or 'm'ost fractional variable",
    442 &branchruledata->strategy, FALSE, BRANCHRULE_STRATEGY_DEFAULT, BRANCHRULE_STRATEGIES, NULL, NULL) );
    443
    444 return SCIP_OKAY;
    445}
    #define BRANCHRULE_DESC
    #define BRANCHRULE_PRIORITY
    static SCIP_DECL_BRANCHEXECLP(branchExeclpColoring)
    static SCIP_DECL_BRANCHFREE(branchFreeColoring)
    #define BRANCHRULE_NAME
    static SCIP_DECL_BRANCHCOPY(branchCopyColoring)
    SCIP_RETCODE SCIPincludeBranchruleColoring(SCIP *scip)
    static SCIP_DECL_BRANCHEXECPS(branchExecpsColoring)
    #define BRANCHRULE_STRATEGY_DEFAULT
    #define BRANCHRULE_STRATEGIES
    #define BRANCHRULE_MAXDEPTH
    #define BRANCHRULE_MAXBOUNDDIST
    default branching rule for the vertex coloring problem
    TCLIQUE_GRAPH * COLORconsGetCurrentGraph(SCIP *scip)
    SCIP_RETCODE COLORcreateConsStoreGraph(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONS *fatherconstraint, COLOR_CONSTYPE type, int node1, int node2, SCIP_NODE *stickingnode)
    int COLORconsGetRepresentative(SCIP *scip, int node)
    SCIP_CONS * COLORconsGetActiveStoreGraphCons(SCIP *scip)
    @ COLOR_CONSTYPE_DIFFER
    @ COLOR_CONSTYPE_SAME
    #define NULL
    Definition: def.h:248
    #define MIN(x, y)
    Definition: def.h:224
    #define SCIP_Real
    Definition: def.h:156
    #define FALSE
    Definition: def.h:94
    #define SCIPABORT()
    Definition: def.h:327
    #define SCIP_CALL(x)
    Definition: def.h:355
    int SCIPgetNVarsSetppc(SCIP *scip, SCIP_CONS *cons)
    Definition: cons_setppc.c:9596
    SCIP_VAR ** SCIPgetVarsSetppc(SCIP *scip, SCIP_CONS *cons)
    Definition: cons_setppc.c:9619
    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
    SCIP_RETCODE SCIPaddCharParam(SCIP *scip, const char *name, const char *desc, char *valueptr, SCIP_Bool isadvanced, char defaultvalue, const char *allowedvalues, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:167
    SCIP_RETCODE SCIPsetBranchruleExecLp(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHEXECLP((*branchexeclp)))
    Definition: scip_branch.c:256
    SCIP_RETCODE SCIPsetBranchruleCopy(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHCOPY((*branchcopy)))
    Definition: scip_branch.c:160
    SCIP_RETCODE SCIPincludeBranchruleBasic(SCIP *scip, SCIP_BRANCHRULE **branchruleptr, const char *name, const char *desc, int priority, int maxdepth, SCIP_Real maxbounddist, SCIP_BRANCHRULEDATA *branchruledata)
    Definition: scip_branch.c:123
    SCIP_RETCODE SCIPsetBranchruleExecPs(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHEXECPS((*branchexecps)))
    Definition: scip_branch.c:288
    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
    void SCIPbranchruleSetData(SCIP_BRANCHRULE *branchrule, SCIP_BRANCHRULEDATA *branchruledata)
    Definition: branch.c:1896
    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_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
    Definition: cons.c:8486
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24268
    SCIP_VARDATA * SCIPvarGetData(SCIP_VAR *var)
    Definition: var.c:23287
    void COLORprobGetStableSet(SCIP *scip, int setindex, int **stableset, int *nelements)
    int COLORprobGetNNodes(SCIP *scip)
    SCIP_CONS * COLORprobGetConstraint(SCIP *scip, int node)
    struct SCIP_BranchruleData SCIP_BRANCHRULEDATA
    Definition: type_branch.h:57
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_BRANCHED
    Definition: type_result.h:54
    @ SCIP_PARAMETERWRONGVAL
    Definition: type_retcode.h:57
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63