SCIP

    Solving Constraint Integer Programs

    nodesel_bfs.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 nodesel_bfs.c
    26 * @ingroup DEFPLUGINS_NODESEL
    27 * @brief node selector for best first search
    28 * @author Tobias Achterberg
    29 */
    30
    31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    32
    33#include "scip/nodesel_bfs.h"
    34#include "scip/pub_message.h"
    35#include "scip/pub_nodesel.h"
    36#include "scip/pub_tree.h"
    37#include "scip/scip_mem.h"
    38#include "scip/scip_message.h"
    39#include "scip/scip_nodesel.h"
    40#include "scip/scip_numerics.h"
    41#include "scip/scip_param.h"
    43#include "scip/scip_tree.h"
    44#include "scip/type_misc.h"
    45
    46
    47#define NODESEL_NAME "bfs"
    48#define NODESEL_DESC "best first search"
    49#define NODESEL_STDPRIORITY 100000
    50#define NODESEL_MEMSAVEPRIORITY 0
    51
    52
    53/*
    54 * Default parameter settings
    55 */
    56
    57#define MINPLUNGEDEPTH -1 /**< minimal plunging depth, before new best node may be selected (-1 for dynamic setting) */
    58#define MAXPLUNGEDEPTH -1 /**< maximal plunging depth, before new best node is forced to be selected (-1 for dynamic setting) */
    59#define MAXPLUNGEQUOT 0.25 /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
    60 * where plunging is performed */
    61
    62
    63/** node selector data for best first search node selection */
    64struct SCIP_NodeselData
    65{
    66 SCIP_Real maxplungequot; /**< maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound)
    67 * where plunging is performed */
    68 int minplungedepth; /**< minimal plunging depth, before new best node may be selected
    69 * (-1 for dynamic setting) */
    70 int maxplungedepth; /**< maximal plunging depth, before new best node is forced to be selected
    71 * (-1 for dynamic setting) */
    72};
    73
    74
    75/*
    76 * Callback methods
    77 */
    78
    79/** copy method for node selector plugins (called when SCIP copies plugins) */
    80static
    81SCIP_DECL_NODESELCOPY(nodeselCopyBfs)
    82{ /*lint --e{715}*/
    83 assert(scip != NULL);
    84 assert(nodesel != NULL);
    85
    87
    88 /* call inclusion method of node selector */
    90
    91 return SCIP_OKAY;
    92}
    93
    94/** destructor of node selector to free user data (called when SCIP is exiting) */
    95/**! [SnippetNodeselFreeBfs] */
    96static
    97SCIP_DECL_NODESELFREE(nodeselFreeBfs)
    98{ /*lint --e{715}*/
    99 SCIP_NODESELDATA* nodeseldata;
    100
    101 assert(nodesel != NULL);
    102 assert(scip != NULL);
    103
    105
    106 /* free user data of node selector */
    107 nodeseldata = SCIPnodeselGetData(nodesel);
    108 assert(nodeseldata != NULL);
    109 SCIPfreeBlockMemory(scip, &nodeseldata);
    110 SCIPnodeselSetData(nodesel, nodeseldata);
    111
    112 return SCIP_OKAY;
    113}
    114/**! [SnippetNodeselFreeBfs] */
    115
    116
    117/** node selection method of node selector */
    118static
    119SCIP_DECL_NODESELSELECT(nodeselSelectBfs)
    120{ /*lint --e{715}*/
    121 SCIP_NODESELDATA* nodeseldata;
    122 int minplungedepth;
    123 int maxplungedepth;
    124 int plungedepth;
    125 SCIP_Real maxplungequot;
    126
    127 assert(nodesel != NULL);
    128 assert(scip != NULL);
    129 assert(selnode != NULL);
    130
    132
    133 *selnode = NULL;
    134
    135 /* get node selector user data */
    136 nodeseldata = SCIPnodeselGetData(nodesel);
    137 assert(nodeseldata != NULL);
    138
    139 /* calculate minimal and maximal plunging depth */
    140 minplungedepth = nodeseldata->minplungedepth;
    141 maxplungedepth = nodeseldata->maxplungedepth;
    142 maxplungequot = nodeseldata->maxplungequot;
    143 if( minplungedepth == -1 )
    144 {
    145 minplungedepth = SCIPgetMaxDepth(scip)/10;
    147 minplungedepth += 10;
    148 if( maxplungedepth >= 0 )
    149 minplungedepth = MIN(minplungedepth, maxplungedepth);
    150 }
    151 if( maxplungedepth == -1 )
    152 maxplungedepth = SCIPgetMaxDepth(scip)/2;
    153 maxplungedepth = MAX(maxplungedepth, minplungedepth);
    154
    155 /* check, if we exceeded the maximal plunging depth */
    156 plungedepth = SCIPgetPlungeDepth(scip);
    157 if( plungedepth >= maxplungedepth )
    158 {
    159 /* we don't want to plunge again: select best node from the tree */
    160 SCIPdebugMsg(scip, "plungedepth: [%d,%d], cur: %d -> abort plunging\n", minplungedepth, maxplungedepth, plungedepth);
    161 *selnode = SCIPgetBestNode(scip);
    162 SCIPdebugMsg(scip, " -> best node : lower=%g\n",
    163 *selnode != NULL ? SCIPnodeGetLowerbound(*selnode) : SCIPinfinity(scip));
    164 }
    165 else
    166 {
    167 SCIP_NODE* node;
    168 SCIP_Real maxbound;
    169
    170 /* check, if plunging is forced at the current depth */
    171 if( plungedepth < minplungedepth )
    172 {
    173 maxbound = SCIPinfinity(scip);
    174 SCIPdebugMsg(scip, "plungedepth: [%d,%d], cur: %d => maxbound: infinity\n",
    175 minplungedepth, maxplungedepth, plungedepth);
    176 }
    177 else
    178 {
    179 SCIP_Real lowerbound;
    180 SCIP_Real cutoffbound;
    181 /* get global lower and cutoff bound */
    182 lowerbound = SCIPgetLowerbound(scip);
    183 cutoffbound = SCIPgetCutoffbound(scip);
    184
    185 /* if we didn't find a solution yet, the cutoff bound is usually very bad:
    186 * use only 20% of the gap as cutoff bound
    187 */
    188 if( SCIPgetNSolsFound(scip) == 0 )
    189 cutoffbound = lowerbound + 0.2 * (cutoffbound - lowerbound);
    190 /* calculate maximal plunging bound */
    191 maxbound = lowerbound + maxplungequot * (cutoffbound - lowerbound);
    192
    193 SCIPdebugMsg(scip, "plungedepth: [%d,%d], cur: %d, bounds: [%g,%g], maxbound: %g\n",
    194 minplungedepth, maxplungedepth, plungedepth, lowerbound, cutoffbound, maxbound);
    195 }
    196
    197 /* we want to plunge again: prefer children over siblings, and siblings over leaves,
    198 * but only select a child or sibling, if its dual bound is small enough;
    199 * prefer using nodes with higher node selection priority assigned by the branching rule
    200 */
    201 node = SCIPgetPrioChild(scip);
    202 if( node != NULL && SCIPnodeGetLowerbound(node) < maxbound )
    203 {
    204 *selnode = node;
    205 SCIPdebugMsg(scip, " -> selected prio child: lower=%g\n", SCIPnodeGetLowerbound(*selnode));
    206 }
    207 else
    208 {
    209 node = SCIPgetBestChild(scip);
    210 if( node != NULL && SCIPnodeGetLowerbound(node) < maxbound )
    211 {
    212 *selnode = node;
    213 SCIPdebugMsg(scip, " -> selected best child: lower=%g\n", SCIPnodeGetLowerbound(*selnode));
    214 }
    215 else
    216 {
    217 node = SCIPgetPrioSibling(scip);
    218 if( node != NULL && SCIPnodeGetLowerbound(node) < maxbound )
    219 {
    220 *selnode = node;
    221 SCIPdebugMsg(scip, " -> selected prio sibling: lower=%g\n", SCIPnodeGetLowerbound(*selnode));
    222 }
    223 else
    224 {
    225 node = SCIPgetBestSibling(scip);
    226 if( node != NULL && SCIPnodeGetLowerbound(node) < maxbound )
    227 {
    228 *selnode = node;
    229 SCIPdebugMsg(scip, " -> selected best sibling: lower=%g\n", SCIPnodeGetLowerbound(*selnode));
    230 }
    231 else
    232 {
    233 *selnode = SCIPgetBestNode(scip);
    234 SCIPdebugMsg(scip, " -> selected best leaf: lower=%g\n",
    235 *selnode != NULL ? SCIPnodeGetLowerbound(*selnode) : SCIPinfinity(scip));
    236 }
    237 }
    238 }
    239 }
    240 }
    241
    242 return SCIP_OKAY;
    243}
    244
    245
    246/** node comparison method of node selector */
    247static
    249{ /*lint --e{715}*/
    250 SCIP_Real lowerbound1;
    251 SCIP_Real lowerbound2;
    252
    253 assert(nodesel != NULL);
    254 assert(scip != NULL);
    255
    256 lowerbound1 = SCIPnodeGetLowerbound(node1);
    257 lowerbound2 = SCIPnodeGetLowerbound(node2);
    258 if( SCIPisLT(scip, lowerbound1, lowerbound2) )
    259 return -1;
    260 else if( SCIPisGT(scip, lowerbound1, lowerbound2) )
    261 return +1;
    262 else
    263 {
    264 SCIP_Real estimate1;
    265 SCIP_Real estimate2;
    266
    267 estimate1 = SCIPnodeGetEstimate(node1);
    268 estimate2 = SCIPnodeGetEstimate(node2);
    269 if( (SCIPisInfinity(scip, estimate1) && SCIPisInfinity(scip, estimate2)) ||
    270 (SCIPisInfinity(scip, -estimate1) && SCIPisInfinity(scip, -estimate2)) ||
    271 SCIPisEQ(scip, estimate1, estimate2) )
    272 {
    273 SCIP_NODETYPE nodetype1;
    274 SCIP_NODETYPE nodetype2;
    275
    276 nodetype1 = SCIPnodeGetType(node1);
    277 nodetype2 = SCIPnodeGetType(node2);
    278 if( nodetype1 == SCIP_NODETYPE_CHILD && nodetype2 != SCIP_NODETYPE_CHILD )
    279 return -1;
    280 else if( nodetype1 != SCIP_NODETYPE_CHILD && nodetype2 == SCIP_NODETYPE_CHILD )
    281 return +1;
    282 else if( nodetype1 == SCIP_NODETYPE_SIBLING && nodetype2 != SCIP_NODETYPE_SIBLING )
    283 return -1;
    284 else if( nodetype1 != SCIP_NODETYPE_SIBLING && nodetype2 == SCIP_NODETYPE_SIBLING )
    285 return +1;
    286 else
    287 {
    288 int depth1;
    289 int depth2;
    290
    291 depth1 = SCIPnodeGetDepth(node1);
    292 depth2 = SCIPnodeGetDepth(node2);
    293 if( depth1 < depth2 )
    294 return -1;
    295 else if( depth1 > depth2 )
    296 return +1;
    297 else
    298 return 0;
    299 }
    300 }
    301
    302 if( SCIPisLT(scip, estimate1, estimate2) )
    303 return -1;
    304
    305 assert(SCIPisGT(scip, estimate1, estimate2));
    306 return +1;
    307 }
    308}
    309
    310
    311/*
    312 * bfs specific interface methods
    313 */
    314
    315/** creates the node selector for best first search and includes it in SCIP */
    317 SCIP* scip /**< SCIP data structure */
    318 )
    319{
    320 SCIP_NODESELDATA* nodeseldata;
    321 SCIP_NODESEL* nodesel;
    322
    323 /* allocate and initialize node selector data; this has to be freed in the destructor */
    324 SCIP_CALL( SCIPallocBlockMemory(scip, &nodeseldata) );
    325
    326 /* include node selector */
    328 nodeselSelectBfs, nodeselCompBfs, nodeseldata) );
    329
    330 assert(nodesel != NULL);
    331
    332 SCIP_CALL( SCIPsetNodeselCopy(scip, nodesel, nodeselCopyBfs) );
    333 SCIP_CALL( SCIPsetNodeselFree(scip, nodesel, nodeselFreeBfs) );
    334
    335 /* add node selector parameters */
    337 "nodeselection/bfs/minplungedepth",
    338 "minimal plunging depth, before new best node may be selected (-1 for dynamic setting)",
    339 &nodeseldata->minplungedepth, TRUE, MINPLUNGEDEPTH, -1, INT_MAX, NULL, NULL) );
    341 "nodeselection/bfs/maxplungedepth",
    342 "maximal plunging depth, before new best node is forced to be selected (-1 for dynamic setting)",
    343 &nodeseldata->maxplungedepth, TRUE, MAXPLUNGEDEPTH, -1, INT_MAX, NULL, NULL) );
    345 "nodeselection/bfs/maxplungequot",
    346 "maximal quotient (curlowerbound - lowerbound)/(cutoffbound - lowerbound) where plunging is performed",
    347 &nodeseldata->maxplungequot, TRUE, MAXPLUNGEQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    348
    349 return SCIP_OKAY;
    350}
    351
    #define NULL
    Definition: def.h:257
    #define SCIP_REAL_MAX
    Definition: def.h:167
    #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 MAX(x, y)
    Definition: def.h:229
    #define SCIP_CALL(x)
    Definition: def.h:364
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    SCIP_RETCODE SCIPincludeNodeselBfs(SCIP *scip)
    Definition: nodesel_bfs.c:316
    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 SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:139
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    SCIP_NODETYPE SCIPnodeGetType(SCIP_NODE *node)
    Definition: tree.c:8503
    SCIP_Real SCIPnodeGetLowerbound(SCIP_NODE *node)
    Definition: tree.c:8533
    SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
    Definition: tree.c:8553
    int SCIPnodeGetDepth(SCIP_NODE *node)
    Definition: tree.c:8523
    SCIP_RETCODE SCIPincludeNodeselBasic(SCIP *scip, SCIP_NODESEL **nodesel, const char *name, const char *desc, int stdpriority, int memsavepriority, SCIP_DECL_NODESELSELECT((*nodeselselect)), SCIP_DECL_NODESELCOMP((*nodeselcomp)), SCIP_NODESELDATA *nodeseldata)
    Definition: scip_nodesel.c:111
    void SCIPnodeselSetData(SCIP_NODESEL *nodesel, SCIP_NODESELDATA *nodeseldata)
    Definition: nodesel.c:1273
    SCIP_RETCODE SCIPsetNodeselFree(SCIP *scip, SCIP_NODESEL *nodesel, SCIP_DECL_NODESELFREE((*nodeselfree)))
    Definition: scip_nodesel.c:162
    SCIP_NODESELDATA * SCIPnodeselGetData(SCIP_NODESEL *nodesel)
    Definition: nodesel.c:1263
    SCIP_RETCODE SCIPsetNodeselCopy(SCIP *scip, SCIP_NODESEL *nodesel, SCIP_DECL_NODESELCOPY((*nodeselcopy)))
    Definition: scip_nodesel.c:146
    const char * SCIPnodeselGetName(SCIP_NODESEL *nodesel)
    Definition: nodesel.c:1195
    SCIP_Longint SCIPgetNSolsFound(SCIP *scip)
    int SCIPgetMaxDepth(SCIP *scip)
    SCIP_Longint SCIPgetNStrongbranchLPIterations(SCIP *scip)
    SCIP_Real SCIPgetLowerbound(SCIP *scip)
    SCIP_Longint SCIPgetNNodeLPIterations(SCIP *scip)
    SCIP_Real SCIPgetCutoffbound(SCIP *scip)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_NODE * SCIPgetBestSibling(SCIP *scip)
    Definition: scip_tree.c:336
    SCIP_NODE * SCIPgetBestChild(SCIP *scip)
    Definition: scip_tree.c:320
    SCIP_NODE * SCIPgetPrioSibling(SCIP *scip)
    Definition: scip_tree.c:304
    SCIP_NODE * SCIPgetBestNode(SCIP *scip)
    Definition: scip_tree.c:368
    int SCIPgetPlungeDepth(SCIP *scip)
    Definition: scip_tree.c:715
    SCIP_NODE * SCIPgetPrioChild(SCIP *scip)
    Definition: scip_tree.c:288
    static SCIP_DECL_NODESELFREE(nodeselFreeBfs)
    Definition: nodesel_bfs.c:97
    #define NODESEL_NAME
    Definition: nodesel_bfs.c:47
    #define MAXPLUNGEQUOT
    Definition: nodesel_bfs.c:59
    static SCIP_DECL_NODESELSELECT(nodeselSelectBfs)
    Definition: nodesel_bfs.c:119
    static SCIP_DECL_NODESELCOMP(nodeselCompBfs)
    Definition: nodesel_bfs.c:248
    #define NODESEL_MEMSAVEPRIORITY
    Definition: nodesel_bfs.c:50
    #define NODESEL_STDPRIORITY
    Definition: nodesel_bfs.c:49
    #define NODESEL_DESC
    Definition: nodesel_bfs.c:48
    #define MINPLUNGEDEPTH
    Definition: nodesel_bfs.c:57
    static SCIP_DECL_NODESELCOPY(nodeselCopyBfs)
    Definition: nodesel_bfs.c:81
    #define MAXPLUNGEDEPTH
    Definition: nodesel_bfs.c:58
    node selector for best first search
    public methods for message output
    public methods for node selectors
    public methods for branch and bound tree
    public methods for memory management
    public methods for message handling
    public methods for node selector plugins
    public methods for numerical tolerances
    public methods for SCIP parameter handling
    public methods for querying solving statistics
    public methods for the branch-and-bound tree
    type definitions for miscellaneous datastructures
    struct SCIP_NodeselData SCIP_NODESELDATA
    Definition: type_nodesel.h:52
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    enum SCIP_NodeType SCIP_NODETYPE
    Definition: type_tree.h:53
    @ SCIP_NODETYPE_CHILD
    Definition: type_tree.h:44
    @ SCIP_NODETYPE_SIBLING
    Definition: type_tree.h:43