SCIP

    Solving Constraint Integer Programs

    event_shadowtree.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 event_shadowtree.c
    26 * @ingroup DEFPLUGINS_EVENT
    27 * @brief event handler for maintaining the unmodified branch-and-bound tree
    28 * @author Jasper van Doornmalen
    29 *
    30 * It is possible that SCIP detects that variable bounds can be restricted globally further than formerly known.
    31 * In that case, it is decided to update the global bounds of these variables, and modify the history of the branching
    32 * decisions this way. This breaks methods that depend on the assumption that historic choices in the branch-and-bound
    33 * tree remain unmodified througout the search, e.g., dynamic symmetry handling constraints.
    34 *
    35 * This event handler registers decisions made by the branch-and-bound tree directly at the moment of branching, and
    36 * does not modify those at later stages of the solve.
    37 */
    38
    39/*--+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    40
    42#include "scip/debug.h"
    43#include "scip/pub_cons.h"
    44#include "scip/pub_message.h"
    45#include "scip/pub_var.h"
    46#include "scip/struct_var.h"
    47#include "scip/type_var.h"
    48#include "scip/scip.h"
    49#include "scip/scip_branch.h"
    50#include "scip/scip_conflict.h"
    51#include "scip/scip_cons.h"
    52#include "scip/scip_copy.h"
    53#include "scip/scip_cut.h"
    54#include "scip/scip_general.h"
    55#include "scip/scip_lp.h"
    56#include "scip/scip_mem.h"
    57#include "scip/scip_message.h"
    58#include "scip/scip_numerics.h"
    59#include "scip/scip_param.h"
    60#include "scip/scip_prob.h"
    61#include "scip/scip_probing.h"
    62#include "scip/scip_sol.h"
    63#include "scip/scip_var.h"
    64#include "scip/struct_scip.h"
    65#include "scip/struct_mem.h"
    66#include "scip/struct_tree.h"
    67#include "scip/symmetry.h"
    68#include <ctype.h>
    69#include <memory.h>
    71
    72#define EVENTHDLR_NAME "event_shadowtree"
    73#define EVENTHDLR_DESC "event handler for maintaining the unmodified branch-and-bound tree"
    74#define NODEMAP_MAX_INITIAL_SIZE 10000
    75#define NODEMAP_MAX_INITIAL_SIZE_2LOG 14
    76
    77
    78/*
    79 * Data structures
    80 */
    81
    82
    83/** wrapper for shadow tree eventhandler data */
    84struct SCIP_EventhdlrData
    85{
    86#ifndef NDEBUG
    87 SCIP* scip; /**< SCIP data structure */
    88#endif
    89 SCIP_SHADOWTREE* shadowtree; /**< Shadow tree structure */
    90 SCIP_CLOCK* clock; /**< clock for measuring time in shadow tree events */
    91 SCIP_Bool active; /**< whether a shadow tree should be maintained */
    92};
    93
    94
    95/*
    96 * Local methods
    97 */
    98
    99/** hash key for SCIP_SHADOWNODE */
    100static
    101SCIP_DECL_HASHGETKEY(hashGetKeyShadowNode)
    102{ /*lint --e{715}*/
    103 return elem;
    104}
    105
    106/** returns TRUE iff the indices of both node numbers are equal */
    107static
    108SCIP_DECL_HASHKEYEQ(hashKeyEqShadowNode)
    109{ /*lint --e{715}*/
    110 return ((SCIP_SHADOWNODE*) key1)->nodeid == ((SCIP_SHADOWNODE*) key2)->nodeid;
    111}
    112
    113/** returns the hash value of the key */
    114static
    115SCIP_DECL_HASHKEYVAL(hashKeyValShadowNode)
    116{ /*lint --e{715}*/
    117 return (unsigned int) ((SCIP_SHADOWNODE*) key)->nodeid;
    118}
    119
    120
    121/** get the time spent in the shadow tree eventhdlr */
    123 SCIP* scip, /**< SCIP data structure */
    124 SCIP_EVENTHDLR* eventhdlr /**< event handler */
    125 )
    126{
    127 SCIP_EVENTHDLRDATA* eventhdlrdata;
    128
    129 eventhdlrdata = (SCIP_EVENTHDLRDATA*) SCIPeventhdlrGetData(eventhdlr);
    130 assert( eventhdlrdata != NULL );
    131 assert( eventhdlrdata->scip != NULL );
    132 assert( eventhdlrdata->scip == scip );
    133 assert( eventhdlrdata->clock != NULL );
    134
    135 return SCIPgetClockTime(scip, eventhdlrdata->clock);
    136}
    137
    138
    139/** given a node number, returns the node in the shadow tree, or NULL if it doesn't exist */
    141 SCIP_SHADOWTREE* shadowtree, /**< pointer to the shadow tree */
    142 SCIP_Longint nodeid /**< index of the node, equivalent to the standard branch and bound tree */
    143 )
    144{
    145 SCIP_SHADOWNODE tmpnode;
    146
    147 assert( shadowtree != NULL );
    148 assert( nodeid >= 0 );
    149
    150 tmpnode.nodeid = nodeid;
    151
    152 /* the following line of code returns NULL if it cannot find the entry in the hashtable */
    153 return (SCIP_SHADOWNODE*) SCIPhashtableRetrieve(shadowtree->nodemap, (void*) &tmpnode);
    154}
    155
    156/** given a node, returns the node in the shadowtree, or NULL if it doesn't exist */
    158 SCIP_SHADOWTREE* shadowtree, /**< pointer to the shadow tree */
    159 SCIP_NODE* node /**< node from the actual branch-and-bound tree */
    160 )
    161{
    162 assert( shadowtree != NULL );
    163 assert( node != NULL );
    164
    166}
    167
    168/*
    169 * Callback methods of event handler
    170 */
    171
    172/** event handler for branching event */
    173static
    174SCIP_DECL_EVENTEXEC(eventExecNodeBranched)
    175{
    176 SCIP_EVENTHDLRDATA* eventhdlrdata;
    177 SCIP_SHADOWTREE* shadowtree;
    178 SCIP_SHADOWNODE* eventshadownode;
    179 SCIP_SHADOWNODE* childshadownode;
    180 SCIP_NODE* eventnode;
    181 SCIP_NODE** children;
    182 SCIP_NODE* childnode;
    183 SCIP_DOMCHG* domchg;
    184 SCIP_BOUNDCHG* boundchg;
    185 SCIP_SHADOWBOUNDUPDATE* branchingdecisions;
    187 int maxnbranchingdecisions;
    188 int nbranchingdecisions;
    189 int nboundchgs;
    190 int nchildren;
    191 int i;
    192 int c;
    193
    194 assert( scip != NULL );
    195 assert( eventhdlr != NULL );
    196 assert( event != NULL );
    198
    199 /* no branching during probing */
    200 assert( !SCIPinProbing(scip) );
    201
    202 eventnode = SCIPeventGetNode(event);
    203 assert( SCIPgetFocusNode(scip) == eventnode );
    204 assert( SCIPnodeGetType(eventnode) == SCIP_NODETYPE_FOCUSNODE );
    205
    206 eventhdlrdata = (SCIP_EVENTHDLRDATA*) SCIPeventhdlrGetData(eventhdlr);
    207 assert( eventhdlrdata != NULL );
    208 assert( scip == eventhdlrdata->scip );
    209
    210 shadowtree = eventhdlrdata->shadowtree;
    211 assert( shadowtree != NULL );
    212
    213 eventshadownode = SCIPshadowTreeGetShadowNode(shadowtree, eventnode);
    214
    215 /* only add children to the shadowtree if eventnode is in the shadowtree */
    216 if ( eventshadownode == NULL )
    217 return SCIP_OKAY;
    218
    219 assert( eventshadownode->nchildren == 0 );
    220 assert( eventshadownode->children == NULL );
    221
    222 SCIP_CALL( SCIPgetChildren(scip, &children, &nchildren) );
    223
    224 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &eventshadownode->children, nchildren) );
    225 eventshadownode->nchildren = nchildren;
    226
    227 maxnbranchingdecisions = 1; /* good guess that there's one branching variable, because that's likely the number */
    228 SCIP_CALL( SCIPallocBufferArray(scip, &branchingdecisions, maxnbranchingdecisions) );
    229
    230 /* get all variables branched upon and check all branches */
    231 for (c = 0; c < nchildren; ++c)
    232 {
    233 nbranchingdecisions = 0;
    234
    235 childnode = children[c];
    236 domchg = SCIPnodeGetDomchg(childnode);
    237
    238 /* loop through all bound changes */
    239 nboundchgs = SCIPdomchgGetNBoundchgs(domchg);
    240 for (i = 0; i < nboundchgs; ++i)
    241 {
    242 /* get bound change info */
    243 boundchg = SCIPdomchgGetBoundchg(domchg, i);
    244 assert( boundchg != NULL );
    245
    246 /* branching decisions have to be in the beginning of the bound change array */
    248 break;
    249
    250 if ( nbranchingdecisions >= maxnbranchingdecisions )
    251 {
    252 assert( nbranchingdecisions == maxnbranchingdecisions );
    253 assert( maxnbranchingdecisions > 0 );
    254 maxnbranchingdecisions = SCIPcalcMemGrowSize(scip, maxnbranchingdecisions + 1);
    255 SCIP_CALL( SCIPreallocBufferArray(scip, &branchingdecisions, maxnbranchingdecisions) );
    256 }
    257 assert( nbranchingdecisions < maxnbranchingdecisions );
    258
    259 /* get corresponding branching step */
    260 update = &branchingdecisions[nbranchingdecisions++];
    261 update->var = SCIPboundchgGetVar(boundchg);
    262 update->boundchgtype = SCIPboundchgGetBoundtype(boundchg);
    263 update->newbound = SCIPboundchgGetNewbound(boundchg);
    264 }
    265
    266 /* create the child in the shadow tree */
    267 SCIP_CALL( SCIPallocBlockMemory(scip, &childshadownode) );
    268 eventshadownode->children[c] = childshadownode;
    269
    270 childshadownode->nodeid = SCIPnodeGetNumber(childnode);
    271 childshadownode->parent = eventshadownode;
    272
    273 /* children are only set after this node is focused and branched on */
    274 childshadownode->children = NULL;
    275 childshadownode->nchildren = 0;
    276
    277 if ( nbranchingdecisions <= 0 )
    278 childshadownode->branchingdecisions = NULL;
    279 else
    280 {
    281 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &childshadownode->branchingdecisions, nbranchingdecisions) );
    282 for (i = 0; i < nbranchingdecisions; ++i)
    283 {
    284 /* this copies the whole struct */
    285 childshadownode->branchingdecisions[i] = branchingdecisions[i];
    286 }
    287 }
    288 childshadownode->nbranchingdecisions = nbranchingdecisions;
    289
    290 /* propagations are only set after this node is focused and branched on */
    291 childshadownode->propagations = NULL;
    292 childshadownode->npropagations = 0;
    293
    294 /* add childshadownode to the nodemap as well
    295 *
    296 * The hashtable only checks by the 'nodeid' field, so we just check if there's none with this nodeid.
    297 */
    298 assert( !SCIPhashtableExists(shadowtree->nodemap, (void*) childshadownode));
    299 SCIP_CALL( SCIPhashtableInsert(shadowtree->nodemap, childshadownode) );
    300 }
    301 SCIPfreeBufferArray(scip, &branchingdecisions);
    302
    303 /* also store the propagations in the eventnode (the node that got solved by branching) */
    304 domchg = SCIPnodeGetDomchg(eventnode);
    305
    306 /* loop through all bound changes in the focus node */
    307 nboundchgs = SCIPdomchgGetNBoundchgs(domchg);
    308 if ( nboundchgs <= 0 )
    309 {
    310 assert( nboundchgs == 0 );
    311
    312 /* this is set to NULL at initialization of this shadownode, already */
    313 assert( eventshadownode->npropagations == 0 );
    314 assert( eventshadownode->branchingdecisions == NULL );
    315 }
    316 else
    317 {
    318 /* just include everything, even the branching decisions! */
    319 eventshadownode->npropagations = nboundchgs;
    320 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &eventshadownode->propagations, nboundchgs) );
    321 for (i = 0; i < nboundchgs; ++i)
    322 {
    323 boundchg = SCIPdomchgGetBoundchg(domchg, i);
    324 assert( boundchg != NULL );
    325 update = &(eventshadownode->propagations[i]);
    326 update->var = SCIPboundchgGetVar(boundchg);
    327 update->boundchgtype = SCIPboundchgGetBoundtype(boundchg);
    328 update->newbound = SCIPboundchgGetNewbound(boundchg);
    329 }
    330 }
    331
    332 return SCIP_OKAY;
    333} /*lint !e715*/
    334
    335
    336/** event handler for node deletion event */
    337static
    338SCIP_DECL_EVENTEXEC(eventExecNodeDeleted)
    339{ /*lint !e396*/
    340 SCIP_EVENTHDLRDATA* eventhdlrdata;
    341 SCIP_SHADOWTREE* shadowtree;
    342 SCIP_NODE* deletednode;
    343 SCIP_SHADOWNODE* deletedshadownode;
    344 int c;
    345 SCIP_SHADOWNODE* childshadownode;
    346
    347 assert( scip != NULL );
    348 assert( eventhdlr != NULL );
    349 assert( event != NULL );
    351
    352 deletednode = SCIPeventGetNode(event);
    353 assert( deletednode != NULL );
    354
    355 /* probing nodes are not stored */
    356 if( SCIPnodeGetType(deletednode) == SCIP_NODETYPE_PROBINGNODE )
    357 return SCIP_OKAY;
    358
    359 eventhdlrdata = (SCIP_EVENTHDLRDATA*) SCIPeventhdlrGetData(eventhdlr);
    360 assert( eventhdlrdata != NULL );
    361 assert( scip == eventhdlrdata->scip );
    362
    363 shadowtree = eventhdlrdata->shadowtree;
    364 assert( shadowtree != NULL );
    365
    366 deletedshadownode = SCIPshadowTreeGetShadowNode(shadowtree, deletednode);
    367
    368 /* no need to delete if not included in the shadowtree */
    369 if ( deletedshadownode == NULL )
    370 return SCIP_OKAY;
    371 assert( deletedshadownode->nodeid == SCIPnodeGetNumber(deletednode) );
    372
    373 /* It is possible that deletedshadownode has a non-deleted sibling.
    374 * If the branching variable of this sibling differs from deletedshadownode's,
    375 * then in the variable branching order also the branching variables of deletedshadownode must be included,
    376 * e.g., see `shadowtreeFillNodeDepthBranchIndices` in symmetry_lexred.c.
    377 * As such, we may not delete deletedshadownode just yet. However, we can delete its children.
    378 * So, mark deletedshadownode as 'ready to delete' by freeing its children, and setting nchildren to -1.
    379 * SCIP always deletes leaf nodes only, so if `deletedshadownode` is removed,
    380 * its children in the shadowtree (if they exist) in the 'ready to delete' state. */
    381 assert( deletedshadownode->nchildren >= 0 );
    382 assert( (deletedshadownode->nchildren == 0) == (deletedshadownode->children == NULL) );
    383 for (c = 0; c < deletedshadownode->nchildren; ++c)
    384 {
    385 childshadownode = deletedshadownode->children[c];
    386
    387 /* remove from hashtable */
    388 SCIP_CALL( SCIPhashtableRemove(shadowtree->nodemap, (void*) childshadownode) );
    389
    390 /* clean childshadownode */
    391 assert( childshadownode->npropagations >= 0 );
    392 assert( (childshadownode->npropagations > 0) != (childshadownode->propagations == NULL) );
    393 SCIPfreeBlockMemoryArrayNull(scip, &childshadownode->propagations, childshadownode->npropagations);
    394
    395 assert( childshadownode->nbranchingdecisions >= 0 );
    396 assert( (childshadownode->nbranchingdecisions > 0) != (childshadownode->branchingdecisions == NULL) );
    397 SCIPfreeBlockMemoryArrayNull(scip, &childshadownode->branchingdecisions, childshadownode->nbranchingdecisions);
    398
    399 /* childshadownode must be in the 'ready to delete'-state */
    400 assert( childshadownode->nchildren < 0 );
    401
    402 SCIPfreeBlockMemory(scip, &childshadownode);
    403 }
    404
    405 assert( (deletedshadownode->nchildren > 0) != (deletedshadownode->children == NULL) );
    406 if ( deletedshadownode->nchildren > 0 )
    407 {
    408 SCIPfreeBlockMemoryArray(scip, &deletedshadownode->children, deletedshadownode->nchildren);
    409 }
    410
    411 /* mark deletedshadownode as 'ready to delete' */
    412 deletedshadownode->children = NULL;
    413 deletedshadownode->nchildren = -1;
    414
    415 return SCIP_OKAY;
    416} /*lint !e715*/
    417
    418
    419/** execution method for all events handled by this eventhandler */
    420static
    422{
    423 SCIP_EVENTHDLRDATA* eventhdlrdata;
    424
    426
    427 eventhdlrdata = (SCIP_EVENTHDLRDATA*) SCIPeventhdlrGetData(eventhdlr);
    428 assert( eventhdlrdata != NULL );
    429 assert( scip == eventhdlrdata->scip );
    430 assert( eventhdlrdata->clock != NULL );
    431
    432 SCIP_CALL( SCIPstartClock(scip, eventhdlrdata->clock) );
    433
    434 switch (SCIPeventGetType(event))
    435 {
    437 SCIP_CALL( eventExecNodeBranched(scip, eventhdlr, event, eventdata) );
    438 break;
    440 SCIP_CALL( eventExecNodeDeleted(scip, eventhdlr, event, eventdata) );
    441 break;
    442 default:
    443 SCIPerrorMessage("unrecognized eventtype in shadowtree event handler\n");
    444 return SCIP_ERROR;
    445 }
    446
    447 SCIP_CALL( SCIPstopClock(scip, eventhdlrdata->clock) );
    448
    449 return SCIP_OKAY;
    450}
    451
    452
    453/** frees shadow tree data structure */
    454static
    456 SCIP* scip, /**< SCIP data structure */
    457 SCIP_SHADOWTREE* shadowtree /**< pointer to shadow tree*/
    458 )
    459{
    460 int i;
    461 int nentries;
    462 SCIP_SHADOWNODE* shadownode;
    463
    464 assert( scip != NULL );
    465 assert( shadowtree != NULL );
    466 assert( shadowtree->nodemap != NULL );
    467
    468 nentries = SCIPhashtableGetNEntries(shadowtree->nodemap);
    469
    470 /* free all shadow tree nodes */
    471 for (i = 0; i < nentries; ++i)
    472 {
    473 shadownode = (SCIP_SHADOWNODE*) SCIPhashtableGetEntry(shadowtree->nodemap, i);
    474 if ( shadownode == NULL )
    475 continue;
    476
    477 assert( shadownode != NULL );
    478
    479 assert( shadownode->npropagations >= 0 );
    480 assert( (shadownode->npropagations > 0) != (shadownode->propagations == NULL) );
    482
    483 assert( shadownode->nbranchingdecisions >= 0 );
    484 assert( (shadownode->nbranchingdecisions > 0) != (shadownode->branchingdecisions == NULL) );
    486
    487 assert( shadownode->nchildren >= -1 );
    488 assert( (shadownode->nchildren > 0) != (shadownode->children == NULL) );
    489 SCIPfreeBlockMemoryArrayNull(scip, &shadownode->children, shadownode->nchildren);
    490
    491 SCIPfreeBlockMemory(scip, &shadownode);
    492 }
    493 SCIPhashtableFree(&(shadowtree->nodemap));
    494
    495 return SCIP_OKAY;
    496}
    497
    498
    499/** destructor of event handler to free shadow tree data (called when SCIP is exiting) */
    500static
    501SCIP_DECL_EVENTFREE(eventFreeShadowTree)
    502{
    503 SCIP_EVENTHDLRDATA* eventhdlrdata;
    504
    505 assert( scip != NULL );
    506 assert( eventhdlr != NULL );
    508
    509 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    510 assert( eventhdlrdata != NULL );
    511 assert( eventhdlrdata->scip == scip );
    512 assert( eventhdlrdata->clock != NULL );
    513
    514 SCIP_CALL( SCIPfreeClock(scip, &eventhdlrdata->clock) );
    515
    516 if ( eventhdlrdata->shadowtree != NULL )
    517 {
    518 SCIP_CALL( freeShadowTree(scip, eventhdlrdata->shadowtree) );
    519 SCIPfreeBlockMemory(scip, &eventhdlrdata->shadowtree);
    520 }
    521
    522 SCIPfreeBlockMemory(scip, &eventhdlrdata);
    523
    524 return SCIP_OKAY;
    525}
    526
    527
    528/** solving process initialization method of event handler (called when branch and bound process is about to begin) */
    529static
    530SCIP_DECL_EVENTINITSOL(eventInitsolShadowTree)
    531{
    532 int initialnodemapsize;
    533
    534 SCIP_EVENTHDLRDATA* eventhdlrdata;
    535 SCIP_SHADOWTREE* shadowtree;
    536 SCIP_SHADOWNODE* rootnode;
    537
    538 assert( scip != NULL );
    539 assert( eventhdlr != NULL );
    540
    541 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    542 assert( eventhdlrdata != NULL );
    543 assert( eventhdlrdata->scip == scip );
    544
    545 assert( eventhdlrdata->shadowtree == NULL );
    546 assert( SCIPisTransformed(scip) );
    547
    548 /* early termination */
    549 if ( !eventhdlrdata->active )
    550 return SCIP_OKAY;
    551
    552 SCIP_CALL( SCIPallocBlockMemory(scip, &eventhdlrdata->shadowtree) );
    553 shadowtree = eventhdlrdata->shadowtree;
    554
    555 /* prevent unnecessary reallocations by having a good initial guess for the tree size
    556 *
    557 * By default, we initialize NODEMAP_MAX_INITIAL_SIZE slots, unless reasonably fewer nodes suffice.
    558 * Knowing that a full enumeration tree on n binary variables has size 2^n, we base our guess on this number,
    559 * counting with the number of binary and integer variables in the problem.
    560 */
    563 MIN(NODEMAP_MAX_INITIAL_SIZE, 1 << (SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip))); /*lint !e666 !e701 !e747*/
    564 SCIP_CALL( SCIPhashtableCreate(&shadowtree->nodemap, scip->mem->probmem, initialnodemapsize,
    565 hashGetKeyShadowNode, hashKeyEqShadowNode, hashKeyValShadowNode, NULL) );
    566
    567 /* the root node is the only branch-and-bound tree node not created by branching, so add. */
    568 SCIP_CALL( SCIPallocBlockMemory(scip, &rootnode) );
    569 rootnode->nodeid = 1ll; /*lint !e620*/ /* root node has number 1 */
    570 rootnode->parent = NULL;
    571 rootnode->children = NULL;
    572 rootnode->nchildren = 0;
    573 rootnode->branchingdecisions = NULL;
    574 rootnode->nbranchingdecisions = 0;
    575 rootnode->propagations = NULL;
    576 rootnode->npropagations = 0;
    577
    578 /* add to the nodemap structure */
    579 SCIP_CALL( SCIPhashtableInsert(shadowtree->nodemap, rootnode) );
    580
    581 /* catch NODEBRANCHED and NODEDELETE events */
    583
    584 return SCIP_OKAY;
    585}
    586
    587
    588/** solving process deinitialization method of event handler (called before branch and bound process data is freed) */
    589static
    590SCIP_DECL_EVENTEXITSOL(eventExitsolShadowTree)
    591{
    592 SCIP_EVENTHDLRDATA* eventhdlrdata;
    593
    594 assert( scip != NULL );
    595 assert( eventhdlr != NULL );
    596
    597 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    598 assert( eventhdlrdata != NULL );
    599 assert( eventhdlrdata->scip == scip );
    600 assert( SCIPisTransformed(scip) );
    601
    602 /* early termination */
    603 if ( !eventhdlrdata->active )
    604 {
    605 assert( eventhdlrdata->shadowtree == NULL );
    606 return SCIP_OKAY;
    607 }
    608
    609 assert( eventhdlrdata->shadowtree != NULL );
    610
    611 SCIP_CALL( freeShadowTree(scip, eventhdlrdata->shadowtree) );
    612 SCIPfreeBlockMemory(scip, &eventhdlrdata->shadowtree);
    613 eventhdlrdata->shadowtree = NULL;
    614
    615 /* do not listen for NODEBRANCHED events */
    617
    618 return SCIP_OKAY;
    619}
    620
    621
    622/** gets the shadow tree */
    624 SCIP_EVENTHDLR* eventhdlr /**< event handler */
    625 )
    626{
    627 SCIP_EVENTHDLRDATA* eventhdlrdata;
    628 assert( eventhdlr != NULL );
    629
    631
    632 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    633 assert( eventhdlrdata != NULL );
    634
    635 return eventhdlrdata->shadowtree;
    636}
    637
    638
    639/** activates shadow tree eventhandler if it is not already activated (which keeps a copy of the tree) */
    641 SCIP* scip, /**< SCIP data structure */
    642 SCIP_EVENTHDLR* eventhdlr /**< event handler */
    643 )
    644{
    645 SCIP_EVENTHDLRDATA* eventhdlrdata;
    646 assert( eventhdlr != NULL );
    647
    649
    650 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    651 assert( eventhdlrdata != NULL );
    652 assert( eventhdlrdata->scip == scip );
    653 assert( eventhdlrdata->shadowtree == NULL );
    654
    655 /* active param may not be changed between (and including) the initsol and exitsol stages */
    656 SCIP_CALL( SCIPcheckStage(scip, "SCIPactivateShadowTree", TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE,
    657 FALSE, FALSE, FALSE, FALSE, FALSE) );
    658
    659 eventhdlrdata->active = TRUE;
    660
    661 return SCIP_OKAY;
    662}
    663
    664
    665/** creates event handler for event */
    667 SCIP* scip, /**< SCIP data structure */
    668 SCIP_EVENTHDLR** eventhdlrptr /**< pointer to store the event handler */
    669 )
    670{
    671 SCIP_EVENTHDLRDATA* eventhdlrdata;
    672 SCIP_EVENTHDLR* eventhdlr;
    673
    674 /* create event handler data */
    675 eventhdlrdata = NULL;
    676 SCIP_CALL( SCIPallocBlockMemory(scip, &eventhdlrdata) );
    677
    678#ifndef NDEBUG
    679 /* only needed for assertions, to check whether we're working with the correct SCIP. */
    680 eventhdlrdata->scip = scip;
    681#endif
    682
    683 /* shadow tree must be activated */
    684 eventhdlrdata->active = FALSE;
    685
    686 /* do not start with a shadow tree by default. Initialize at initsol, remove at exitsol. */
    687 eventhdlrdata->shadowtree = NULL;
    688 eventhdlr = NULL;
    689
    690 /* include event handler into SCIP */
    691 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExec, eventhdlrdata) );
    692 assert(eventhdlr != NULL);
    693 *eventhdlrptr = eventhdlr;
    694
    695 /* clock */
    696 SCIP_CALL( SCIPcreateClock(scip, &eventhdlrdata->clock) );
    697
    698 /* set non fundamental callbacks via setter functions */
    699
    700 /* frees the event handler */
    701 SCIP_CALL( SCIPsetEventhdlrFree(scip, eventhdlr, eventFreeShadowTree) );
    702
    703 /* initialize the shadowtree data structure, initialize by setting the root node */
    704 SCIP_CALL( SCIPsetEventhdlrInitsol(scip, eventhdlr, eventInitsolShadowTree) );
    705
    706 /* free the shadowtree data structure */
    707 SCIP_CALL( SCIPsetEventhdlrExitsol(scip, eventhdlr, eventExitsolShadowTree) );
    708
    709 return SCIP_OKAY;
    710}
    static GRAPHNODE ** active
    methods for debugging
    #define SCIPcheckStage(scip, method, init, problem, transforming, transformed, initpresolve, presolving, exitpresolve, presolved, initsolve, solving, solved, exitsolve, freetrans, freescip)
    Definition: debug.h:365
    #define NULL
    Definition: def.h:257
    #define SCIP_Longint
    Definition: def.h:150
    #define SCIP_Bool
    Definition: def.h:100
    #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 FALSE
    Definition: def.h:103
    #define SCIP_CALL(x)
    Definition: def.h:364
    SCIP_RETCODE SCIPactivateShadowTree(SCIP *scip, SCIP_EVENTHDLR *eventhdlr)
    SCIP_SHADOWTREE * SCIPgetShadowTree(SCIP_EVENTHDLR *eventhdlr)
    static SCIP_DECL_EVENTEXEC(eventExecNodeBranched)
    static SCIP_DECL_EVENTEXITSOL(eventExitsolShadowTree)
    static SCIP_DECL_HASHKEYEQ(hashKeyEqShadowNode)
    SCIP_SHADOWNODE * SCIPshadowTreeGetShadowNode(SCIP_SHADOWTREE *shadowtree, SCIP_NODE *node)
    SCIP_SHADOWNODE * SCIPshadowTreeGetShadowNodeFromNodeNumber(SCIP_SHADOWTREE *shadowtree, SCIP_Longint nodeid)
    static SCIP_DECL_HASHGETKEY(hashGetKeyShadowNode)
    SCIP_Real SCIPgetShadowTreeEventHandlerExecutionTime(SCIP *scip, SCIP_EVENTHDLR *eventhdlr)
    #define NODEMAP_MAX_INITIAL_SIZE_2LOG
    static SCIP_DECL_HASHKEYVAL(hashKeyValShadowNode)
    static SCIP_DECL_EVENTFREE(eventFreeShadowTree)
    #define NODEMAP_MAX_INITIAL_SIZE
    static SCIP_RETCODE freeShadowTree(SCIP *scip, SCIP_SHADOWTREE *shadowtree)
    static SCIP_DECL_EVENTINITSOL(eventInitsolShadowTree)
    #define EVENTHDLR_DESC
    SCIP_RETCODE SCIPincludeEventHdlrShadowTree(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr)
    #define EVENTHDLR_NAME
    SCIP_Bool SCIPisTransformed(SCIP *scip)
    Definition: scip_general.c:655
    SCIP_STAGE SCIPgetStage(SCIP *scip)
    Definition: scip_general.c:444
    int SCIPgetNIntVars(SCIP *scip)
    Definition: scip_prob.c:2340
    int SCIPgetNBinVars(SCIP *scip)
    Definition: scip_prob.c:2293
    void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
    Definition: misc.c:2348
    SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
    Definition: misc.c:2647
    int SCIPhashtableGetNEntries(SCIP_HASHTABLE *hashtable)
    Definition: misc.c:2765
    void * SCIPhashtableGetEntry(SCIP_HASHTABLE *hashtable, int entryidx)
    Definition: misc.c:2773
    SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
    Definition: misc.c:2298
    void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
    Definition: misc.c:2596
    SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
    Definition: misc.c:2665
    SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
    Definition: misc.c:2535
    SCIP_RETCODE SCIPsetEventhdlrInitsol(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_DECL_EVENTINITSOL((*eventinitsol)))
    Definition: scip_event.c:199
    SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
    Definition: scip_event.c:111
    const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
    Definition: event.c:396
    SCIP_EVENTHDLRDATA * SCIPeventhdlrGetData(SCIP_EVENTHDLR *eventhdlr)
    Definition: event.c:406
    SCIP_RETCODE SCIPsetEventhdlrExitsol(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_DECL_EVENTEXITSOL((*eventexitsol)))
    Definition: scip_event.c:213
    SCIP_RETCODE SCIPsetEventhdlrFree(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_DECL_EVENTFREE((*eventfree)))
    Definition: scip_event.c:157
    SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
    Definition: event.c:1194
    SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
    Definition: scip_event.c:293
    SCIP_NODE * SCIPeventGetNode(SCIP_EVENT *event)
    Definition: event.c:1530
    SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
    Definition: scip_event.c:333
    #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 SCIPreallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:128
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #define SCIPallocBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:93
    #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_NODETYPE SCIPnodeGetType(SCIP_NODE *node)
    Definition: tree.c:8503
    SCIP_DOMCHG * SCIPnodeGetDomchg(SCIP_NODE *node)
    Definition: tree.c:8618
    SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
    Definition: tree.c:8513
    SCIP_Bool SCIPinProbing(SCIP *scip)
    Definition: scip_probing.c:98
    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_RETCODE SCIPgetChildren(SCIP *scip, SCIP_NODE ***children, int *nchildren)
    Definition: scip_tree.c:164
    SCIP_NODE * SCIPgetFocusNode(SCIP *scip)
    Definition: scip_tree.c:72
    SCIP_BOUNDTYPE SCIPboundchgGetBoundtype(SCIP_BOUNDCHG *boundchg)
    Definition: var.c:23226
    SCIP_VAR * SCIPboundchgGetVar(SCIP_BOUNDCHG *boundchg)
    Definition: var.c:23206
    SCIP_BOUNDCHG * SCIPdomchgGetBoundchg(SCIP_DOMCHG *domchg, int pos)
    Definition: var.c:23254
    SCIP_BOUNDCHGTYPE SCIPboundchgGetBoundchgtype(SCIP_BOUNDCHG *boundchg)
    Definition: var.c:23216
    SCIP_Real SCIPboundchgGetNewbound(SCIP_BOUNDCHG *boundchg)
    Definition: var.c:23186
    int SCIPdomchgGetNBoundchgs(SCIP_DOMCHG *domchg)
    Definition: var.c:23246
    memory allocation routines
    public methods for managing constraints
    public methods for message output
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    public methods for problem variables
    SCIP callable library.
    public methods for branching rule plugins and branching
    public methods for conflict handler plugins and conflict analysis
    public methods for constraint handler plugins and constraints
    public methods for problem copies
    public methods for cuts and aggregation rows
    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 solutions
    public methods for SCIP variables
    SCIP_BOUNDTYPE boundchgtype
    SCIP_Longint nodeid
    struct SCIP_ShadowNode ** children
    SCIP_SHADOWBOUNDUPDATE * branchingdecisions
    SCIP_SHADOWBOUNDUPDATE * propagations
    struct SCIP_ShadowNode * parent
    SCIP_HASHTABLE * nodemap
    datastructures for block memory pools and memory buffers
    SCIP main data structure.
    data structures for branch and bound tree
    datastructures for problem variables
    methods for handling symmetries
    struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
    Definition: type_event.h:160
    #define SCIP_EVENTTYPE_NODEBRANCHED
    Definition: type_event.h:96
    #define SCIP_EVENTTYPE_NODEDELETE
    Definition: type_event.h:97
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    @ SCIP_ERROR
    Definition: type_retcode.h:43
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    @ SCIP_STAGE_SOLVING
    Definition: type_set.h:53
    @ SCIP_NODETYPE_PROBINGNODE
    Definition: type_tree.h:42
    @ SCIP_NODETYPE_FOCUSNODE
    Definition: type_tree.h:41
    type definitions for problem variables
    @ SCIP_BOUNDCHGTYPE_BRANCHING
    Definition: type_var.h:131