Scippy

    SCIP

    Solving Constraint Integer Programs

    event_estim.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 event_estim.c
    26 * @ingroup DEFPLUGINS_EVENT
    27 * @brief event handler for tree size estimation and restarts
    28 *
    29 * This event handler plugin provides different methods for approximating the current fraction of the search
    30 * that has already been completed and for estimating the total tree size at completion.
    31 * It can trigger restarts of the current run if the current run seems hopeless.
    32 *
    33 * For details about the available approximations of search completion, please see
    34 *
    35 * Anderson, Hendel, Le Bodic, Pfetsch
    36 * Estimating The Size of Branch-and-Bound Trees
    37 * under preparation
    38 *
    39 * This code is a largely enriched version of a code that was used for clairvoyant restarts, see
    40 *
    41 * Anderson, Hendel, Le Bodic, Viernickel
    42 * Clairvoyant Restarts in Branch-and-Bound Search Using Online Tree-Size Estimation
    43 * AAAI-19: Proceedings of the Thirty-Third AAAI Conference on Artificial Intelligence, 2018
    44 *
    45 * @author Gregor Hendel
    46 */
    47
    48/*--+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    49
    50#include <string.h>
    52#include "scip/event_estim.h"
    53#include "scip/prop_symmetry.h"
    54#include "scip/pub_disp.h"
    55#include "scip/pub_event.h"
    56#include "scip/pub_fileio.h"
    57#include "scip/pub_message.h"
    58#include "scip/pub_misc.h"
    59#include "scip/pub_tree.h"
    60#include "scip/scip_disp.h"
    61#include "scip/scip_event.h"
    62#include "scip/scip_general.h"
    63#include "scip/scip_mem.h"
    64#include "scip/scip_message.h"
    65#include "scip/scip_nlp.h"
    66#include "scip/scip_numerics.h"
    67#include "scip/scip_param.h"
    68#include "scip/scip_pricer.h"
    69#include "scip/scip_sol.h"
    70#include "scip/scip_solve.h"
    72#include "scip/scip_table.h"
    73#include "scip/scip_timing.h"
    74#include "scip/scip_tree.h"
    75#include "scip/type_disp.h"
    76#include "scip/type_event.h"
    77#include "scip/type_message.h"
    78#include "scip/type_misc.h"
    79#include "scip/type_retcode.h"
    80#include "scip/type_stat.h"
    81#include "scip/type_table.h"
    82
    83#define EVENTHDLR_NAME "estim"
    84#define EVENTHDLR_DESC "event handler for tree size estimation and restarts"
    85#define EVENTTYPE_ESTIM (SCIP_EVENTTYPE_NODEDELETE | SCIP_EVENTTYPE_NODEBRANCHED)
    86
    87/*
    88 * Data structures
    89 */
    90
    91/** enumerator for available restart policies */
    93{
    94 RESTARTPOLICY_NEVER = 0, /**< never restart (disable this event handler) */
    95 RESTARTPOLICY_ALWAYS = 1, /**< always restart (can be fine tuned by using minimum number of nodes and restart limit) */
    96 RESTARTPOLICY_ESTIMATION = 2, /**< base restart on the estimation method */
    97 RESTARTPOLICY_COMPLETION = 3 /**< trigger restart based on search completion approximation */
    98};
    99
    101
    102#define RESTARTPOLICY_CHAR_NEVER 'n'
    103#define RESTARTPOLICY_CHAR_ALWAYS 'a'
    104#define RESTARTPOLICY_CHAR_COMPLETION 'c'
    105#define RESTARTPOLICY_CHAR_ESTIMATION 'e'
    106
    107#define DES_USETRENDINLEVEL TRUE /**< Should the trend be used in the level update? */
    108
    109/* constants for the table estimation */
    110#define TABLE_NAME "estim"
    111#define TABLE_DESC "tree size estimations statistics table"
    112#define TABLE_POSITION 18500 /**< the position of the statistics table */
    113#define TABLE_EARLIEST_STAGE SCIP_STAGE_INIT /**< output of the statistics table is only printed from this stage onwards */
    114
    115/* constants for the search completion display column */
    116#define DISP_NAME "completed"
    117#define DISP_DESC "completion of search in percent (based on tree size estimation)"
    118#define DISP_HEADER "compl."
    119#define DISP_WIDTH 8 /**< the width of the display column */
    120#define DISP_PRIORITY 110000 /**< the priority of the display column */
    121#define DISP_POSITION 30100 /**< the relative position of the display column */
    122#define DISP_STRIPLINE TRUE /**< the default for whether the display column should be separated
    123 * with a line from its right neighbor */
    124#define INITIALSIZE 100
    125#define SESCOEFF 0.75 /**< coefficient of single exponential smoothing of estimation */
    126
    127/* double exponential smoothing parameters for different time series */
    128#define DES_ALPHA_TREEWEIGHT 0.65
    129#define DES_BETA_TREEWEIGHT 0.15
    130
    131#define DES_ALPHA_GAP 0.6
    132#define DES_BETA_GAP 0.15
    133
    134#define DES_ALPHA_LEAFFREQUENCY 0.3
    135#define DES_BETA_LEAFFREQUENCY 0.33
    136
    137#define DES_ALPHA_SSG 0.6
    138#define DES_BETA_SSG 0.15
    139
    140#define DES_ALPHA_OPENNODES 0.6
    141#define DES_BETA_OPENNODES 0.15
    142
    143#define MAX_REGFORESTSIZE 10000000 /**< size limit (number of nodes) for regression forest */
    144
    145
    146
    147/* computation of search completion */
    148#define COMPLETIONTYPE_AUTO 'a' /**< automatic (regression forest if available, else monotone regression on binary and SSG on nonbinary trees) */
    149#define COMPLETIONTYPE_REGFOREST 'r' /**< regression forest (must be provided by user) */
    150#define COMPLETIONTYPE_MONOREG 'm' /**< monotone regression (using tree weight and SSG) */
    151#define COMPLETIONTYPE_TREEWEIGHT 'w' /**< use tree weight value as approximation of search tree completion */
    152#define COMPLETIONTYPE_SSG 's' /**< use SSG value as approximation of search tree completion */
    153#define COMPLETIONTYPE_GAP 'g' /**< use gap value as approximation of search tree completion */
    154
    155
    156/* tree size estimation method */
    157#define ESTIMMETHOD_COMPL 'c' /**< estimation based on projection of current search completion */
    158#define ESTIMMETHOD_WBE 'b' /**< weighted backtrack estimation */
    159#define ESTIMMETHOD_ENSMBL 'e' /**< estimation based on an ensemble of the individual estimations */
    160#define ESTIMMETHOD_GAP 'g' /**< estimation based on double exponential smoothing for open nodes */
    161#define ESTIMMETHOD_LFREQ 'l' /**< estimation based on double exponential smoothing for leaf frequency */
    162#define ESTIMMETHOD_OPEN 'o' /**< estimation based on double exponential smoothing for open nodes */
    163#define ESTIMMETHOD_SSG 's' /**< estimation based on double exponential smoothing for sum of subtree gaps */
    164#define ESTIMMETHOD_TPROF 't' /**< estimation based on tree profile method */
    165#define ESTIMMETHOD_TREEWEIGHT 'w' /**< estimation based on double exponential smoothing for tree weight */
    166
    167#define ESTIMMETHODS "bceglostw"
    168
    169/* constants and default values for treeprofile parameters */
    170#define TREEPROFILE_MINSIZE 512 /**< minimum size (depth) that tree profile can hold */
    171#define SSG_STARTPRIMBOUND SCIP_INVALID /**< initial value of primal bound used within SSG */
    172
    173/** double exponential smoothing data structure */
    175{
    176 SCIP_Real alpha; /**< level smoothing constant */
    177 SCIP_Real beta; /**< trend smoothing constant */
    178 SCIP_Real level; /**< estimation of the current level used for smoothing */
    179 SCIP_Real trend; /**< estimation of the current trend (slope) */
    180 SCIP_Real initialvalue; /**< the level value at 0 observations */
    181 SCIP_Bool usetrendinlevel; /**< Should the trend be used in the level update? */
    182 int n; /**< number of observations */
    183};
    185
    186/** time series data structure for leaf time series
    187 *
    188 * These time series are the basic ingredient for tree size estimation via forecasting.
    189 *
    190 * This general class represents concrete time series such as the closed gap, tree weight, and leaf frequency.
    191 * Through callbacks for data (de-)initialization and value queries, it provides a common interface
    192 * to which double exponential smoothing or window forecasts can be applied.
    193 */
    194typedef struct TimeSeries TIMESERIES;
    195
    196/** data structure for convenient access of tree information */
    197typedef struct TreeData TREEDATA;
    198
    199
    200#define NTIMESERIES 5
    201
    202/** time series position in event handler time series array */
    204{
    205 TSPOS_NONE = -1, /**< invalid array position */
    206 TSPOS_GAP = 0, /**< time series position of gap */
    207 TSPOS_TREEWEIGHT = 1, /**< time series position of tree weight */
    208 TSPOS_LFREQ = 2, /**< time series position of leaf frequency */
    209 TSPOS_SSG = 3, /**< time series position of SSG */
    210 TSPOS_OPEN = 4 /**< time series position of open nodes */
    212
    213typedef enum TsPos TSPOS;
    214
    215/** regression forest data structure */
    217
    218/** statistics collected from profile used for prediction */
    220{
    221 int maxdepth; /**< maximum node depth encountered */
    222 int lastfulldepth; /**< deepest layer for which all nodes have been explored */
    223 int minwaistdepth; /**< minimum depth of the waist, i.e. the widest part of the tree */
    224 int maxwaistdepth; /**< maximum depth of the waist, i.e. the widest part of the tree */
    225};
    226
    228
    229
    230/** profile data structure for tree */
    232{
    233 SCIP_Longint* profile; /**< array to store the tree profile */
    234 int profilesize; /**< size of the profile array */
    235 TREEPROFILESTATS stats; /**< statistics collected from profile used for prediction */
    236 SCIP_Real lastestimate; /**< the last estimate predicted by predictTotalSizeTreeprofile() */
    237 TREEPROFILESTATS lastestimatestats; /**< tree profile statistics at last estimation */
    238};
    239
    241
    242/* default values of user parameters */
    243#define DEFAULT_USELEAFTS TRUE /**< Use leaf nodes as basic observations for time series, or all nodes? */
    244#define DEFAULT_REPORTFREQ -1 /**< report frequency on estimation: -1: never, 0: always, k >= 1: k times evenly during search */
    245#define DEFAULT_REGFORESTFILENAME "-" /**< default file name of user regression forest in RFCSV format */
    246#define DEFAULT_COEFMONOWEIGHT 0.3667 /**< coefficient of tree weight in monotone approximation of search completion */
    247#define DEFAULT_COEFMONOSSG 0.6333 /**< coefficient of 1 - SSG in monotone approximation of search completion */
    248#define DEFAULT_COMPLETIONTYPE COMPLETIONTYPE_AUTO /**< default computation of search tree completion */
    249#define DEFAULT_ESTIMMETHOD ESTIMMETHOD_TREEWEIGHT /**< default tree size estimation method: (c)ompletion, (e)nsemble, time series forecasts on either
    250 * (g)ap, (l)eaf frequency, (o)open nodes,
    251 * tree (w)eight, (s)sg, or (t)ree profile or w(b)e */
    252#define DEFAULT_TREEPROFILE_ENABLED FALSE /**< Should the event handler collect data? */
    253#define DEFAULT_TREEPROFILE_MINNODESPERDEPTH 20.0 /**< minimum average number of nodes at each depth before producing estimations */
    254#define DEFAULT_RESTARTPOLICY 'e' /**< default restart policy: (a)lways, (c)ompletion, (e)stimation, (n)ever */
    255#define DEFAULT_RESTARTLIMIT 1 /**< default restart limit */
    256#define DEFAULT_MINNODES 1000L /**< minimum number of nodes before restart */
    257#define DEFAULT_COUNTONLYLEAVES FALSE /**< should only leaves count for the minnodes parameter? */
    258#define DEFAULT_RESTARTFACTOR 50.0 /**< factor by which the estimated number of nodes should exceed the current number of nodes */
    259#define DEFAULT_RESTARTNONLINEAR FALSE /**< whether to apply a restart when nonlinear constraints are present */
    260#define DEFAULT_RESTARTACTPRICERS FALSE /**< whether to apply a restart when active pricers are used */
    261#define DEFAULT_HITCOUNTERLIM 50 /**< limit on the number of successive samples to really trigger a restart */
    262#define DEFAULT_SSG_NMAXSUBTREES -1 /**< the maximum number of individual SSG subtrees; the old split is kept if
    263 * a new split exceeds this number of subtrees ; -1: no limit */
    264#define DEFAULT_SSG_NMINNODESLASTSPLIT 0L /**< minimum number of nodes to process between two consecutive SSG splits */
    265#define DEFAULT_SHOWSTATS FALSE /**< should statistics be shown at the end? */
    266
    267/** event handler data */
    268struct SCIP_EventhdlrData
    269{
    270 SCIP_REGFOREST* regforest; /**< regression forest data structure */
    271 TIMESERIES* timeseries[NTIMESERIES]; /**< array of time series slots */
    272 TREEDATA* treedata; /**< tree data */
    273 TREEPROFILE* treeprofile; /**< tree profile data structure */
    274 char* regforestfilename; /**< file name of user regression forest in RFCSV format */
    275 SCIP_Real restartfactor; /**< factor by which the estimated number of nodes should exceed the current number of nodes */
    276 SCIP_Real weightlastreport; /**< tree weight at which last report was printed */
    277 SCIP_Real treeprofile_minnodesperdepth;/**< minimum average number of nodes at each depth before producing estimations */
    278 SCIP_Real coefmonoweight; /**< coefficient of tree weight in monotone approximation of search completion */
    279 SCIP_Real coefmonossg; /**< coefficient of 1 - SSG in monotone approximation of search completion */
    280 SCIP_Longint minnodes; /**< minimum number of nodes in a run before restart is triggered */
    281 int restartlimit; /**< How often should a restart be triggered? (-1 for no limit) */
    282 int nrestartsperformed; /**< number of restarts performed so far */
    283 int restarthitcounter; /**< the number of successive samples that would trigger a restart */
    284 int hitcounterlim; /**< limit on the number of successive samples to really trigger a restart */
    285 int nreports; /**< the number of reports already printed */
    286 int reportfreq; /**< report frequency on estimation: -1: never, 0:always, k >= 1: k times evenly during search */
    287 int lastrestartrun; /**< the last run at which this event handler triggered restart */
    288 char restartpolicyparam; /**< restart policy parameter */
    289 char estimmethod; /**< tree size estimation method: (c)ompletion, (e)nsemble, time series forecasts on either
    290 * (g)ap, (l)eaf frequency, (o)open nodes,
    291 * tree (w)eight, (s)sg, or (t)ree profile or w(b)e */
    292 char completiontypeparam;/**< approximation of search tree completion:
    293 * (a)uto, (g)ap, tree (w)eight, (m)onotone regression, (r)egression forest, (s)sg */
    294 SCIP_Bool countonlyleaves; /**< Should only leaves count for the minnodes parameter? */
    295 SCIP_Bool useleafts; /**< Use leaf nodes as basic observations for time series, or all nodes? */
    296 SCIP_Bool treeprofile_enabled;/**< Should the event handler collect treeprofile data? */
    297 SCIP_Bool treeisbinary; /**< internal flag if all branching decisions produced 2 children */
    298 SCIP_Bool restartnonlinear; /**< whether to apply a restart when nonlinear constraints are present */
    299 SCIP_Bool restartactpricers; /**< whether to apply a restart when active pricers are used */
    300 SCIP_Bool showstats; /**< should statistics be shown at the end? */
    301};
    302
    304
    306{
    307 SCIP_Longint nnodes; /**< the total number of nodes */
    308 SCIP_Longint nopen; /**< the current number of open nodes */
    309 SCIP_Longint ninner; /**< the number of inner nodes */
    310 SCIP_Longint nleaves; /**< the number of final leaf nodes */
    311 SCIP_Longint nvisited; /**< the number of visited nodes */
    312 long double weight; /**< the current tree weight (sum of leaf weights) */
    313 SUBTREESUMGAP* ssg; /**< subtree sum gap data structure */
    314};
    315
    317{
    318 SCIP_Real value; /**< the current subtree sum gap */
    319 SCIP_HASHMAP* nodes2info; /**< map between nodes and their subtree indices */
    320 SCIP_PQUEUE** subtreepqueues; /**< array of priority queues, one for each subtree */
    321 SCIP_Real scalingfactor; /**< the current scaling factor */
    322 SCIP_Real pblastsplit; /**< primal bound when last split occurred */
    323 SCIP_Longint nodelastsplit; /**< last node at which a subtree split occurred */
    324 SCIP_Longint nminnodeslastsplit; /**< minimum number of nodes to process between two consecutive SSG splits */
    325 int nmaxsubtrees; /**< the maximum number of individual SSG subtrees; the old split is kept if
    326 * a new split exceeds this number of subtrees ; -1: no limit */
    327 int nsubtrees; /**< the current number n of subtrees labeled 0 .. n - 1 */
    328};
    329
    330/** update callback of time series */
    331#define DECL_TIMESERIESUPDATE(x) SCIP_RETCODE x (\
    332 SCIP* scip, \
    333 TIMESERIES* ts, \
    334 TREEDATA* treedata, \
    335 SCIP_Real* value \
    336 )
    337
    338/** time series data structure for leaf time series */
    340{
    341 DOUBLEEXPSMOOTH des; /**< double exponential smoothing data structure */
    342 char* name; /**< name of this time series */
    343 SCIP_Real* vals; /**< value array of this time series */
    344 SCIP_Real* estimation; /**< array of estimations of this time series */
    345 SCIP_Real smoothestimation; /**< smoothened estimation value */
    346 SCIP_Real targetvalue; /**< target value of this time series */
    347 SCIP_Real currentvalue; /**< current value of time series */
    348 SCIP_Real initialvalue; /**< the initial value of time series */
    349 SCIP_Longint nobs; /**< total number of observations */
    350 int valssize; /**< size of value array */
    351 int nvals; /**< number of values */
    352 int resolution; /**< current (inverse of) resolution */
    353 SCIP_Bool useleafts; /**< Should this time series be recorded at leaf nodes, or at every node? */
    354 DECL_TIMESERIESUPDATE((*timeseriesupdate));/**< update callback at nodes */
    355};
    356
    357/** extended node information for SSG priority queue */
    359{
    360 SCIP_NODE* node; /**< search tree node */
    361 SCIP_Real lowerbound; /**< lower bound of the node at insertion into priority queue */
    362 int pos; /**< position of this node in priority queue */
    363 int subtreeidx; /**< subtree index of this node */
    364};
    365typedef struct NodeInfo NODEINFO;
    366
    368{
    369 int ntrees; /**< number of trees in this forest */
    370 int dim; /**< feature dimension */
    371 int* nbegin; /**< array of root node indices of each tree */
    372 int* child; /**< child index pair of each internal node, or (-1, -1) for leaves */
    373 int* splitidx; /**< data index for split at node, or -1 at a leaf */
    374 SCIP_Real* value; /**< split position at internal nodes, prediction at leaves */
    375 int size; /**< length of node arrays */
    376};
    377
    378/*
    379 * Local methods
    380 */
    381
    382/** convert number to string and treat SCIP_INVALID as '-' */
    383static
    385 SCIP_Real num, /**< number to convert to string */
    386 char* buf, /**< string buffer */
    387 int digits /**< number of decimal digits */
    388 )
    389{
    390 if( num == SCIP_INVALID )/*lint !e777*/
    391 (void) SCIPsnprintf(buf, 1, "-");
    392 else if( num >= 1e+20 ) /*lint !e777*/
    393 (void) SCIPsnprintf(buf, 3, "inf");
    394 else
    395 (void) SCIPsnprintf(buf, SCIP_MAXSTRLEN, "%10.*f", digits, num);
    396
    397 return buf;
    398}
    399
    400/** free a regression forest data structure */
    401static
    403 SCIP_REGFOREST** regforest /**< regression forest data structure */
    404 )
    405{
    406 SCIP_REGFOREST* regforestptr;
    407
    408 assert(regforest != NULL);
    409
    410 if( *regforest == NULL )
    411 return;
    412 regforestptr = *regforest;
    413
    414 BMSfreeMemoryArrayNull(&regforestptr->nbegin);
    415 BMSfreeMemoryArrayNull(&regforestptr->child);
    416 BMSfreeMemoryArrayNull(&regforestptr->splitidx);
    417 BMSfreeMemoryArrayNull(&regforestptr->value);
    418
    419 BMSfreeMemory(regforest);
    420}
    421
    422/** make a prediction with regression forest */
    423static
    425 SCIP_REGFOREST* regforest, /**< regression forest data structure */
    426 SCIP_Real* datapoint /**< a data point that matches the dimension of this regression forest */
    427 )
    428{
    429 int treeidx;
    430 SCIP_Real value = 0.0;
    431
    432 assert(regforest != NULL);
    433 assert(datapoint != NULL);
    434
    435 SCIPdebugMessage("Start prediction method of regression forest\n");
    436
    437 /* loop through the trees */
    438 for( treeidx = 0; treeidx < regforest->ntrees; ++treeidx )
    439 {
    440 int treepos = regforest->nbegin[treeidx];
    441 int* childtree = &(regforest->child[2 * treepos]);
    442 int* splitidxtree = &(regforest->splitidx[treepos]);
    443 int pos = 0;
    444 SCIP_Real* valuetree = &(regforest->value[treepos]);
    445
    446 SCIPdebugMessage("Tree %d at position %d\n", treeidx, treepos);
    447
    448 /* find the correct leaf */
    449 while( splitidxtree[pos] != - 1 )
    450 {
    451 int goright;
    452
    453 assert(splitidxtree[pos] < regforest->dim);
    454
    455 goright = (datapoint[splitidxtree[pos]] > valuetree[pos]) ? 1 : 0;
    456 pos = childtree[2 * pos + goright];
    457 }
    458
    459 value += valuetree[pos];
    460 }
    461
    462 /* return the average value that the trees predict */
    463 return value / (SCIP_Real)(regforest->ntrees);
    464}
    465
    466/** read a regression forest from an rfcsv file
    467 *
    468 * TODO improve this parser to better capture wrong user input, e.g., if the dimension is wrong
    469 */
    470static
    472 SCIP_REGFOREST** regforest, /**< regression forest data structure */
    473 const char* filename /**< name of file with the regression forest data */
    474 )
    475{
    476 SCIP_RETCODE retcode = SCIP_OKAY;
    477 SCIP_FILE* file;
    478 SCIP_REGFOREST* regforestptr;
    479 char buffer[SCIP_MAXSTRLEN];
    480 char firstlineformat[SCIP_MAXSTRLEN];
    481 char dataformat[SCIP_MAXSTRLEN];
    482 char valuestr[SCIP_MAXSTRLEN];
    483 SCIP_Bool error = FALSE;
    484 int ntrees;
    485 int dim;
    486 int size;
    487 int sscanret;
    488 int pos;
    489 int treepos;
    490
    491 /* try to open file */
    492 file = SCIPfopen(filename, "r");
    493
    494 if( file == NULL )
    495 return SCIP_NOFILE;
    496
    497 /* parse read the first line that contains the number of trees, feature dimension, and total number of nodes */
    498 (void) SCIPsnprintf(firstlineformat, SCIP_MAXSTRLEN, "### NTREES=%%10d FEATURE_DIM=%%10d LENGTH=%%10d\n");
    499 if( SCIPfgets(buffer, (int) sizeof(buffer), file) == NULL )
    500 {
    501 error = TRUE;
    502 SCIPerrorMessage("Could not read first line of regression file '%s'\n", filename);
    503 goto CLOSEFILE;
    504 }
    505
    506 /* coverity[secure_coding] */
    507 sscanret = sscanf(buffer, firstlineformat, &ntrees, &dim, &size);
    508
    509 if( sscanret != 3 )
    510 {
    511 error = TRUE;
    512 SCIPerrorMessage("Could not extract tree information from buffer line [%s]\n", buffer);
    513 goto CLOSEFILE;
    514 }
    515
    516 SCIPdebugMessage("Read ntrees=%d, dim=%d, size=%d (return value %d)\n", ntrees, dim, size, sscanret);
    517
    518 /* check if the tree is too big, or numbers are negative */
    519 if( size > MAX_REGFORESTSIZE )
    520 {
    521 error = TRUE;
    522 SCIPerrorMessage("Requested size %d exceeds size limit %d for regression trees", size, MAX_REGFORESTSIZE);
    523 goto CLOSEFILE;
    524 }
    525
    526 if( dim <= 0 || ntrees <= 0 || size <= 0 )
    527 {
    528 error = TRUE;
    529 SCIPerrorMessage("Cannot create regression tree with negative size, dimension, or number of trees\n");
    530 goto CLOSEFILE;
    531 }
    532
    533 /* allocate memory in regression forest data structure */
    534 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemory(regforest), FREEFOREST );
    535 BMSclearMemory(*regforest);
    536 regforestptr = *regforest;
    537
    538 /* coverity[tainted_data] */
    539 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&regforestptr->nbegin, ntrees), FREEFOREST );
    540 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&regforestptr->child, 2 * size), FREEFOREST ); /*lint !e647*/
    541 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&regforestptr->splitidx, size), FREEFOREST );
    542 SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&regforestptr->value, size), FREEFOREST );
    543
    544 regforestptr->dim = dim;
    545 regforestptr->size = size;
    546 regforestptr->ntrees = ntrees;
    547
    548 SCIPdebugMessage("Random Forest allocated\n");
    549
    550 /* loop through the rest of the file, which contains the comma separated node data */
    551 (void) SCIPsnprintf(dataformat, SCIP_MAXSTRLEN, "%%10d,%%10d,%%10d,%%10d,%%%ds\n", SCIP_MAXSTRLEN);
    552
    553 pos = 0;
    554 treepos = 0;
    555 while( !SCIPfeof(file) && !error )
    556 {
    557 int node;
    558 char* endptr;
    559
    560 /* get next line */
    561 if( SCIPfgets(buffer, (int) sizeof(buffer), file) == NULL )
    562 break;
    563
    564 sscanret = sscanf(buffer, dataformat,
    565 &node,
    566 &regforestptr->child[2 * pos],
    567 &regforestptr->child[2 * pos + 1],
    568 &regforestptr->splitidx[pos],
    569 valuestr);
    570
    571 if( sscanret != 5 )
    572 {
    573 SCIPerrorMessage("Something wrong with line %d '%s'", pos + 1, buffer);
    574 error = TRUE;
    575 }
    576
    577 (void)SCIPstrToRealValue(valuestr, &regforestptr->value[pos], &endptr);
    578
    579 /* new root node - increase the tree index position */
    580 if( node == 0 )
    581 {
    582 assert(treepos < regforestptr->ntrees);
    583
    584 regforestptr->nbegin[treepos++] = pos;
    585 }
    586
    587 ++pos;
    588 }
    589
    590 goto CLOSEFILE;
    591
    592/* insufficient memory for allocating regression forest */
    593FREEFOREST:
    594 assert(retcode == SCIP_NOMEMORY);
    595 SCIPregForestFree(regforest);
    596
    597CLOSEFILE:
    598 SCIPfclose(file);
    599
    600 if( error )
    601 retcode = SCIP_INVALIDDATA;
    602
    603 return retcode;
    604}
    605
    606/** compare two tree profile statistics for equality */
    607static
    609 TREEPROFILESTATS* stats, /**< first tree profile statistics */
    610 TREEPROFILESTATS* other /**< other tree profile statistics */
    611 )
    612{
    613 assert(stats != NULL);
    614 assert(other != NULL);
    615
    616 return stats->maxdepth == other->maxdepth &&
    617 stats->lastfulldepth == other->lastfulldepth &&
    618 stats->minwaistdepth == other->minwaistdepth &&
    619 stats->maxwaistdepth == other->maxwaistdepth;
    620}
    621
    622/** copy source tree profile into destination */
    623static
    625 TREEPROFILESTATS* dest, /**< destination tree profile statistics */
    626 TREEPROFILESTATS* src /**< source tree profile statistics */
    627 )
    628{
    629 assert(dest != NULL);
    630 assert(src != NULL);
    631
    632 dest->maxdepth = src->maxdepth;
    633 dest->lastfulldepth = src->lastfulldepth;
    634 dest->minwaistdepth = src->minwaistdepth;
    635 dest->maxwaistdepth = src->maxwaistdepth;
    636}
    637
    638/** reset tree profile statistics */
    639static
    641 TREEPROFILESTATS* treeprofilestats /**< tree profile statistics */
    642 )
    643{
    644 assert(treeprofilestats != NULL);
    645
    646 BMSclearMemory(treeprofilestats);
    647}
    648
    649
    650/** extend tree profile to deeper tree */
    651static
    653 SCIP* scip, /**< SCIP data structure */
    654 TREEPROFILE* treeprofile, /**< tree profile data structure */
    655 int mindepth /**< minimum depth that the tree profile should hold */
    656 )
    657{
    658 if( mindepth < treeprofile->profilesize )
    659 return SCIP_OKAY;
    660
    661 if( treeprofile->profile == NULL )
    662 {
    663 SCIP_CALL( SCIPallocClearMemoryArray(scip, &treeprofile->profile, mindepth) );
    664 treeprofile->profilesize = mindepth;
    665 }
    666 else
    667 {
    668 int newsize;
    669 int nnewelems;
    670 SCIP_Longint* newprofile;
    671
    672 newsize = SCIPcalcMemGrowSize(scip, mindepth + 1);
    673 nnewelems = newsize - treeprofile->profilesize;
    674 assert(newsize > treeprofile->profilesize);
    675
    676 SCIP_CALL( SCIPreallocMemoryArray(scip, &treeprofile->profile, newsize) );
    677 newprofile = &treeprofile->profile[treeprofile->profilesize];
    678 BMSclearMemoryArray(newprofile, nnewelems);
    679 treeprofile->profilesize = newsize;
    680 }
    681
    682 return SCIP_OKAY;
    683}
    684
    685/** create a tree profile */
    686static
    688 SCIP* scip, /**< SCIP data structure */
    689 TREEPROFILE** treeprofile /**< pointer to store tree profile data structure */
    690 )
    691{
    692 assert(scip != NULL);
    693 assert(treeprofile != NULL);
    694
    695 SCIP_CALL( SCIPallocMemory(scip, treeprofile) );
    696
    697 (*treeprofile)->profile = NULL;
    698 (*treeprofile)->profilesize = 0;
    700
    701 resetTreeProfileStats(&(*treeprofile)->stats);
    702 resetTreeProfileStats(&(*treeprofile)->lastestimatestats);
    703
    704 (*treeprofile)->lastestimate = -1.0;
    705
    706 return SCIP_OKAY;
    707}
    708
    709/** free a tree profile */
    710static
    712 SCIP* scip, /**< SCIP data structure */
    713 TREEPROFILE** treeprofile /**< pointer to tree profile data structure */
    714 )
    715{
    716 assert(scip != NULL);
    717 assert(treeprofile != NULL);
    718
    719 if( *treeprofile == NULL )
    720 return;
    721
    722 SCIPfreeMemoryArray(scip, &(*treeprofile)->profile);
    723
    724 SCIPfreeMemory(scip, treeprofile);
    725
    726 *treeprofile = NULL;
    727}
    728
    729/** update tree profile */
    730static
    732 SCIP* scip, /**< SCIP data structure */
    733 TREEPROFILE* treeprofile, /**< tree profile data structure */
    734 SCIP_NODE* node /**< node that should be added to the profile */
    735 )
    736{
    737 int nodedepth;
    738 unsigned long nbits;
    739 SCIP_Longint nodedepthcnt;
    740 SCIP_Longint maxnodes;
    741
    742 assert(scip != NULL);
    743 assert(node != NULL);
    744
    745 if( treeprofile == NULL )
    746 return SCIP_OKAY;
    747
    748 nodedepth = SCIPnodeGetDepth(node);
    749 assert(nodedepth >= 0);
    750 maxnodes = treeprofile->profile[treeprofile->stats.minwaistdepth];
    751 assert(treeprofile->stats.minwaistdepth == treeprofile->stats.maxwaistdepth ||
    752 maxnodes == treeprofile->profile[treeprofile->stats.maxwaistdepth]);
    753
    754 /* ensure that the memory can hold at least this depth */
    755 SCIP_CALL( extendMemoryTreeProfile(scip, treeprofile, nodedepth) );
    756
    757 nodedepthcnt = ++treeprofile->profile[nodedepth];
    758
    759 /* Is this level fully explored? We assume binary branching. The first condition ensures that the bit shift operation
    760 * of the second condition represents a feasible power of unsigned int. The largest power of 2 representable
    761 * by unsigned int is 2^{8*sizeof(unsigned int) - 1}. */
    762 nbits = 8*sizeof(unsigned int);
    763 /* coverity[overflow_before_widen] */
    764 if( (unsigned int)nodedepth < nbits && nodedepthcnt == (1U << nodedepth) )/*lint !e647*/
    765 {
    766 SCIPdebugMsg(scip, "Level %d fully explored: %" SCIP_LONGINT_FORMAT " nodes\n", nodedepth, nodedepthcnt);
    767
    768 treeprofile->stats.lastfulldepth = nodedepth;
    769 }
    770
    771 /* update maximum depth */
    772 if( treeprofile->stats.maxdepth < nodedepth )
    773 {
    774 treeprofile->stats.maxdepth = nodedepth;
    775 SCIPdebugMsg(scip, "Maximum depth increased to %d\n", treeprofile->stats.maxdepth);
    776 }
    777
    778 /* minimum and maximum waist now coincide */
    779 if( nodedepthcnt > maxnodes )
    780 {
    781 treeprofile->stats.minwaistdepth = treeprofile->stats.maxwaistdepth = nodedepth;
    782 SCIPdebugMsg(scip, "Updating depth of tree waist: %d (%" SCIP_LONGINT_FORMAT " nodes)\n",
    783 treeprofile->stats.minwaistdepth, nodedepthcnt);
    784 }
    785 else if( nodedepthcnt == maxnodes )
    786 {
    787 /* enlarge the interval in which the waist lies */
    788 if( treeprofile->stats.minwaistdepth > nodedepth )
    789 treeprofile->stats.minwaistdepth = nodedepth;
    790 else if( treeprofile->stats.maxwaistdepth < nodedepth )
    791 treeprofile->stats.maxwaistdepth = nodedepth;
    792 }
    793 assert(treeprofile->stats.minwaistdepth <= treeprofile->stats.maxwaistdepth);
    794
    795 return SCIP_OKAY;
    796}
    797
    798/** make a prediction of the total tree size based on the current tree profile */
    799static
    801 SCIP* scip, /**< SCIP data structure */
    802 TREEPROFILE* treeprofile, /**< tree profile data structure */
    803 SCIP_Real minnodesperdepth /**< minimum number of average nodes per depth to make a prediction */
    804 )
    805{
    806 SCIP_Real estimate;
    807 SCIP_Real growthfac;
    808 int d;
    809 int waist;
    810
    811 /* prediction is disabled */
    812 if( treeprofile == NULL )
    813 return -1.0;
    814
    815 /* two few nodes to make a prediction */
    816 if( minnodesperdepth * treeprofile->stats.maxdepth > SCIPgetNNodes(scip) )
    817 return -1.0;
    818
    819 /* reuse previous estimation if tree profile hasn't changed */
    820 if( isEqualTreeProfileStats(&treeprofile->lastestimatestats, &treeprofile->stats) )
    821 {
    822 SCIPdebugMsg(scip, "Reusing previous estimation result %g\n", treeprofile->lastestimate);
    823
    824 return treeprofile->lastestimate;
    825 }
    826
    827 /* compute the (depth of the) waist as convex combination between the minimum and maximum waist depths */
    828 waist = (2 * treeprofile->stats.maxwaistdepth + treeprofile->stats.minwaistdepth) / 3;
    829
    830 growthfac = 2;
    831 estimate = 1;
    832
    833 /* loop over all full levels */
    834 for( d = 1; d < treeprofile->stats.lastfulldepth; ++d )
    835 {
    836 SCIP_Real gamma_d = 2.0;
    837
    838 estimate += growthfac;
    839 growthfac *= gamma_d;
    840 }
    841
    842 /* loop until the waist is reached */
    843 for( ; d < waist; ++d )
    844 {
    845 SCIP_Real gamma_d = 2.0 - (d - treeprofile->stats.lastfulldepth + 1.0)/(waist - treeprofile->stats.lastfulldepth + 1.0);
    846
    847 assert(1.0 <= gamma_d && gamma_d <= 2.0);
    848 estimate += growthfac;
    849 growthfac *= gamma_d;
    850 }
    851
    852 /* loop over the remaining levels */
    853 for( ; d <= treeprofile->stats.maxdepth; ++d )
    854 {
    855 SCIP_Real gamma_d = (1.0 - (d - waist + 1.0)/(treeprofile->stats.maxdepth - waist + 1.0));
    856 assert(0.0 <= gamma_d && gamma_d <= 1.0);
    857
    858 estimate += growthfac;
    859 growthfac *= gamma_d;
    860 }
    861
    862 /* copy tree profile statistics */
    863 copyTreeProfileStats(&treeprofile->lastestimatestats, &treeprofile->stats);
    864
    865 treeprofile->lastestimate = estimate;
    866
    867 return estimate;
    868}
    869
    870/** clean subtrees stored as priority queues */
    871static
    873 SCIP* scip, /**< SCIP data structure */
    874 SUBTREESUMGAP* ssg /**< subtree sum gap data structure */
    875 )
    876{
    877 assert(ssg->nsubtrees <= 1 || ssg->subtreepqueues != NULL);
    878
    879 /* free all previous priority queues */
    880 if( ssg->nsubtrees > 1 )
    881 {
    882 int s;
    883
    884 for( s = 0; s < ssg->nsubtrees; ++s )
    885 {
    886 int i;
    887 SCIP_PQUEUE* pqueue = ssg->subtreepqueues[s];
    888 NODEINFO** nodeinfos;
    889
    890 assert(pqueue != NULL);
    891 nodeinfos = (NODEINFO**)SCIPpqueueElems(pqueue);
    892
    893 /* free all remaining elements in reverse order */
    894 for( i = SCIPpqueueNElems(pqueue); --i >= 0; )
    895 {
    896 NODEINFO* nodeinfo = nodeinfos[i];
    897 assert(nodeinfo != NULL);
    898 SCIPfreeBlockMemory(scip, &nodeinfo);
    899 }
    900
    901 SCIPpqueueFree(&pqueue);
    902 }
    903
    905 }
    906
    907 ssg->subtreepqueues = NULL;
    908}
    909
    910/** reset subtree sum gap */
    911static
    913 SCIP* scip, /**< SCIP data structure */
    914 SUBTREESUMGAP* ssg /**< subtree sum gap data structure */
    915 )
    916{
    917 assert(ssg != NULL);
    918 assert(ssg->nodes2info != NULL);
    919
    921
    923
    924 ssg->value = 1.0;
    925 ssg->scalingfactor = 1.0;
    926 ssg->nsubtrees = 1;
    927 ssg->subtreepqueues = NULL;
    929 ssg->nodelastsplit = -1L;
    930
    931 return SCIP_OKAY;
    932}
    933
    934/** create a subtree sum gap */
    935static
    937 SCIP* scip, /**< SCIP data structure */
    938 SUBTREESUMGAP** ssg /**< pointer to store subtree sum gap data structure */
    939 )
    940{
    941 assert(scip != NULL);
    942 assert(ssg != NULL);
    943
    944 /* allocate storage */
    946 SCIP_CALL( SCIPhashmapCreate(&(*ssg)->nodes2info, SCIPblkmem(scip), INITIALSIZE) );
    947
    948 /* explicitly set this to skip removal of subtrees during reset */
    949 (*ssg)->nsubtrees = 0;
    950
    951 /* reset ssg */
    953
    954 return SCIP_OKAY;
    955}
    956
    957/** free a subtree sum gap */
    958static
    960 SCIP* scip, /**< SCIP data structure */
    961 SUBTREESUMGAP** ssg /**< pointer to store subtree sum gap data structure */
    962 )
    963{
    964 assert(scip != NULL);
    965
    966 if( *ssg == NULL )
    967 return;
    968
    969 if( (*ssg)->nodes2info != NULL )
    970 {
    971 SCIPhashmapFree(&(*ssg)->nodes2info);
    972 }
    973
    974 /* delete all subtree data */
    976
    977 SCIPfreeMemory(scip, ssg);
    978}
    979
    980/** compare two node infos by comparing their lower bound */
    981static
    982SCIP_DECL_SORTPTRCOMP(compareNodeInfos)
    983{
    984 NODEINFO* nodeinfo1 = (NODEINFO*)elem1;
    985 NODEINFO* nodeinfo2 = (NODEINFO*)elem2;
    986
    987 if( nodeinfo1->lowerbound < nodeinfo2->lowerbound )
    988 return -1;
    989 else if( nodeinfo1->lowerbound > nodeinfo2->lowerbound )
    990 return 1;
    991
    992 return 0;
    993}
    994
    995/** position change callback of element in priority queue */
    996static
    997SCIP_DECL_PQUEUEELEMCHGPOS(elemChgPosNodeInfo)
    998{
    999 NODEINFO* nodeinfo = (NODEINFO*)elem;
    1000
    1001 assert(oldpos == -1 || oldpos == nodeinfo->pos);
    1002 nodeinfo->pos = newpos;
    1003}
    1004
    1005/** store node in SSG data structure */
    1006static
    1008 SCIP* scip, /**< SCIP data structure */
    1009 SUBTREESUMGAP* ssg, /**< subtree sum gap data structure */
    1010 SCIP_NODE* node, /**< node that should be stored */
    1011 int subtreeidx /**< subtree index of that node */
    1012 )
    1013{
    1014 NODEINFO* nodeinfo;
    1015
    1016 assert(scip != NULL);
    1017 assert(ssg != NULL);
    1018 assert(node != NULL);
    1019
    1020 /* create a new node info */
    1021 SCIP_CALL( SCIPallocBlockMemory(scip, &nodeinfo) );
    1022
    1023 /* store node information in data structure and insert into priority queue */
    1024 nodeinfo->node = node;
    1025 nodeinfo->subtreeidx = subtreeidx;
    1026 nodeinfo->pos = -1;
    1027 nodeinfo->lowerbound = SCIPnodeGetLowerbound(node);
    1028
    1029 SCIPdebugMsg(scip, "Inserting label %d for node number %" SCIP_LONGINT_FORMAT " (%p)\n",
    1030 subtreeidx, SCIPnodeGetNumber(node), (void*)node);
    1031
    1032 assert(!SCIPhashmapExists(ssg->nodes2info, (void*)node));
    1033 /* store node information in Hash Map */
    1034 SCIP_CALL( SCIPhashmapInsert(ssg->nodes2info, (void*)node, (void*)nodeinfo) );
    1035
    1036 /* create the corresponding priority queue, if it does not exist yet */
    1037 assert(subtreeidx >= 0);
    1038 assert(subtreeidx < ssg->nsubtrees);
    1039
    1040 if( ssg->subtreepqueues[subtreeidx] == NULL )
    1041 {
    1042 SCIP_CALL( SCIPpqueueCreate(&ssg->subtreepqueues[subtreeidx], 5, 1.2, compareNodeInfos, elemChgPosNodeInfo) );
    1043 }
    1044
    1045 /* insert node and ensure that its position is up to date */
    1046 SCIP_CALL( SCIPpqueueInsert(ssg->subtreepqueues[subtreeidx], (void*)nodeinfo) );
    1047 assert(0 <= nodeinfo->pos);
    1048 assert(SCIPpqueueNElems(ssg->subtreepqueues[subtreeidx]) > nodeinfo->pos);
    1049 assert(SCIPpqueueElems(ssg->subtreepqueues[subtreeidx])[nodeinfo->pos] == (void*)nodeinfo);
    1050
    1051 return SCIP_OKAY;
    1052}
    1053
    1054/** split the open nodes of the current tree */
    1055static
    1057 SCIP* scip, /**< SCIP data structure */
    1058 SUBTREESUMGAP* ssg, /**< subtree sum gap data structure */
    1059 SCIP_Bool addfocusnode /**< should the focus node be a subtree, too? */
    1060 )
    1061{
    1062 SCIP_NODE** opennodes[3];
    1063 int nopennodes[3];
    1064 int label;
    1065 int t;
    1066 int nnewsubtrees;
    1067
    1068 assert(scip != NULL);
    1069 assert(ssg != NULL);
    1070
    1071 /* query the open nodes of SCIP */
    1072 SCIP_CALL( SCIPgetOpenNodesData(scip, &opennodes[0], &opennodes[1], &opennodes[2], &nopennodes[0], &nopennodes[1], &nopennodes[2]) );
    1073
    1074 nnewsubtrees = nopennodes[0] + nopennodes[1] + nopennodes[2] + (addfocusnode ? 1 : 0);
    1075
    1076 /* clear hash map from entries */
    1078
    1079 /* delete all subtrees */
    1081
    1082 ssg->nsubtrees = nnewsubtrees;
    1083 SCIPdebugMsg(scip, "Splitting tree into %d subtrees\n", ssg->nsubtrees);
    1084
    1085 /* create priority queue array */
    1086 if( ssg->nsubtrees > 1 )
    1087 {
    1089 }
    1090 else
    1091 {
    1092 ssg->subtreepqueues = NULL;
    1093
    1094 return SCIP_OKAY;
    1095 }
    1096
    1097 /* loop over node types (leaves, siblings, children) */
    1098 label = 0;
    1099 for( t = 0; t < 3; ++t )
    1100 {
    1101 SCIP_NODE** nodes = opennodes[t];
    1102 int nnodes = nopennodes[t];
    1103 int n;
    1104
    1105 /* label each open node as new, separate subtree */
    1106 for( n = 0; n < nnodes; ++n )
    1107 {
    1108 SCIP_NODE* node = nodes[n];
    1109 SCIP_CALL( subtreeSumGapStoreNode(scip, ssg, node, label++) );
    1110 }
    1111 }
    1112
    1113 if( addfocusnode )
    1114 {
    1115 assert(SCIPgetFocusNode(scip) != NULL);
    1117 }
    1118
    1119 return SCIP_OKAY;
    1120}
    1121
    1122/** compute a gap between a lower bound and the current upper bound */
    1123static
    1125 SCIP* scip, /**< SCIP data structure */
    1126 SCIP_Real lowerbound /**< lower bound value */
    1127 )
    1128{
    1129 SCIP_Real db;
    1130 SCIP_Real pb;
    1131 SCIP_Real abspb;
    1132 SCIP_Real absdb;
    1133 SCIP_Real gap;
    1134
    1135 if( SCIPisInfinity(scip, lowerbound) || lowerbound >= SCIPgetUpperbound(scip) )
    1136 return 0.0;
    1137
    1139 return 1.0;
    1140
    1141 db = SCIPretransformObj(scip, lowerbound);
    1143
    1144 if( SCIPisEQ(scip, db, pb) )
    1145 return 0.0;
    1146
    1147 abspb = REALABS(pb);
    1148 absdb = REALABS(db);
    1149 gap = REALABS(pb - db)/MAX(abspb,absdb);
    1150 gap = MIN(gap, 1.0);
    1151
    1152 return gap;
    1153}
    1154
    1155/** remove node from the subtree sum gap (because it has been solved by branching or is a leaf) */
    1156static
    1158 SCIP* scip, /**< SCIP data structure */
    1159 SUBTREESUMGAP* ssg, /**< subtree sum gap data structure */
    1160 SCIP_NODE* node /**< node that should be removed */
    1161 )
    1162{
    1163 NODEINFO* nodeinfo;
    1164 int subtreeidx;
    1165 int pos;
    1166 SCIP_PQUEUE* pqueue;
    1167
    1168 if( ssg->nsubtrees <= 1 )
    1169 return SCIP_OKAY;
    1170
    1171 nodeinfo = (NODEINFO*)SCIPhashmapGetImage(ssg->nodes2info, (void*)node);
    1172
    1173 /* it can happen that the node was not created via branching; search for the most recent ancestor in the queue */
    1174 if( nodeinfo == NULL )
    1175 {
    1176 do
    1177 {
    1178 node = SCIPnodeGetParent(node);
    1179 } while( node != NULL && (nodeinfo = (NODEINFO*)SCIPhashmapGetImage(ssg->nodes2info, (void*)node)) == NULL);
    1180
    1181 /* no ancestor found */
    1182 if( nodeinfo == NULL )
    1183 return SCIP_OKAY;
    1184 }
    1185
    1186 /* get open nodes of this subtree stored as priority queue */
    1187 subtreeidx = nodeinfo->subtreeidx;
    1188 pqueue = ssg->subtreepqueues[subtreeidx];
    1189 assert(pqueue != NULL);
    1190
    1191 /* delete the element from the priority queue */
    1192 pos = nodeinfo->pos;
    1193 assert(pos >= 0);
    1194 assert(pos < SCIPpqueueNElems(pqueue));
    1195 assert(SCIPpqueueElems(pqueue)[pos] == (void *)nodeinfo);
    1196 SCIPpqueueDelPos(pqueue, pos);
    1197
    1198 /* update ssg if removed node was the lower bound defining node of its subtree */
    1199 if( pos == 0 )
    1200 {
    1201 NODEINFO* nodeinfofirst;
    1202 SCIP_Real oldgap;
    1203 SCIP_Real newgap;
    1204
    1205 oldgap = calcGap(scip, nodeinfo->lowerbound);
    1206 nodeinfofirst = (NODEINFO*)SCIPpqueueFirst(ssg->subtreepqueues[subtreeidx]);
    1207 assert(nodeinfofirst == NULL || subtreeidx == nodeinfofirst->subtreeidx);
    1208 newgap = calcGap(scip, nodeinfofirst != NULL ? nodeinfofirst->lowerbound : SCIPinfinity(scip) );
    1209
    1210 assert(SCIPisLE(scip, newgap, oldgap));
    1211
    1212 /* the SSG value is always up-to-date because it is recomputed when the primal bound changes */
    1213 ssg->value += ssg->scalingfactor * MIN(newgap - oldgap, 0.0);
    1214 }
    1215
    1216 SCIP_CALL( SCIPhashmapRemove(ssg->nodes2info, (void*)node) );
    1217
    1218 SCIPdebugMsg(scip, "Removed node %" SCIP_LONGINT_FORMAT " from open nodes of SSG\n",
    1219 SCIPnodeGetNumber(node));
    1220
    1221 SCIPfreeBlockMemory(scip, &nodeinfo);
    1222
    1223 return SCIP_OKAY;
    1224}
    1225
    1226/** insert children into subtree sum gap */
    1227static
    1229 SCIP* scip, /**< SCIP data structure */
    1230 SUBTREESUMGAP* ssg /**< subtree sum gap data structure */
    1231 )
    1232{
    1233 int nchildren;
    1234 SCIP_NODE** children;
    1235 SCIP_NODE* focusnode;
    1236 SCIP_NODE* parentnode;
    1237 NODEINFO* parentnodeinfo;
    1238 int parentnodelabel;
    1239 int n;
    1240
    1241 assert(scip != NULL);
    1242 assert(ssg != NULL);
    1243
    1244 if( ssg->nsubtrees == 1 )
    1245 return SCIP_OKAY;
    1246
    1247 SCIP_CALL( SCIPgetChildren(scip, &children, &nchildren) );
    1248
    1249 if( nchildren == 0 )
    1250 return SCIP_OKAY;
    1251
    1252 focusnode = SCIPgetFocusNode(scip);
    1253
    1254 /* a rare case: the search has been stopped at some point, and the current focus node is the only descendant
    1255 * of its parent node
    1256 */
    1257 if( !SCIPhashmapExists(ssg->nodes2info, (void*)focusnode) )
    1258 {
    1259 parentnode = focusnode;
    1260 do
    1261 {
    1262 parentnode = SCIPnodeGetParent(parentnode);
    1263 } while( parentnode != NULL && !SCIPhashmapExists(ssg->nodes2info, (void *)parentnode));
    1264
    1265 assert(parentnode != NULL && SCIPhashmapExists(ssg->nodes2info, (void *)parentnode));
    1266 }
    1267 else
    1268 parentnode = focusnode;
    1269
    1270 parentnodeinfo = (NODEINFO*)SCIPhashmapGetImage(ssg->nodes2info, (void *)parentnode);
    1271 parentnodelabel = parentnodeinfo->subtreeidx;
    1272
    1273 /* loop over children and insert the focus node label */
    1274 for( n = 0; n < nchildren; ++n )
    1275 {
    1276 assert(SCIPnodeGetParent(children[n]) == focusnode);
    1277
    1279 "Inserting label %d for node number %" SCIP_LONGINT_FORMAT " (parent %" SCIP_LONGINT_FORMAT ")\n",
    1280 parentnodelabel, SCIPnodeGetNumber(children[n]), SCIPnodeGetNumber(parentnode));
    1281
    1282 SCIP_CALL( subtreeSumGapStoreNode(scip, ssg, children[n], parentnodelabel) );
    1283 }
    1284
    1285 /* remove focus node from hash map */
    1286 SCIP_CALL( subtreeSumGapRemoveNode(scip, ssg, parentnode) );
    1287
    1288 return SCIP_OKAY;
    1289}
    1290
    1291/* this function is inefficient because it loops over all open nodes, but can be used for debugging */
    1292#ifdef SCIP_DISABLED_CODE
    1293/** compute subtree sum gap from scratch (inefficiently because loop over all open nodes) */
    1294static
    1295SCIP_RETCODE subtreesumgapComputeFromScratch(
    1296 SCIP* scip, /**< SCIP data structure */
    1297 SUBTREESUMGAP* ssg, /**< subtree sum gap data structure */
    1298 SCIP_Bool updatescaling /**< should the scaling factor be updated? */
    1299 )
    1300{
    1301 SCIP_Real* lowerbounds;
    1302 SCIP_NODE** opennodes[3];
    1303 SCIP_Real gapsum = 0;
    1304 SCIP_Real pb;
    1305 int nopennodes[3];
    1306 int l;
    1307 int t;
    1308
    1309 /* treat trivial cases: only 1 subtree, no incumbent solution */
    1311 {
    1312 ssg->value = 1.0;
    1313
    1314 return SCIP_OKAY;
    1315 }
    1316
    1317 /* simply use normal gap in trivial case */
    1318 if( ssg->nsubtrees == 1 )
    1319 {
    1321
    1322 return SCIP_OKAY;
    1323 }
    1324
    1325 /* allocate temporary memory to store lower bound for every subtree */
    1326 SCIP_CALL( SCIPallocBufferArray(scip, &lowerbounds, ssg->nsubtrees) );
    1327
    1328 /* initialize lower bounds as SCIPinfinity(scip) */
    1329 for( l = 0; l < ssg->nsubtrees; ++l )
    1330 lowerbounds[l] = SCIPinfinity(scip);
    1331
    1332 /* loop over children, siblings, and leaves to update subtree lower bounds */
    1333 SCIP_CALL( SCIPgetOpenNodesData(scip, &opennodes[0], &opennodes[1], &opennodes[2], &nopennodes[0], &nopennodes[1], &nopennodes[2]) );
    1334
    1335 /* loop over the three types leaves, siblings, leaves */
    1336 for( t = 0; t < 3; ++t )
    1337 {
    1338 int n;
    1339 /* loop over nodes of this type */
    1340 for( n = 0; n < nopennodes[t]; ++n )
    1341 {
    1342 SCIP_NODE* node = opennodes[t][n];
    1343 NODEINFO* nodeinfo;
    1344 SCIP_Real lowerbound;
    1345 int label;
    1346 nodeinfo = (NODEINFO*)SCIPhashmapGetImage(ssg->nodes2info, (void *)node);
    1347 label = nodeinfo->subtreeidx;
    1348 lowerbound = nodeinfo->lowerbound;
    1349
    1350 assert(label >= 0 && label < ssg->nsubtrees);
    1351 lowerbounds[label] = MIN(lowerbounds[label], lowerbound);
    1352 }
    1353 }
    1354
    1355 /* compute subtree gaps in original space; sum them up */
    1357 for( l = 0; l < ssg->nsubtrees; ++l )
    1358 {
    1359 SCIP_Real subtreedualbound;
    1360 SCIP_Real subtreegap;
    1361 /* skip subtrees with infinite lower bound; they are empty and contribute 0.0 to the gap sum term */
    1362 if( SCIPisInfinity(scip, lowerbounds[l]) )
    1363 continue;
    1364
    1365 subtreedualbound = SCIPretransformObj(scip, lowerbounds[l]);
    1366
    1367 if( SCIPisEQ(scip, subtreedualbound, pb) )
    1368 continue;
    1369
    1370 subtreegap = REALABS(pb - subtreedualbound)/MAX(REALABS(pb),REALABS(subtreedualbound));
    1371 subtreegap = MIN(subtreegap, 1.0);
    1372
    1373 gapsum += subtreegap;
    1374 }
    1375
    1376 /* update the scaling factor by using the previous SSG value divided by the current gapsum */
    1377 if( updatescaling )
    1378 {
    1379 ssg->scalingfactor = ssg->value / MAX(gapsum, 1e-6);
    1380 }
    1381
    1382 /* update and store SSG value by considering scaling factor */
    1383 ssg->value = ssg->scalingfactor * gapsum;
    1384
    1385 SCIPfreeBufferArray(scip, &lowerbounds);
    1386
    1387 return SCIP_OKAY;
    1388}
    1389#endif
    1390
    1391/** compute subtree sum gap from scratch efficiently (linear effort in the number of subtrees) */
    1392static
    1394 SCIP* scip, /**< SCIP data structure */
    1395 SUBTREESUMGAP* ssg, /**< subtree sum gap data structure */
    1396 SCIP_Bool updatescaling /**< should the scaling factor be updated? */
    1397 )
    1398{
    1399 SCIP_Real gapsum = 0.0;
    1400 int l;
    1401
    1402 /* treat trivial cases: only 1 subtree, no incumbent solution */
    1404 {
    1405 ssg->value = 1.0;
    1406
    1407 return SCIP_OKAY;
    1408 }
    1409
    1410 if( ssg->nsubtrees == 1 )
    1411 {
    1413
    1414 return SCIP_OKAY;
    1415 }
    1416
    1417 /* compute subtree gaps in original space; sum them up */
    1418 for( l = 0; l < ssg->nsubtrees; ++l )
    1419 {
    1420 SCIP_Real subtreegap;
    1421 NODEINFO* nodeinfo;
    1422
    1423 assert(ssg->subtreepqueues[l] != NULL);
    1424
    1425 nodeinfo = (NODEINFO*)SCIPpqueueFirst(ssg->subtreepqueues[l]);
    1426
    1427 /* skip subtrees with infinite lower bound; they are empty and contribute 0.0 to the gap sum term */
    1428 if( nodeinfo == NULL || SCIPisInfinity(scip, nodeinfo->lowerbound) )
    1429 continue;
    1430
    1431 subtreegap = calcGap(scip, nodeinfo->lowerbound);
    1432
    1433 gapsum += subtreegap;
    1434 }
    1435
    1436 /* update the scaling factor by using the previous SSG value divided by the current gapsum */
    1437 if( updatescaling )
    1438 {
    1439 ssg->scalingfactor = ssg->value / MAX(gapsum, 1e-6);
    1440 }
    1441
    1442 /* update and store SSG value by considering scaling factor */
    1443 ssg->value = ssg->scalingfactor * gapsum;
    1444
    1445 return SCIP_OKAY;
    1446}
    1447
    1448/** update the subtree sum gap after a node event (branching or deletion of a node) */
    1449static
    1451 SCIP* scip, /**< SCIP data structure */
    1452 SUBTREESUMGAP* ssg, /**< subtree sum gap data structure */
    1453 SCIP_NODE* node, /**< the corresponding node */
    1454 int nchildren, /**< number of children */
    1455 SCIP_Longint nsolvednodes /**< number of solved nodes so far, used as a time stamp */
    1456 )
    1457{
    1458 SCIP_Bool insertchildren = (ssg->nsubtrees > 1 && nchildren > 0);
    1459
    1460 /* if the instance is solved or a node is cutoff at the initsolve stage or we are unbounded, the ssg is 0 */
    1462 {
    1463 ssg->value = 0.0;
    1464
    1465 return SCIP_OKAY;
    1466 }
    1467
    1468 /* make a new tree split if the primal bound has changed. */
    1470 {
    1471 int nnewsubtrees;
    1472 SCIP_Bool addfocusnode;
    1473
    1475 nnewsubtrees = SCIPgetNSiblings(scip) + SCIPgetNLeaves(scip) + SCIPgetNChildren(scip) + (addfocusnode ? 1 : 0);
    1476
    1477 /* check if number of new subtrees does not exceed maximum number of subtrees; always split if no split happened, yet */
    1478 if( ssg->nsubtrees <= 1 ||
    1479 ((ssg->nmaxsubtrees == -1 || nnewsubtrees <= ssg->nmaxsubtrees) &&
    1480 (nsolvednodes - ssg->nodelastsplit >= ssg->nminnodeslastsplit)) )
    1481 {
    1482 SCIP_CALL( subtreeSumGapSplit(scip, ssg, addfocusnode) );
    1483
    1484 /* remember time stamp */
    1485 ssg->nodelastsplit = nsolvednodes;
    1486 }
    1487 else
    1488 {
    1489 if( ssg->nmaxsubtrees != -1 && nnewsubtrees >= ssg->nmaxsubtrees )
    1490 {
    1491 SCIPdebugMsg(scip, "Keep split into %d subtrees because new split into %d subtrees exceeds limit %d\n",
    1492 ssg->nsubtrees, nnewsubtrees, ssg->nmaxsubtrees);
    1493 }
    1494 else
    1495 {
    1496 SCIPdebugMsg(scip, "Keep split into %d subtrees from %" SCIP_LONGINT_FORMAT " nodes ago\n",
    1497 ssg->nsubtrees, nsolvednodes - ssg->nodelastsplit);
    1498 }
    1499
    1500 /* no new split has happened; insert the new children to their SSG subtree */
    1501 if( insertchildren )
    1502 {
    1504 }
    1505 }
    1506
    1508
    1509 /* compute the current SSG value from scratch */
    1511 }
    1512 /* otherwise, if new children have been created, label them */
    1513 else if( insertchildren )
    1514 {
    1516 }
    1517
    1518 /* remove the node from the hash map if it is a leaf */
    1519 if( nchildren == 0 )
    1520 {
    1521 SCIP_CALL( subtreeSumGapRemoveNode(scip, ssg, node) );
    1522 }
    1523
    1524 return SCIP_OKAY;
    1525}
    1526
    1527/** reset tree data */
    1528static
    1530 SCIP* scip, /**< SCIP data structure */
    1531 TREEDATA* treedata /**< tree data */
    1532 )
    1533{
    1534 /* simply set everything to 0 */
    1535 treedata->ninner = treedata->nleaves = treedata->nvisited = 0L;
    1536 treedata->weight = 0.0;
    1537
    1538 /* set up root node */
    1539 treedata->nnodes = 1;
    1540 treedata->nopen = 1;
    1541
    1542 SCIP_CALL( subtreeSumGapReset(scip, treedata->ssg) );
    1543
    1544 return SCIP_OKAY;
    1545}
    1546
    1547/** create tree data structure */
    1548static
    1550 SCIP* scip, /**< SCIP data structure */
    1551 TREEDATA** treedata /**< pointer to store tree data */
    1552 )
    1553{
    1554 assert(treedata != NULL);
    1555 assert(scip != NULL);
    1556
    1557 SCIP_CALL( SCIPallocMemory(scip, treedata) );
    1558
    1559 SCIP_CALL( subtreeSumGapCreate(scip, &(*treedata)->ssg) );
    1560
    1561 SCIP_CALL( resetTreeData(scip, *treedata) );
    1562
    1563 return SCIP_OKAY;
    1564}
    1565
    1566/** free tree data structure */
    1567static
    1569 SCIP* scip, /**< SCIP data structure */
    1570 TREEDATA** treedata /**< pointer to tree data */
    1571 )
    1572{
    1573 assert(scip != NULL);
    1574
    1575 if( *treedata == NULL )
    1576 return;
    1577
    1578 subtreeSumGapFree(scip, &(*treedata)->ssg);
    1579
    1580 SCIPfreeMemory(scip, treedata);
    1581 *treedata = NULL;
    1582}
    1583
    1584/** update tree data structure after a node has been solved/is about to be deleted */
    1585static
    1587 SCIP* scip, /**< SCIP data structure */
    1588 TREEDATA* treedata, /**< tree data */
    1589 SCIP_NODE* node, /**< the corresponding node */
    1590 int nchildren /**< the number of children */
    1591 )
    1592{
    1593 assert(node != NULL);
    1594
    1595 ++treedata->nvisited;
    1596 treedata->nopen--;
    1597
    1598 if( nchildren == 0 )
    1599 {
    1600 int depth = SCIPnodeGetDepth(node);
    1601 treedata->nleaves++;
    1602 treedata->weight += pow(0.5, (SCIP_Real)depth);
    1603 }
    1604 else
    1605 {
    1606 treedata->nnodes += nchildren;
    1607 treedata->nopen += nchildren;
    1608 ++treedata->ninner;
    1609 }
    1610
    1611 /* update the subtree sum gap */
    1612 if( ! SCIPisInRestart(scip) )
    1613 {
    1614 SCIP_CALL( subtreeSumGapUpdate(scip, treedata->ssg, node, nchildren, treedata->nvisited) );
    1615 }
    1616
    1617 return SCIP_OKAY;
    1618}
    1619
    1620/** get weighted backtrack estimation from this tree data */
    1621static
    1623 TREEDATA* treedata /**< tree data */
    1624 )
    1625{
    1626 if( treedata->weight <= 0.0 || treedata->nleaves == 0 )
    1627 return -1.0;
    1628
    1629 return 2.0 * treedata->nleaves / (SCIP_Real)treedata->weight - 1.0;
    1630}
    1631
    1632#ifdef SCIP_DEBUG
    1633/* print method for tree data */
    1634static
    1635char* treeDataPrint(
    1636 TREEDATA* treedata, /**< tree data */
    1637 char* strbuf /**< string buffer */
    1638 )
    1639{
    1640 (void )SCIPsnprintf(strbuf, SCIP_MAXSTRLEN,
    1641 "Tree Data: %" SCIP_LONGINT_FORMAT " nodes ("
    1642 "%" SCIP_LONGINT_FORMAT " visited, "
    1643 "%" SCIP_LONGINT_FORMAT " inner, "
    1644 "%" SCIP_LONGINT_FORMAT " leaves, "
    1645 "%" SCIP_LONGINT_FORMAT " open), "
    1646 "weight: %.4Lf, ssg %.4f",
    1647 treedata->nnodes,
    1648 treedata->nvisited,
    1649 treedata->ninner,
    1650 treedata->nleaves,
    1651 treedata->nopen,
    1652 treedata->weight,
    1653 treedata->ssg->value
    1654 );
    1655 return strbuf;
    1656}
    1657#endif
    1658
    1659/** reset double exponential smoothing */
    1660static
    1662 DOUBLEEXPSMOOTH* des, /**< double exponential smoothing data structure */
    1663 SCIP_Real initialvalue /**< the initial value */
    1664 )
    1665{
    1666 des->n = 0;
    1667 des->level = SCIP_INVALID;
    1668 des->trend = SCIP_INVALID;
    1669 des->initialvalue = initialvalue;
    1670}
    1671
    1672/** initialize a double exponential smoothing data structure */
    1673static
    1675 DOUBLEEXPSMOOTH* des, /**< double exponential smoothing data structure */
    1676 SCIP_Real x1 /**< the first sample value */
    1677 )
    1678{
    1679 assert(des != NULL);
    1680
    1681 des->n = 1;
    1682 des->level = x1;
    1683 des->trend = x1 - des->initialvalue;
    1684
    1686
    1687 return;
    1688}
    1689
    1690/** update a double exponential smoothing data structure */
    1691static
    1693 DOUBLEEXPSMOOTH* des, /**< double exponential smoothing data structure */
    1694 SCIP_Real xnew /**< new sample value */
    1695 )
    1696{
    1697 if( des->n == 0 )
    1698 doubleExpSmoothInit(des, xnew);
    1699 else
    1700 {
    1701 SCIP_Real newlevel;
    1702 SCIP_Real newtrend;
    1703
    1704 newlevel = des->alpha * xnew + (1.0 - des->alpha) * (des->level + (des->usetrendinlevel ? des->trend : 0.0));
    1705 newtrend = des->beta * (newlevel - des->level) + (1.0 - des->beta) * des->trend;
    1706
    1707 des->level = newlevel;
    1708 des->trend = newtrend;
    1709 }
    1710}
    1711
    1712/** get the current trend (slope) computed by this double exponential smoothing */
    1713static
    1715 DOUBLEEXPSMOOTH* des /**< double exponential smoothing data structure */
    1716 )
    1717{
    1718 assert(des != NULL);
    1719
    1720 if( des->n == 0 )
    1721 return SCIP_INVALID;
    1722
    1723 return des->trend;
    1724}
    1725
    1726/** reset time series */
    1727static
    1729 TIMESERIES* timeseries /**< pointer to store time series */
    1730 )
    1731{
    1732 timeseries->resolution = 1;
    1733 timeseries->nvals = 0;
    1734 timeseries->nobs = 0L;
    1735 timeseries->currentvalue = timeseries->initialvalue;
    1736 timeseries->smoothestimation = SCIP_INVALID;
    1737
    1738 doubleExpSmoothReset(&timeseries->des, timeseries->initialvalue);
    1739}
    1740
    1741/** create a time series object */
    1742static
    1744 SCIP* scip, /**< SCIP data structure */
    1745 TIMESERIES** timeseries, /**< pointer to store time series */
    1746 const char* name, /**< name of this time series */
    1747 SCIP_Real targetvalue, /**< target value of this time series */
    1748 SCIP_Real initialvalue, /**< the initial value of time series */
    1749 SCIP_Real alpha, /**< alpha parameter (level weight) for double exponential smoothing */
    1750 SCIP_Real beta, /**< beta parameter (level weight) for double exponential smoothing */
    1751 DECL_TIMESERIESUPDATE ((*timeseriesupdate)) /**< update callback at nodes, or NULL */
    1752 )
    1753{
    1754 TIMESERIES* timeseriesptr;
    1755 assert(scip != NULL);
    1756 assert(timeseries != NULL);
    1757 assert(name != NULL);
    1758 assert(alpha >= 0.0 && alpha <= 1);
    1759 assert(beta >= 0.0 && beta <= 1);
    1760
    1761 SCIP_CALL( SCIPallocMemory(scip, timeseries) );
    1762
    1763 timeseriesptr = *timeseries;
    1764 assert(timeseriesptr != NULL);
    1765
    1766 /* copy name */
    1767 SCIP_ALLOC( BMSduplicateMemoryArray(&timeseriesptr->name, name, strlen(name)+1) );
    1768
    1769 /* copy callbacks */
    1770 assert(timeseriesupdate != NULL);
    1771 timeseriesptr->timeseriesupdate = timeseriesupdate;
    1772
    1773 timeseriesptr->targetvalue = targetvalue;
    1774 timeseriesptr->valssize = 1024;
    1775 timeseriesptr->initialvalue = initialvalue;
    1776
    1777 SCIP_CALL( SCIPallocMemoryArray(scip, &timeseriesptr->vals, timeseriesptr->valssize) );
    1778 SCIP_CALL( SCIPallocMemoryArray(scip, &timeseriesptr->estimation, timeseriesptr->valssize) );
    1779
    1780 timeSeriesReset(timeseriesptr);
    1781
    1782 timeseriesptr->des.alpha = alpha;
    1783 timeseriesptr->des.beta = beta;
    1784
    1785 SCIPdebugMsg(scip, "Finished creation of time series '%s'\n", timeseriesptr->name);
    1786
    1787 return SCIP_OKAY;
    1788}
    1789
    1790/** free a time series */
    1791static
    1793 SCIP* scip, /**< SCIP data structure */
    1794 TIMESERIES** timeseries /**< pointer to time series */
    1795 )
    1796{
    1797 assert(scip != NULL);
    1798 assert(timeseries != NULL);
    1799
    1800 BMSfreeMemoryArray(&(*timeseries)->name);
    1801
    1802 SCIPfreeMemoryArray(scip, &(*timeseries)->vals);
    1803 SCIPfreeMemoryArray(scip, &(*timeseries)->estimation);
    1804
    1805 SCIPfreeMemory(scip, timeseries);
    1806
    1807 *timeseries = NULL;
    1808}
    1809
    1810/** get current value of time series */
    1811static
    1813 TIMESERIES* timeseries /**< time series */
    1814 )
    1815{
    1816 assert(timeseries != NULL);
    1817
    1818 return timeseries->currentvalue;
    1819}
    1820
    1821/** get target value (which this time series reaches at the end of the solution process) */
    1822static
    1824 TIMESERIES* timeseries /**< time series */
    1825 )
    1826{
    1827 return timeseries->targetvalue;
    1828}
    1829
    1830/** get resolution of time series */
    1831static
    1833 TIMESERIES* timeseries /**< time series */
    1834 )
    1835{
    1836 return timeseries->resolution;
    1837}
    1838
    1839/** estimate tree size at which time series reaches target value */
    1840static
    1842 TIMESERIES* timeseries, /**< time series */
    1843 TREEDATA* treedata /**< tree data for fallback estimation */
    1844 )
    1845{
    1846 SCIP_Real val;
    1847 SCIP_Real targetval;
    1848 SCIP_Real trend;
    1849 SCIP_Real estimated;
    1850 const SCIP_Real tolerance = 1e-6;
    1851
    1852 /* if no observations have been made yet, return infinity */
    1853 if( timeseries->nobs == 0L )
    1854 return -1.0;
    1855
    1856 val = timeSeriesGetValue(timeseries);
    1857 targetval = timeSeriesGetTargetValue(timeseries);
    1858
    1859 /* if the value has reached the target value already, return the number of observations */
    1860 if( EPSZ(val - targetval, tolerance) )
    1861 return treedata->nnodes;
    1862
    1863 trend = doubleExpSmoothGetTrend(&timeseries->des);
    1864
    1865 /* Get current value and trend. The linear trend estimation may point into the wrong direction
    1866 * In this case, we use the fallback mechanism that we will need twice as many nodes.
    1867 */
    1868 if( (targetval > val && trend < tolerance) || (targetval < val && trend > -tolerance) )
    1869 {
    1870 return 2.0 * treedata->nvisited;
    1871 }
    1872
    1873 /* compute after how many additional steps the current trend reaches the target value; multiply by resolution */
    1874 estimated = timeSeriesGetResolution(timeseries) * (timeseries->nvals + (targetval - val) / (SCIP_Real)trend);
    1875 return timeseries->useleafts ? 2.0 * estimated - 1.0 : estimated;
    1876}
    1877
    1878/** update time series smoothened estimation */
    1879static
    1881 TIMESERIES* timeseries, /**< time series */
    1882 SCIP_Real estimation /**< estimation value */
    1883 )
    1884{
    1885 if( timeseries->smoothestimation == SCIP_INVALID )/*lint !e777*/
    1886 timeseries->smoothestimation = estimation;
    1887 else
    1888 {
    1889 timeseries->smoothestimation *= (1.0 - SESCOEFF);
    1890 timeseries->smoothestimation += SESCOEFF * estimation;
    1891 }
    1892}
    1893
    1894/** get smooth estimation of time series */
    1895static
    1897 TIMESERIES* timeseries /**< time series */
    1898 )
    1899{
    1900 return timeseries->smoothestimation;
    1901}
    1902
    1903/** resample to lower resolution */
    1904static
    1906 TIMESERIES* timeseries /**< time series */
    1907 )
    1908{
    1909 DOUBLEEXPSMOOTH* des;
    1910 int i;
    1911
    1912 assert(timeseries->nvals % 2 == 0);
    1913
    1914 des = &timeseries->des;
    1915 doubleExpSmoothReset(des, timeseries->initialvalue);
    1916
    1917 /* compress vals array to store only every second entry */
    1918 for( i = 0; i < timeseries->nvals / 2; ++i )
    1919 {
    1920 timeseries->vals[i] = timeseries->vals[2 * i];
    1921 timeseries->estimation[i] = timeseries->estimation[2 * i];
    1922 doubleExpSmoothUpdate(des, timeseries->vals[i]);
    1923 timeSeriesUpdateSmoothEstimation(timeseries, timeseries->estimation[i]);
    1924 }
    1925
    1926 timeseries->resolution *= 2;
    1927 timeseries->nvals = timeseries->nvals / 2;
    1928}
    1929
    1930/** update time series */
    1931static
    1933 SCIP* scip, /**< SCIP data structure */
    1934 TIMESERIES* timeseries, /**< time series */
    1935 TREEDATA* treedata, /**< tree data */
    1936 SCIP_Bool isleaf /**< are we at a leaf node? */
    1937 )
    1938{
    1939 SCIP_Real value;
    1940
    1941 assert(scip != NULL);
    1942 assert(timeseries != NULL);
    1943 assert(treedata != NULL);
    1944
    1945 /* call update callback */
    1946 assert(timeseries->timeseriesupdate != NULL);
    1947 SCIP_CALL( timeseries->timeseriesupdate(scip, timeseries, treedata, &value) );
    1948
    1949 /* store the value as current value */
    1950 timeseries->currentvalue = value;
    1951
    1952 if( timeseries->useleafts && ! isleaf )
    1953 return SCIP_OKAY;
    1954
    1955 timeseries->nobs++;
    1956
    1957 /* if this is a leaf that matches the time series resolution, store the value */
    1958 if( timeseries->nobs % timeseries->resolution == 0 )
    1959 {
    1960 int tspos;
    1961 SCIP_Real estimate;
    1962
    1963 assert(timeseries->nvals < timeseries->valssize);
    1964 tspos = timeseries->nvals++;
    1965 timeseries->vals[tspos] = value;
    1966 doubleExpSmoothUpdate(&timeseries->des, value);
    1967 estimate = timeSeriesEstimate(timeseries, treedata);
    1968 timeseries->estimation[tspos] = estimate;
    1969 timeSeriesUpdateSmoothEstimation(timeseries, estimate);
    1970 }
    1971
    1972 /* if the time series has reached its capacity, resample and increase the resolution */
    1973 if( timeseries->nvals == timeseries->valssize )
    1974 timeSeriesResample(timeseries);
    1975
    1976 return SCIP_OKAY;
    1977}
    1978
    1979/** get name of time series */
    1980static
    1982 TIMESERIES* timeseries /**< time series */
    1983 )
    1984{
    1985 return timeseries->name;
    1986}
    1987
    1988/** reset all time series */
    1989static
    1991 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */
    1992 )
    1993{
    1994 TIMESERIES** tss = eventhdlrdata->timeseries;
    1995 int t;
    1996
    1997 /* loop over time series and reset them */
    1998 for( t = 0; t < NTIMESERIES; ++t )
    1999 {
    2000 assert(tss[t] != NULL);
    2001 timeSeriesReset(tss[t]);
    2002
    2003 tss[t]->useleafts = eventhdlrdata->useleafts;
    2004 }
    2005}
    2006
    2007/*
    2008 * Callback methods of event handler
    2009 */
    2010
    2011/** free all time series */
    2012static
    2014 SCIP* scip, /**< SCIP data structure */
    2015 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */
    2016 )
    2017{
    2018 TIMESERIES** tss = eventhdlrdata->timeseries;
    2019 int t;
    2020
    2021 /* loop over time series and reset them */
    2022 for( t = 0; t < NTIMESERIES; ++t )
    2023 {
    2024 assert(tss[t] != NULL);
    2025 timeSeriesFree(scip, &tss[t]);
    2026 }
    2027}
    2028
    2029/** get ensemble tree size estimation as a combination of the individual time series estimations
    2030 *
    2031 * the coefficients have been computed based on a nonlinear fit on a broad set of publicly available
    2032 * MIP instances; please refer to the publication at the top of this file for further details.
    2033 */
    2034static
    2036 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */
    2037 )
    2038{
    2039 TREEDATA* treedata;
    2040 SCIP_Real* coeffs;
    2041 SCIP_Real estim;
    2042 int t;
    2043
    2044 TSPOS tsposs[] = {
    2045 TSPOS_GAP,
    2048 TSPOS_SSG,
    2050 };
    2051
    2052 /* coefficients for the early stage (tree weight <= 0.3) */
    2053 SCIP_Real coeffs_early[] = {
    2054 0.002, /* gap */
    2055 0.381, /* tree weight */
    2056 0.469, /* leaf-frequency */
    2057 0.292, /* SSG */
    2058 0.004 /* open-nodes */
    2059 };
    2060
    2061 /* coefficients for the intermediate stage (0.3 < tree weight <= 0.6) */
    2062 SCIP_Real coeffs_intermediate[] = {
    2063 0.011, /* gap */
    2064 0.193, /* tree weight */
    2065 0.351, /* leaf-frequency */
    2066 0.012, /* SSG */
    2067 0.051 /* open-nodes */
    2068 };
    2069
    2070 /* coefficients for the late stage (tree weight > 0.6) */
    2071 SCIP_Real coeffs_late[] = {
    2072 0.000, /* gap */
    2073 0.033, /* tree weight */
    2074 0.282, /* leaf-frequency */
    2075 0.003, /* SSG */
    2076 0.024 /* open-nodes */
    2077 };
    2078
    2079 assert(eventhdlrdata != NULL);
    2080 treedata = eventhdlrdata->treedata;
    2081
    2082 /* assign coeffs based on stage */
    2083 if( treedata->weight <= 0.3 )
    2084 {
    2085 estim = 0.0;
    2086 coeffs = coeffs_early;
    2087 /* ensure that coeffs and time series are still aligned */
    2088 assert(sizeof(coeffs_early)/sizeof(SCIP_Real) == NTIMESERIES); /*lint !e506*/
    2089 }
    2090 else if( treedata->weight <= 0.6 )
    2091 {
    2092 coeffs = coeffs_intermediate;
    2093 /* ensure that coeffs and time series are still aligned */
    2094 assert(sizeof(coeffs_intermediate)/sizeof(SCIP_Real) == NTIMESERIES); /*lint !e506*/
    2095
    2096 /* initialize by intermediate WBE coefficient */
    2097 estim = 0.156 * treeDataGetWbe(treedata);
    2098 }
    2099 else
    2100 {
    2101 coeffs = coeffs_late;
    2102 /* ensure that coeffs and time series are still aligned */
    2103 assert(sizeof(coeffs_late)/sizeof(SCIP_Real) == NTIMESERIES); /*lint !e506*/
    2104
    2105 /* initialize by late WBE coefficient */
    2106 estim = 0.579 * treeDataGetWbe(treedata);
    2107 }
    2108
    2109 /* combine estimation using the stage-dependent coefficients */
    2110 for( t = 0; t < NTIMESERIES; ++t )
    2111 {
    2112 SCIP_Real testim;
    2113 TSPOS tspos = tsposs[t];
    2114 testim = timeSeriesEstimate(eventhdlrdata->timeseries[tspos], treedata);
    2115
    2116 if( testim < 0.0 )
    2117 testim = treedata->nnodes;
    2118
    2119 estim += coeffs[t] * testim;
    2120 }
    2121
    2122 if( estim < treedata->nnodes )
    2123 return (SCIP_Real)treedata->nnodes;
    2124 else
    2125 return estim;
    2126}
    2127
    2128/** get approximation of search tree completion depending on the selected method */
    2129static
    2131 SCIP_EVENTHDLRDATA* eventhdlrdata, /**< event handler data */
    2132 SCIP_Real* completed /**< pointer to store the search tree completion */
    2133 )
    2134{
    2135 SCIP_Real values[9];
    2136 TREEDATA* treedata;
    2137 char completiontype;
    2138
    2139 assert(eventhdlrdata != NULL);
    2140 treedata = eventhdlrdata->treedata;
    2141 completiontype = eventhdlrdata->completiontypeparam;
    2142
    2143 /* infer automatic completion type
    2144 *
    2145 * use regression forest if available,
    2146 * or
    2147 * use monotone regression if both SSG and tree weight are meaningful;
    2148 * or
    2149 * use tree weight or SSG, depending which one is available,
    2150 * or
    2151 * use gap, which is always available
    2152 */
    2153 if( completiontype == COMPLETIONTYPE_AUTO )
    2154 {
    2155 SCIP_Bool useweight = eventhdlrdata->treeisbinary;
    2156 SCIP_Bool usessg = treedata->ssg->pblastsplit != SSG_STARTPRIMBOUND;/*lint !e777*/
    2157
    2158 if( eventhdlrdata->regforest != NULL )
    2159 completiontype = COMPLETIONTYPE_REGFOREST;
    2160 else if( useweight && usessg )
    2161 completiontype = COMPLETIONTYPE_MONOREG;
    2162 else if( useweight )
    2163 completiontype = COMPLETIONTYPE_TREEWEIGHT;
    2164 else if( usessg )
    2165 completiontype = COMPLETIONTYPE_SSG;
    2166 else
    2167 completiontype = COMPLETIONTYPE_GAP;
    2168 }
    2169
    2170 /* compute the search tree completion based on the selected method */
    2171 switch (completiontype)
    2172 {
    2173 /* use regression forest */
    2175 values[0] = timeSeriesGetValue(eventhdlrdata->timeseries[TSPOS_TREEWEIGHT]);
    2176 values[1] = doubleExpSmoothGetTrend(&eventhdlrdata->timeseries[TSPOS_TREEWEIGHT]->des);
    2177 values[2] = timeSeriesGetValue(eventhdlrdata->timeseries[TSPOS_SSG]);
    2178 values[3] = doubleExpSmoothGetTrend(&eventhdlrdata->timeseries[TSPOS_SSG]->des);
    2179 values[4] = timeSeriesGetValue(eventhdlrdata->timeseries[TSPOS_LFREQ]);
    2180 values[5] = doubleExpSmoothGetTrend(&eventhdlrdata->timeseries[TSPOS_LFREQ]->des);
    2181 values[6] = timeSeriesGetValue(eventhdlrdata->timeseries[TSPOS_GAP]);
    2182 values[7] = doubleExpSmoothGetTrend(&eventhdlrdata->timeseries[TSPOS_GAP]->des);
    2183 values[8] = doubleExpSmoothGetTrend(&eventhdlrdata->timeseries[TSPOS_OPEN]->des) < 0 ? 1.0 : 0.0;
    2184
    2185 *completed = SCIPregForestPredict(eventhdlrdata->regforest, values);
    2186 break;
    2187
    2188 /* interpolate between ssg and tree weight */
    2190 *completed = eventhdlrdata->coefmonoweight * (SCIP_Real)treedata->weight +
    2191 eventhdlrdata->coefmonossg * (1.0 - treedata->ssg->value);
    2192 break;
    2193
    2195 *completed = (SCIP_Real)treedata->weight;
    2196 break;
    2197
    2198 case COMPLETIONTYPE_GAP:
    2199 *completed = timeSeriesGetValue(eventhdlrdata->timeseries[TSPOS_GAP]); /* gap is stored as 1 - gap */
    2200 break;
    2201
    2202 case COMPLETIONTYPE_SSG:
    2203 *completed = 1.0 - treedata->ssg->value; /* ssg is decreasing */
    2204 break;
    2205
    2206 default:
    2207 SCIPerrorMessage("Unsupported completion type '%c'\n", completiontype);
    2208 SCIPABORT();
    2210 }
    2211 return SCIP_OKAY;
    2212}
    2213
    2214/** tree size estimation based on search tree completion */
    2215static
    2217 SCIP* scip, /**< SCIP data structure */
    2218 SCIP_EVENTHDLRDATA* eventhdlrdata, /**< event handler data */
    2219 SCIP_Real* estim /**< pointer to store the estimation value */
    2220 )
    2221{
    2222 SCIP_Real completed;
    2223
    2224 *estim = -1.0;
    2225
    2226 SCIP_CALL( getSearchCompletion(eventhdlrdata, &completed) );
    2227
    2228 completed = MIN(completed, 1.0);
    2229
    2230 if( completed > 0.0 )
    2231 *estim = SCIPgetNNodes(scip) / completed;
    2232
    2233 return SCIP_OKAY;
    2234}
    2235
    2236/** update callback at nodes */
    2237static
    2238DECL_TIMESERIESUPDATE(timeseriesUpdateGap)
    2239{ /*lint --e{715}*/
    2240 SCIP_Real primalbound;
    2241 SCIP_Real dualbound;
    2242
    2243 assert(scip != NULL);
    2244 assert(ts != NULL);
    2245 assert(value != NULL);
    2246
    2247 /* avoid to call SCIPgetDualbound during a restart where the queue is simply emptied */
    2248 if( SCIPisInRestart(scip) )
    2249 {
    2250 *value = timeSeriesGetValue(ts);
    2251
    2252 return SCIP_OKAY;
    2253 }
    2254
    2255 primalbound = SCIPgetPrimalbound(scip);
    2256 dualbound = SCIPgetDualbound(scip);
    2257 if( SCIPisInfinity(scip, REALABS(primalbound)) || SCIPisInfinity(scip, REALABS(dualbound)) )
    2258 *value = 0;
    2259 else if( SCIPisEQ(scip, primalbound, dualbound) )
    2260 *value = 1.0;
    2261 else
    2262 {
    2263 SCIP_Real abspb;
    2264 SCIP_Real absdb;
    2265
    2266 abspb = REALABS(primalbound);
    2267 absdb = REALABS(dualbound);
    2268 *value = 1.0 - REALABS(primalbound - dualbound)/MAX(abspb, absdb);
    2269 }
    2270
    2271 /* using this max, we set the closed gap to 0 in the case where the primal and dual bound differ in their sign */
    2272 *value = MAX(*value, 0.0);
    2273
    2274 return SCIP_OKAY;
    2275}
    2276
    2277/** update callback at nodes */
    2278static
    2279DECL_TIMESERIESUPDATE(timeseriesUpdateTreeWeight)
    2280{ /*lint --e{715}*/
    2281 *value = (SCIP_Real)treedata->weight;
    2282
    2283 return SCIP_OKAY;
    2284}
    2285
    2286/** update callback at nodes */
    2287static
    2288DECL_TIMESERIESUPDATE(timeseriesUpdateLeafFreq)
    2289{ /*lint --e{715}*/
    2290 if( treedata->nvisited == 0 )
    2291 *value = -0.5;
    2292 else
    2293 *value = (treedata->nleaves - 0.5)/(SCIP_Real)treedata->nvisited;
    2294
    2295 return SCIP_OKAY;
    2296}
    2297
    2298/** update callback at nodes */
    2299static
    2300DECL_TIMESERIESUPDATE(timeseriesUpdateSsg)
    2301{ /*lint --e{715}*/
    2302 if( treedata->nvisited == 0 )
    2303 *value = 1.0;
    2304 else
    2305 *value = treedata->ssg->value;
    2306
    2307 return SCIP_OKAY;
    2308}
    2309
    2310/** update callback at nodes */
    2311static
    2312DECL_TIMESERIESUPDATE(timeseriesUpdateOpenNodes)
    2313{ /*lint --e{715}*/
    2314 if( treedata->nvisited == 0 )
    2315 *value = 0.0;
    2316 else
    2317 *value = (SCIP_Real)treedata->nopen;
    2318
    2319 return SCIP_OKAY;
    2320}
    2321
    2322/** include time series to forecast into event handler */
    2323static
    2325 SCIP* scip, /**< SCIP data structure */
    2326 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */
    2327 )
    2328{
    2329 assert(scip != NULL);
    2330 assert(eventhdlrdata != NULL);
    2331
    2332 /* include gap time series */
    2333 SCIP_CALL( timeSeriesCreate(scip, &eventhdlrdata->timeseries[TSPOS_GAP], "gap", 1.0, 0.0,
    2334 DES_ALPHA_GAP, DES_BETA_GAP, timeseriesUpdateGap) );
    2335
    2336 /* include tree weight time series */
    2337 SCIP_CALL( timeSeriesCreate(scip, &eventhdlrdata->timeseries[TSPOS_TREEWEIGHT], "tree-weight", 1.0, 0.0,
    2338 DES_ALPHA_TREEWEIGHT, DES_BETA_TREEWEIGHT, timeseriesUpdateTreeWeight) );
    2339
    2340 /* include leaf time series */
    2341 SCIP_CALL( timeSeriesCreate(scip, &eventhdlrdata->timeseries[TSPOS_LFREQ], "leaf-frequency", 0.5, -0.5,
    2342 DES_ALPHA_LEAFFREQUENCY, DES_BETA_LEAFFREQUENCY, timeseriesUpdateLeafFreq) );
    2343
    2344 /* include SSG time series */
    2345 SCIP_CALL( timeSeriesCreate(scip, &eventhdlrdata->timeseries[TSPOS_SSG], "ssg", 0.0, 1.0,
    2346 DES_ALPHA_SSG, DES_BETA_SSG, timeseriesUpdateSsg) );
    2347
    2348 /* include open nodes time series */
    2349 SCIP_CALL( timeSeriesCreate(scip, &eventhdlrdata->timeseries[TSPOS_OPEN], "open-nodes", 0.0, 0.0,
    2350 DES_ALPHA_OPENNODES, DES_BETA_OPENNODES, timeseriesUpdateOpenNodes) );
    2351
    2352 return SCIP_OKAY;
    2353}
    2354
    2355/** get restartpolicy based on the value of the restart parameter */
    2356static
    2358 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */
    2359 )
    2360{
    2361 switch (eventhdlrdata->restartpolicyparam)
    2362 {
    2364 return RESTARTPOLICY_ALWAYS;
    2366 return RESTARTPOLICY_NEVER;
    2371 default:
    2372 SCIPerrorMessage("Unknown restart policy %c\n", eventhdlrdata->restartpolicyparam);
    2373 break;
    2374 }
    2375
    2376 return RESTARTPOLICY_NEVER;
    2377}
    2378
    2379/** check if a restart is applicable considering limit and threshold user parameters */
    2380static
    2382 SCIP* scip, /**< SCIP data structure */
    2383 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */
    2384 )
    2385{
    2387
    2388 /* if there are no root node integer fixings, restart is usually not helpful */
    2390 return FALSE;
    2391
    2392 /* check whether to apply restarts when there are active pricers available */
    2393 if( SCIPgetNActivePricers(scip) > 0 && ! eventhdlrdata->restartactpricers )
    2394 return FALSE;
    2395
    2396 /* check whether to apply a restart when nonlinear constraints are present */
    2397 if( SCIPisNLPConstructed(scip) && ! eventhdlrdata->restartnonlinear )
    2398 return FALSE;
    2399
    2400 /* check if max number of restarts has been reached */
    2401 if( eventhdlrdata->restartlimit != -1 && eventhdlrdata->nrestartsperformed >= eventhdlrdata->restartlimit )
    2402 return FALSE;
    2403
    2404 /* check if number of nodes exceeds the minimum number of nodes */
    2405 if( eventhdlrdata->countonlyleaves )
    2406 nnodes = eventhdlrdata->treedata->nleaves;
    2407 else
    2408 nnodes = eventhdlrdata->treedata->nvisited;
    2409
    2410 if( nnodes < eventhdlrdata->minnodes )
    2411 return FALSE;
    2412
    2413 return TRUE;
    2414}
    2415
    2416/** should a restart be applied based on the value of the selected completion method? */ /*lint --e{715}*/
    2417static
    2419 SCIP* scip, /**< SCIP data structure */
    2420 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */
    2421 )
    2422{ /*lint --e{715}*/
    2423 SCIP_Real completion;
    2424
    2425 SCIP_CALL_ABORT( getSearchCompletion(eventhdlrdata, &completion) );
    2426
    2427 /* if the estimation exceeds the current number of nodes by a dramatic factor, restart */
    2428 if( completion < 1.0 / eventhdlrdata->restartfactor )
    2429 {
    2432 "Completion %.5f less than restart threshold %.5f\n",
    2433 completion, 1.0 / eventhdlrdata->restartfactor);
    2434 )
    2435
    2436 return TRUE;
    2437 }
    2438
    2439 return FALSE;
    2440}
    2441
    2442/** should a restart be applied based on the value of the selected completion method? */
    2443static
    2445 SCIP* scip, /**< SCIP data structure */
    2446 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */
    2447 )
    2448{
    2449 SCIP_Real estimation;
    2450
    2451 estimation = SCIPgetTreesizeEstimation(scip);
    2452
    2453 if( estimation < 0.0 )
    2454 {
    2457 "Estimation %g is still unavailable\n",
    2458 estimation);
    2459 )
    2460
    2461 return TRUE;
    2462 }
    2463
    2464 /* if the estimation exceeds the current number of nodes by a dramatic factor, restart */
    2465 if( estimation > eventhdlrdata->treedata->nnodes * eventhdlrdata->restartfactor )
    2466 {
    2469 "Estimation %g exceeds number of estimation tree nodes %" SCIP_LONGINT_FORMAT " by a factor of %.1f\n",
    2470 estimation, eventhdlrdata->treedata->nnodes, estimation / eventhdlrdata->treedata->nnodes);
    2471 )
    2472
    2473 return TRUE;
    2474 }
    2475
    2476 return FALSE;
    2477}
    2478
    2479/** check if a restart should be performed based on the given restart policy */
    2480static
    2482 SCIP* scip, /**< SCIP data structure */
    2483 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */
    2484 )
    2485{
    2486 SCIP_Bool applyrestart = FALSE;
    2487
    2488 switch (getRestartPolicy(eventhdlrdata))
    2489 {
    2491 applyrestart = TRUE;
    2492 break;
    2494 applyrestart = FALSE;
    2495 break;
    2497 applyrestart = shouldApplyRestartCompletion(scip, eventhdlrdata);
    2498 break;
    2500 applyrestart = shouldApplyRestartEstimation(scip, eventhdlrdata);
    2501 break;
    2502 default:
    2503 break;
    2504 }
    2505
    2506 return applyrestart;
    2507}
    2508
    2509/** update all time series */
    2510static
    2512 SCIP* scip, /**< SCIP data structure */
    2513 SCIP_EVENTHDLRDATA* eventhdlrdata, /**< event handler data */
    2514 TREEDATA* treedata, /**< tree data */
    2515 SCIP_Bool isleaf /**< are we at a leaf node? */
    2516 )
    2517{
    2518 TIMESERIES** tss = eventhdlrdata->timeseries;
    2519 int t;
    2520
    2521 /* loop over time series */
    2522 for( t = 0; t < NTIMESERIES; ++t )
    2523 {
    2524 assert(tss[t] != NULL);
    2525 SCIP_CALL( timeSeriesUpdate(scip, tss[t], treedata, isleaf) );
    2526
    2527#ifdef SCIP_MORE_DEBUG
    2529 "Update of time series '%s', current value %.4f (%" SCIP_LONGINT_FORMAT " observations)\n",
    2530 timeSeriesGetName(tss[t]), timeSeriesGetValue(tss[t]), tss[t]->nobs);
    2531#endif
    2532 }
    2533
    2534 return SCIP_OKAY;
    2535}
    2536
    2537/** print a treesize estimation report into the string buffer */
    2538static
    2540 SCIP* scip, /**< SCIP data structure */
    2541 SCIP_EVENTHDLRDATA* eventhdlrdata, /**< event handler data */
    2542 char* strbuf, /**< string buffer */
    2543 int reportnum /**< report number, or 0 to omit number */
    2544 )
    2545{
    2546 TREEDATA* treedata = eventhdlrdata->treedata;
    2547 char* ptr = strbuf;
    2548 SCIP_Real completed;
    2549 SCIP_Real wbeestim;
    2550 char wbeestimstr[SCIP_MAXSTRLEN];
    2551 int t;
    2552
    2553 /* print report number */
    2554 if( reportnum > 0 )
    2555 ptr += SCIPsnprintf(ptr, SCIP_MAXSTRLEN, "Report %d\nTime Elapsed: %.2f\n", reportnum, SCIPgetSolvingTime(scip));
    2556
    2557 ptr += SCIPsnprintf(ptr, SCIP_MAXSTRLEN,
    2558 "Estim. Tree Size :%11" SCIP_LONGINT_FORMAT "\n",
    2560
    2561 SCIP_CALL_ABORT( getSearchCompletion(eventhdlrdata, &completed) );
    2562
    2563 completed = MIN(1.0, completed);
    2564 completed = MAX(0.0, completed);
    2565
    2566 /* print tree data */
    2567 ptr += SCIPsnprintf(ptr, SCIP_MAXSTRLEN,
    2568 "%-19s: %" SCIP_LONGINT_FORMAT " nodes ("
    2569 "%" SCIP_LONGINT_FORMAT " visited, "
    2570 "%" SCIP_LONGINT_FORMAT " internal, "
    2571 "%" SCIP_LONGINT_FORMAT " leaves, "
    2572 "%" SCIP_LONGINT_FORMAT " open), "
    2573 "weight: %.4Lf completed %.4f\n",
    2574 "Estimation Tree",
    2575 treedata->nnodes,
    2576 treedata->nvisited,
    2577 treedata->ninner,
    2578 treedata->nleaves,
    2579 treedata->nopen,
    2580 treedata->weight,
    2581 completed
    2582 );
    2583
    2584 /* print estimations */
    2585 ptr += SCIPsnprintf(ptr, SCIP_MAXSTRLEN, "Estimations : %10s %10s %10s %10s %10s",
    2586 "estim", "value", "trend", "resolution", "smooth");
    2587 ptr += SCIPsnprintf(ptr, SCIP_MAXSTRLEN, "\n");
    2588
    2589 wbeestim = treeDataGetWbe(eventhdlrdata->treedata);
    2590 ptr += SCIPsnprintf(ptr, SCIP_MAXSTRLEN, " wbe : %10s %10s %10s %10s %10s\n",
    2591 real2String(wbeestim, wbeestimstr, 0), "-", "-", "-", "-");
    2592
    2593 ptr += SCIPsnprintf(ptr, SCIP_MAXSTRLEN, " tree-profile : %10.0f %10s %10s %10s %10s\n",
    2594 predictTotalSizeTreeProfile(scip, eventhdlrdata->treeprofile, eventhdlrdata->treeprofile_minnodesperdepth),
    2595 "-", "-", "-", "-");
    2596
    2597 /* print time series forecasts */
    2598 for( t = 0; t < NTIMESERIES; ++t )
    2599 {
    2600 SCIP_Real trend;
    2601 SCIP_Real smoothestim;
    2602 TIMESERIES* ts = eventhdlrdata->timeseries[t];
    2603 char trendstr[SCIP_MAXSTRLEN];
    2604 char smoothestimstr[SCIP_MAXSTRLEN];
    2605
    2606 trend = doubleExpSmoothGetTrend(&ts->des);
    2607 smoothestim = timeSeriesGetSmoothEstimation(ts);
    2608
    2609 ptr += SCIPsnprintf(ptr, SCIP_MAXSTRLEN, " %-17s: %10.0f %10.5f %10s %10d %10s\n",
    2611 timeSeriesEstimate(ts, eventhdlrdata->treedata),
    2613 real2String(trend, trendstr, 5),
    2615 real2String(smoothestim, smoothestimstr, 0));
    2616 }
    2617
    2618 if( reportnum > 0 )
    2619 (void) SCIPsnprintf(ptr, SCIP_MAXSTRLEN, "End of Report %d\n", reportnum);
    2620}
    2621
    2622
    2623/** copy method for event handler plugins (called when SCIP copies plugins) */
    2624static
    2625SCIP_DECL_EVENTCOPY(eventCopyEstim)
    2626{ /*lint --e{715}*/
    2627 assert(scip != NULL);
    2628
    2630
    2631 return SCIP_OKAY;
    2632}
    2633
    2634/** destructor of event handler to free user data (called when SCIP is exiting) */
    2635static
    2636SCIP_DECL_EVENTFREE(eventFreeEstim)
    2637{ /*lint --e{715}*/
    2638 SCIP_EVENTHDLRDATA* eventhdlrdata;
    2639
    2640 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    2641 assert(eventhdlrdata != NULL);
    2642
    2643 freeTreeData(scip, &eventhdlrdata->treedata);
    2644
    2645 freeTimeSeries(scip, eventhdlrdata);
    2646
    2647 SCIPfreeMemory(scip, &eventhdlrdata);
    2648
    2649 return SCIP_OKAY;
    2650}
    2651
    2652/** initialization method of event handler (called after problem was transformed) */
    2653static
    2654SCIP_DECL_EVENTINIT(eventInitEstim)
    2655{ /*lint --e{715}*/
    2656 SCIP_EVENTHDLRDATA* eventhdlrdata;
    2657
    2658 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    2659 assert(eventhdlrdata != NULL);
    2660
    2661 /* test if user specified a regression forest */
    2662 if( 0 != strncmp(eventhdlrdata->regforestfilename, DEFAULT_REGFORESTFILENAME, strlen(DEFAULT_REGFORESTFILENAME)) )
    2663 {
    2664 SCIP_CALL( SCIPregForestFromFile(&eventhdlrdata->regforest, eventhdlrdata->regforestfilename) );
    2665 }
    2666
    2667 eventhdlrdata->lastrestartrun = 0;
    2668 eventhdlrdata->nrestartsperformed = 0;
    2669
    2670 return SCIP_OKAY;
    2671}
    2672
    2673/** deinitialization method of event handler (called before transformed problem is freed) */
    2674static
    2675SCIP_DECL_EVENTEXIT(eventExitEstim)
    2676{ /*lint --e{715}*/
    2677 SCIP_EVENTHDLRDATA* eventhdlrdata;
    2678
    2679 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    2680 assert(eventhdlrdata != NULL);
    2681
    2682 SCIPregForestFree(&eventhdlrdata->regforest);
    2683
    2684 return SCIP_OKAY;
    2685}
    2686
    2687/** solving process initialization method of event handler (called when branch and bound process is about to begin) */
    2688static
    2689SCIP_DECL_EVENTINITSOL(eventInitsolEstim)
    2690{ /*lint --e{715}*/
    2691 SCIP_EVENTHDLRDATA* eventhdlrdata;
    2692
    2693 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    2694 assert(eventhdlrdata != NULL);
    2695
    2696 eventhdlrdata->restarthitcounter = 0;
    2697 eventhdlrdata->weightlastreport = 0.0;
    2698 eventhdlrdata->nreports = 0;
    2699
    2700 /* reset tree data */
    2701 SCIP_CALL( resetTreeData(scip, eventhdlrdata->treedata) );
    2702
    2703 resetTimeSeries(eventhdlrdata);
    2704
    2706
    2707 if( eventhdlrdata->treeprofile_enabled )
    2708 {
    2709 SCIP_CALL( createTreeProfile(scip, &eventhdlrdata->treeprofile) );
    2710 }
    2711
    2712 eventhdlrdata->treeisbinary = TRUE;
    2713
    2714 return SCIP_OKAY;
    2715}
    2716
    2717/** solving process deinitialization method of event handler (called before branch and bound process data is freed) */
    2718static
    2719SCIP_DECL_EVENTEXITSOL(eventExitsolEstim)
    2720{ /*lint --e{715}*/
    2721 SCIP_EVENTHDLRDATA* eventhdlrdata;
    2722
    2723 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    2724 assert(eventhdlrdata != NULL);
    2725
    2726 if( eventhdlrdata->treeprofile != NULL )
    2727 freeTreeProfile(scip, &eventhdlrdata->treeprofile);
    2728
    2729 SCIP_CALL( SCIPdropEvent(scip, EVENTTYPE_ESTIM, eventhdlr, NULL, -1) );
    2730
    2731 return SCIP_OKAY;
    2732}
    2733
    2734/** execution method of event handler */
    2735static
    2736SCIP_DECL_EVENTEXEC(eventExecEstim)
    2737{ /*lint --e{715}*/
    2738 SCIP_EVENTHDLRDATA* eventhdlrdata;
    2739 SCIP_Bool isleaf;
    2740 SCIP_EVENTTYPE eventtype;
    2741 TREEDATA* treedata;
    2742 char strbuf[SCIP_MAXSTRLEN];
    2743
    2744 assert(scip != NULL);
    2745 assert(eventhdlr != NULL);
    2746
    2747 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    2748 assert(eventhdlrdata != NULL);
    2749 eventtype = SCIPeventGetType(event);
    2750 treedata = eventhdlrdata->treedata;
    2751
    2752 if( SCIPisExact(scip) )
    2753 return SCIP_OKAY;
    2754
    2755 /* actual leaf nodes for our tree data are children/siblings/leaves or the focus node itself (deadend)
    2756 * if it has not been branched on
    2757 */
    2758 isleaf = (eventtype == SCIP_EVENTTYPE_NODEDELETE) &&
    2763
    2764 if( eventtype == SCIP_EVENTTYPE_NODEBRANCHED || isleaf )
    2765 {
    2766 SCIP_NODE* eventnode;
    2767 int nchildren = 0;
    2768
    2769 if( eventtype == SCIP_EVENTTYPE_NODEBRANCHED )
    2770 {
    2771 nchildren = SCIPgetNChildren(scip);
    2772
    2773 /* update whether the tree is still binary */
    2774 if( nchildren != 2 )
    2775 eventhdlrdata->treeisbinary = FALSE;
    2776 }
    2777
    2778 eventnode = SCIPeventGetNode(event);
    2779 SCIP_CALL( updateTreeData(scip, treedata, eventnode, nchildren) );
    2780 SCIP_CALL( updateTreeProfile(scip, eventhdlrdata->treeprofile, eventnode) );
    2781
    2782#ifdef SCIP_DEBUG
    2783 SCIPdebugMsg(scip, "%s\n", treeDataPrint(treedata, strbuf));
    2784#endif
    2785
    2786 SCIP_CALL( updateTimeseries(scip, eventhdlrdata, treedata, nchildren == 0) );
    2787
    2788 /* should a new report be printed? */
    2789 if( eventhdlrdata->reportfreq >= 0 && SCIPgetStatus(scip) == SCIP_STATUS_UNKNOWN &&
    2790 (eventhdlrdata->reportfreq == 0
    2791 || treedata->weight >= eventhdlrdata->weightlastreport + 1.0 / (SCIP_Real)eventhdlrdata->reportfreq) )
    2792 {
    2793 printReport(scip, eventhdlrdata, strbuf, ++eventhdlrdata->nreports);
    2794 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "%s\n", strbuf);
    2795
    2796 if( eventhdlrdata->reportfreq > 0 )
    2797 eventhdlrdata->weightlastreport = 1 / (SCIP_Real)eventhdlrdata->reportfreq * SCIPfloor(scip, ((SCIP_Real)treedata->weight * eventhdlrdata->reportfreq));
    2798 else
    2799 eventhdlrdata->weightlastreport = (SCIP_Real)treedata->weight;
    2800 }
    2801 }
    2802
    2803 /* if nodes have been pruned, things are progressing, don't restart right now */
    2804 if( isleaf )
    2805 return SCIP_OKAY;
    2806
    2807 /* check if all conditions are met such that the event handler should run */
    2808 if( !isRestartApplicable(scip, eventhdlrdata) )
    2809 return SCIP_OKAY;
    2810
    2811 /* test if a restart should be applied */
    2812 if( shouldApplyRestart(scip, eventhdlrdata) )
    2813 {
    2814 eventhdlrdata->restarthitcounter++;
    2815
    2816 if( eventhdlrdata->restarthitcounter >= eventhdlrdata->hitcounterlim )
    2817 {
    2818 /* safe that we triggered a restart at this run */
    2819 if( !SCIPisExact(scip) && SCIPgetNRuns(scip) > eventhdlrdata->lastrestartrun )
    2820 {
    2821 eventhdlrdata->nrestartsperformed++;
    2822
    2824 "Restart triggered after %d consecutive estimations that the remaining tree will be large\n",
    2825 eventhdlrdata->restarthitcounter);
    2826 }
    2827
    2828 eventhdlrdata->lastrestartrun = SCIPgetNRuns(scip);
    2829
    2831 }
    2832 }
    2833 else
    2834 {
    2835 eventhdlrdata->restarthitcounter = 0;
    2836 }
    2837
    2838 return SCIP_OKAY;
    2839}
    2840
    2841/** output method of statistics table to output file stream 'file' */
    2842static
    2843SCIP_DECL_TABLEOUTPUT(tableOutputEstim)
    2844{ /*lint --e{715}*/
    2845 SCIP_EVENTHDLR* eventhdlr;
    2846 SCIP_EVENTHDLRDATA* eventhdlrdata;
    2847
    2849 assert(eventhdlr != NULL);
    2850
    2851 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    2852 assert(eventhdlrdata != NULL);
    2853
    2854 if( eventhdlrdata->showstats )
    2855 {
    2856 char strbuf[SCIP_MAXSTRLEN];
    2857 printReport(scip, eventhdlrdata, strbuf, 0);
    2858 SCIPinfoMessage(scip, file, "%s", strbuf);
    2859 }
    2860
    2861 return SCIP_OKAY;
    2862}
    2863
    2864/** output method of search tree completion display column to output file stream 'file' */
    2865static
    2866SCIP_DECL_DISPOUTPUT(dispOutputCompleted)
    2867{ /*lint --e{715}*/
    2868 SCIP_EVENTHDLR* eventhdlr;
    2869 SCIP_EVENTHDLRDATA* eventhdlrdata;
    2870 TREEDATA* treedata;
    2871 SCIP_Real completed;
    2872
    2873 assert(disp != NULL);
    2874 assert(strcmp(SCIPdispGetName(disp), DISP_NAME) == 0);
    2875 assert(scip != NULL);
    2876
    2878 assert(eventhdlr != NULL);
    2879 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    2880 assert(eventhdlrdata != NULL);
    2881 treedata = eventhdlrdata->treedata;
    2882
    2883 SCIP_CALL( getSearchCompletion(eventhdlrdata, &completed) );
    2884
    2885 completed = MIN(completed, 1.0);
    2886
    2887 if( treedata->weight >= 0.005 && completed > 0 )
    2888 SCIPinfoMessage(scip, file, "%7.2f%%", 100.0 * completed);
    2889 else
    2890 SCIPinfoMessage(scip, file, " unknown");
    2891
    2892 return SCIP_OKAY;
    2893}
    2894
    2895/** creates event handler for tree size estimation */
    2897 SCIP* scip /**< SCIP data structure */
    2898 )
    2899{
    2900 SCIP_RETCODE retcode;
    2901 SCIP_EVENTHDLRDATA* eventhdlrdata = NULL;
    2902 SCIP_EVENTHDLR* eventhdlr = NULL;
    2903
    2904 /* create estim event handler data */
    2905 SCIP_CALL( SCIPallocMemory(scip, &eventhdlrdata) );
    2906 BMSclearMemory(eventhdlrdata);
    2907
    2908 SCIP_CALL_TERMINATE( retcode, createTreeData(scip, &eventhdlrdata->treedata), TERMINATE );
    2909
    2911 eventExecEstim, eventhdlrdata) );
    2912 assert(eventhdlr != NULL);
    2913
    2914 /* set non fundamental callbacks via setter functions */
    2915 SCIP_CALL( SCIPsetEventhdlrCopy(scip, eventhdlr, eventCopyEstim) );
    2916 SCIP_CALL( SCIPsetEventhdlrFree(scip, eventhdlr, eventFreeEstim) );
    2917 SCIP_CALL( SCIPsetEventhdlrInit(scip, eventhdlr, eventInitEstim) );
    2918 SCIP_CALL( SCIPsetEventhdlrExit(scip, eventhdlr, eventExitEstim) );
    2919 SCIP_CALL( SCIPsetEventhdlrInitsol(scip, eventhdlr, eventInitsolEstim) );
    2920 SCIP_CALL( SCIPsetEventhdlrExitsol(scip, eventhdlr, eventExitsolEstim) );
    2921
    2922 /* add estimation event handler parameters */
    2923 SCIP_CALL( SCIPaddCharParam(scip, "estimation/restarts/restartpolicy", "restart policy: (a)lways, (c)ompletion, (e)stimation, (n)ever",
    2924 &eventhdlrdata->restartpolicyparam, FALSE, DEFAULT_RESTARTPOLICY, "acen", NULL, NULL) );
    2925
    2926 SCIP_CALL( SCIPaddCharParam(scip, "estimation/method",
    2927 "tree size estimation method: (c)ompletion, (e)nsemble, "
    2928 "time series forecasts on either (g)ap, (l)eaf frequency, (o)open nodes, tree (w)eight, (s)sg, "
    2929 "or (t)ree profile or w(b)e",
    2930 &eventhdlrdata->estimmethod, FALSE, DEFAULT_ESTIMMETHOD, ESTIMMETHODS, NULL, NULL) );
    2931
    2932 SCIP_CALL( SCIPaddIntParam(scip, "estimation/restarts/restartlimit", "restart limit",
    2933 &eventhdlrdata->restartlimit, FALSE, DEFAULT_RESTARTLIMIT, -1, INT_MAX, NULL, NULL) );
    2934
    2935 SCIP_CALL( SCIPaddLongintParam(scip, "estimation/restarts/minnodes", "minimum number of nodes before restart",
    2936 &eventhdlrdata->minnodes, FALSE, DEFAULT_MINNODES, -1L, SCIP_LONGINT_MAX, NULL, NULL) );
    2937
    2938 SCIP_CALL( SCIPaddBoolParam(scip, "estimation/restarts/countonlyleaves", "should only leaves count for the minnodes parameter?",
    2939 &eventhdlrdata->countonlyleaves, DEFAULT_COUNTONLYLEAVES, FALSE, NULL, NULL) );
    2940
    2941 SCIP_CALL( SCIPaddRealParam(scip, "estimation/restarts/restartfactor",
    2942 "factor by which the estimated number of nodes should exceed the current number of nodes",
    2943 &eventhdlrdata->restartfactor, FALSE, DEFAULT_RESTARTFACTOR, 1.0, SCIP_REAL_MAX, NULL, NULL) );
    2944
    2945 SCIP_CALL( SCIPaddBoolParam(scip, "estimation/restarts/restartnonlinear",
    2946 "whether to apply a restart when nonlinear constraints are present",
    2947 &eventhdlrdata->restartnonlinear, FALSE, DEFAULT_RESTARTNONLINEAR, NULL, NULL) );
    2948
    2949 SCIP_CALL( SCIPaddBoolParam(scip, "estimation/restarts/restartactpricers",
    2950 "whether to apply a restart when active pricers are used",
    2951 &eventhdlrdata->restartactpricers, FALSE, DEFAULT_RESTARTACTPRICERS, NULL, NULL) );
    2952
    2953 SCIP_CALL( SCIPaddRealParam(scip, "estimation/coefmonoweight",
    2954 "coefficient of tree weight in monotone approximation of search completion",
    2955 &eventhdlrdata->coefmonoweight, FALSE, DEFAULT_COEFMONOWEIGHT, 0.0, 1.0, NULL, NULL) );
    2956
    2957 SCIP_CALL( SCIPaddRealParam(scip, "estimation/coefmonossg",
    2958 "coefficient of 1 - SSG in monotone approximation of search completion",
    2959 &eventhdlrdata->coefmonossg, FALSE, DEFAULT_COEFMONOSSG, 0.0, 1.0, NULL, NULL) );
    2960
    2961 SCIP_CALL( SCIPaddIntParam(scip, "estimation/restarts/hitcounterlim", "limit on the number of successive samples to really trigger a restart",
    2962 &eventhdlrdata->hitcounterlim, FALSE, DEFAULT_HITCOUNTERLIM, 1, INT_MAX, NULL, NULL) );
    2963
    2964 SCIP_CALL( SCIPaddIntParam(scip, "estimation/reportfreq",
    2965 "report frequency on estimation: -1: never, 0:always, k >= 1: k times evenly during search",
    2966 &eventhdlrdata->reportfreq, TRUE, DEFAULT_REPORTFREQ, -1, INT_MAX / 2, NULL, NULL) );
    2967
    2968 SCIP_CALL( SCIPaddStringParam(scip, "estimation/regforestfilename", "user regression forest in RFCSV format",
    2969 &eventhdlrdata->regforestfilename, FALSE, DEFAULT_REGFORESTFILENAME, NULL, NULL) );
    2970
    2971 SCIP_CALL( SCIPaddCharParam(scip, "estimation/completiontype",
    2972 "approximation of search tree completion: (a)uto, (g)ap, tree (w)eight, (m)onotone regression, (r)egression forest, (s)sg",
    2973 &eventhdlrdata->completiontypeparam, FALSE, DEFAULT_COMPLETIONTYPE, "agmrsw", NULL, NULL) );
    2974
    2975 SCIP_CALL( SCIPaddBoolParam(scip, "estimation/treeprofile/enabled",
    2976 "should the event handler collect data?",
    2977 &eventhdlrdata->treeprofile_enabled, FALSE, DEFAULT_TREEPROFILE_ENABLED, NULL, NULL) );
    2978
    2979 SCIP_CALL( SCIPaddRealParam(scip, "estimation/treeprofile/minnodesperdepth",
    2980 "minimum average number of nodes at each depth before producing estimations",
    2981 &eventhdlrdata->treeprofile_minnodesperdepth, FALSE, DEFAULT_TREEPROFILE_MINNODESPERDEPTH, 1.0, SCIP_REAL_MAX, NULL, NULL) );
    2982
    2983 SCIP_CALL( SCIPaddBoolParam(scip, "estimation/useleafts",
    2984 "use leaf nodes as basic observations for time series, or all nodes?",
    2985 &eventhdlrdata->useleafts, TRUE, DEFAULT_USELEAFTS, NULL, NULL) );
    2986
    2987 SCIP_CALL( SCIPaddBoolParam(scip, "estimation/showstats",
    2988 "should statistics be shown at the end?",
    2989 &eventhdlrdata->showstats, TRUE, DEFAULT_SHOWSTATS, NULL, NULL) );
    2990
    2991 /* SSG parameters */
    2992 SCIP_CALL( SCIPaddIntParam(scip, "estimation/ssg/nmaxsubtrees",
    2993 "the maximum number of individual SSG subtrees; -1: no limit",
    2994 &eventhdlrdata->treedata->ssg->nmaxsubtrees, FALSE, DEFAULT_SSG_NMAXSUBTREES, -1, INT_MAX / 2, NULL, NULL) );
    2995
    2996 SCIP_CALL( SCIPaddLongintParam(scip, "estimation/ssg/nminnodeslastsplit",
    2997 "minimum number of nodes to process between two consecutive SSG splits",
    2998 &eventhdlrdata->treedata->ssg->nminnodeslastsplit, FALSE, DEFAULT_SSG_NMINNODESLASTSPLIT, 0L, SCIP_LONGINT_MAX, NULL, NULL) );
    2999
    3000 /* include statistics table */
    3002 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputEstim, NULL,
    3004
    3005 /* include time series into event handler */
    3006 SCIP_CALL( includeTimeseries(scip, eventhdlrdata) );
    3007
    3008 /* include display column */
    3010 NULL, NULL, NULL, NULL, NULL, NULL, dispOutputCompleted,
    3012
    3013TERMINATE:
    3014 if( retcode != SCIP_OKAY )
    3015 {
    3016 freeTreeData(scip, &eventhdlrdata->treedata);
    3017 SCIPfreeMemory(scip, &eventhdlrdata);
    3018 }
    3019
    3020 return retcode;
    3021}
    3022
    3023/** return an estimation of the final tree size */
    3025 SCIP* scip /**< SCIP data structure */
    3026 )
    3027{
    3028 SCIP_EVENTHDLR* eventhdlr;
    3029 SCIP_EVENTHDLRDATA* eventhdlrdata;
    3030 TSPOS tspos = TSPOS_NONE;
    3031 SCIP_Real estim;
    3032
    3033 assert(scip != NULL);
    3034
    3036 if( eventhdlr == NULL )
    3037 {
    3038 SCIPwarningMessage(scip, "SCIPgetTreesizeEstimation() called, but event handler " EVENTHDLR_NAME " is missing.\n");
    3039 return -1.0;
    3040 }
    3041
    3042 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
    3043 assert(eventhdlrdata != NULL);
    3044
    3045 switch (eventhdlrdata->estimmethod)
    3046 {
    3047 case ESTIMMETHOD_COMPL:
    3048 SCIP_CALL_ABORT( getEstimCompletion(scip, eventhdlrdata, &estim) );
    3049 return estim;
    3050
    3051 case ESTIMMETHOD_ENSMBL:
    3052 return getEnsembleEstimation(eventhdlrdata);
    3053
    3054 /* for the requested time series methods, we specify the array position */
    3055 case ESTIMMETHOD_GAP:
    3056 tspos = TSPOS_GAP;
    3057 break;
    3058
    3059 case ESTIMMETHOD_LFREQ:
    3060 tspos = TSPOS_LFREQ;
    3061 break;
    3062
    3063 case ESTIMMETHOD_OPEN:
    3064 tspos = TSPOS_OPEN;
    3065 break;
    3066
    3068 tspos = TSPOS_TREEWEIGHT;
    3069 break;
    3070
    3071 case ESTIMMETHOD_SSG:
    3072 tspos = TSPOS_SSG;
    3073 break;
    3074
    3075 /* tree profile estimation */
    3076 case ESTIMMETHOD_TPROF:
    3077 return predictTotalSizeTreeProfile(scip, eventhdlrdata->treeprofile, eventhdlrdata->treeprofile_minnodesperdepth);
    3078
    3079 /* Weighted backtrack estimation */
    3080 case ESTIMMETHOD_WBE:
    3081 return treeDataGetWbe(eventhdlrdata->treedata);
    3082
    3083 default:
    3084 SCIPerrorMessage("Unknown estimation '%c' method specified, should be one of [%s]\n",
    3085 eventhdlrdata->estimmethod, ESTIMMETHODS);
    3086 SCIPABORT();
    3087 break;
    3088 }
    3089
    3090 assert(tspos != TSPOS_NONE);
    3091 return (tspos == TSPOS_NONE ? -1.0 : timeSeriesEstimate(eventhdlrdata->timeseries[tspos], eventhdlrdata->treedata));
    3092}
    #define NULL
    Definition: def.h:248
    #define SCIP_MAXSTRLEN
    Definition: def.h:269
    #define SCIP_Longint
    Definition: def.h:141
    #define SCIP_REAL_MAX
    Definition: def.h:158
    #define SCIP_INVALID
    Definition: def.h:178
    #define SCIP_Bool
    Definition: def.h:91
    #define MIN(x, y)
    Definition: def.h:224
    #define SCIP_ALLOC(x)
    Definition: def.h:366
    #define SCIP_ALLOC_TERMINATE(retcode, x, TERM)
    Definition: def.h:386
    #define SCIP_Real
    Definition: def.h:156
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define MAX(x, y)
    Definition: def.h:220
    #define SCIP_CALL_ABORT(x)
    Definition: def.h:334
    #define SCIP_CALL_TERMINATE(retcode, x, TERM)
    Definition: def.h:376
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:148
    #define SCIPABORT()
    Definition: def.h:327
    #define REALABS(x)
    Definition: def.h:182
    #define SCIP_LONGINT_MAX
    Definition: def.h:142
    #define EPSZ(x, eps)
    Definition: def.h:188
    #define SCIP_CALL(x)
    Definition: def.h:355
    static void SCIPregForestFree(SCIP_REGFOREST **regforest)
    Definition: event_estim.c:402
    static char * timeSeriesGetName(TIMESERIES *timeseries)
    Definition: event_estim.c:1981
    static SCIP_RETCODE subtreeSumGapComputeFromScratchEfficiently(SCIP *scip, SUBTREESUMGAP *ssg, SCIP_Bool updatescaling)
    Definition: event_estim.c:1393
    enum RestartPolicy RESTARTPOLICY
    Definition: event_estim.c:100
    #define DEFAULT_COEFMONOWEIGHT
    Definition: event_estim.c:246
    static SCIP_RETCODE timeSeriesCreate(SCIP *scip, TIMESERIES **timeseries, const char *name, SCIP_Real targetvalue, SCIP_Real initialvalue, SCIP_Real alpha, SCIP_Real beta, DECL_TIMESERIESUPDATE((*timeseriesupdate)))
    Definition: event_estim.c:1743
    static SCIP_RETCODE subtreeSumGapSplit(SCIP *scip, SUBTREESUMGAP *ssg, SCIP_Bool addfocusnode)
    Definition: event_estim.c:1056
    static SCIP_DECL_PQUEUEELEMCHGPOS(elemChgPosNodeInfo)
    Definition: event_estim.c:997
    #define DES_BETA_TREEWEIGHT
    Definition: event_estim.c:129
    static void freeTreeProfile(SCIP *scip, TREEPROFILE **treeprofile)
    Definition: event_estim.c:711
    static SCIP_DECL_EVENTEXIT(eventExitEstim)
    Definition: event_estim.c:2675
    static SCIP_RETCODE updateTreeData(SCIP *scip, TREEDATA *treedata, SCIP_NODE *node, int nchildren)
    Definition: event_estim.c:1586
    #define DEFAULT_SHOWSTATS
    Definition: event_estim.c:265
    #define DEFAULT_RESTARTLIMIT
    Definition: event_estim.c:255
    static SCIP_Real getEnsembleEstimation(SCIP_EVENTHDLRDATA *eventhdlrdata)
    Definition: event_estim.c:2035
    static SCIP_Bool shouldApplyRestart(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata)
    Definition: event_estim.c:2481
    #define DES_ALPHA_TREEWEIGHT
    Definition: event_estim.c:128
    #define DES_ALPHA_OPENNODES
    Definition: event_estim.c:140
    #define MAX_REGFORESTSIZE
    Definition: event_estim.c:143
    #define RESTARTPOLICY_CHAR_ALWAYS
    Definition: event_estim.c:103
    TsPos
    Definition: event_estim.c:204
    @ TSPOS_TREEWEIGHT
    Definition: event_estim.c:207
    @ TSPOS_GAP
    Definition: event_estim.c:206
    @ TSPOS_NONE
    Definition: event_estim.c:205
    @ TSPOS_OPEN
    Definition: event_estim.c:210
    @ TSPOS_SSG
    Definition: event_estim.c:209
    @ TSPOS_LFREQ
    Definition: event_estim.c:208
    #define RESTARTPOLICY_CHAR_NEVER
    Definition: event_estim.c:102
    #define INITIALSIZE
    Definition: event_estim.c:124
    static SCIP_Bool isRestartApplicable(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata)
    Definition: event_estim.c:2381
    #define DEFAULT_REPORTFREQ
    Definition: event_estim.c:244
    static void printReport(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata, char *strbuf, int reportnum)
    Definition: event_estim.c:2539
    static SCIP_Real timeSeriesGetSmoothEstimation(TIMESERIES *timeseries)
    Definition: event_estim.c:1896
    static SCIP_RETCODE subtreeSumGapCreate(SCIP *scip, SUBTREESUMGAP **ssg)
    Definition: event_estim.c:936
    static void doubleExpSmoothUpdate(DOUBLEEXPSMOOTH *des, SCIP_Real xnew)
    Definition: event_estim.c:1692
    static void copyTreeProfileStats(TREEPROFILESTATS *dest, TREEPROFILESTATS *src)
    Definition: event_estim.c:624
    #define DEFAULT_SSG_NMAXSUBTREES
    Definition: event_estim.c:262
    #define DES_BETA_LEAFFREQUENCY
    Definition: event_estim.c:135
    #define TABLE_NAME
    Definition: event_estim.c:110
    #define ESTIMMETHOD_GAP
    Definition: event_estim.c:160
    static SCIP_DECL_EVENTEXEC(eventExecEstim)
    Definition: event_estim.c:2736
    #define DEFAULT_SSG_NMINNODESLASTSPLIT
    Definition: event_estim.c:264
    #define DISP_PRIORITY
    Definition: event_estim.c:120
    #define DEFAULT_MINNODES
    Definition: event_estim.c:256
    #define COMPLETIONTYPE_REGFOREST
    Definition: event_estim.c:149
    #define DES_USETRENDINLEVEL
    Definition: event_estim.c:107
    #define COMPLETIONTYPE_MONOREG
    Definition: event_estim.c:150
    #define ESTIMMETHOD_TREEWEIGHT
    Definition: event_estim.c:165
    #define COMPLETIONTYPE_TREEWEIGHT
    Definition: event_estim.c:151
    #define ESTIMMETHOD_LFREQ
    Definition: event_estim.c:161
    static SCIP_RETCODE timeSeriesUpdate(SCIP *scip, TIMESERIES *timeseries, TREEDATA *treedata, SCIP_Bool isleaf)
    Definition: event_estim.c:1932
    #define DEFAULT_TREEPROFILE_ENABLED
    Definition: event_estim.c:252
    static SCIP_DECL_EVENTCOPY(eventCopyEstim)
    Definition: event_estim.c:2625
    static SCIP_Real SCIPregForestPredict(SCIP_REGFOREST *regforest, SCIP_Real *datapoint)
    Definition: event_estim.c:424
    static void freeTreeData(SCIP *scip, TREEDATA **treedata)
    Definition: event_estim.c:1568
    static SCIP_RETCODE resetTreeData(SCIP *scip, TREEDATA *treedata)
    Definition: event_estim.c:1529
    static SCIP_Real timeSeriesEstimate(TIMESERIES *timeseries, TREEDATA *treedata)
    Definition: event_estim.c:1841
    enum TsPos TSPOS
    Definition: event_estim.c:213
    static SCIP_RETCODE includeTimeseries(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata)
    Definition: event_estim.c:2324
    #define ESTIMMETHOD_ENSMBL
    Definition: event_estim.c:159
    #define COMPLETIONTYPE_GAP
    Definition: event_estim.c:153
    #define COMPLETIONTYPE_SSG
    Definition: event_estim.c:152
    static void timeSeriesUpdateSmoothEstimation(TIMESERIES *timeseries, SCIP_Real estimation)
    Definition: event_estim.c:1880
    #define DEFAULT_COUNTONLYLEAVES
    Definition: event_estim.c:257
    static SCIP_RETCODE subtreeSumGapRemoveNode(SCIP *scip, SUBTREESUMGAP *ssg, SCIP_NODE *node)
    Definition: event_estim.c:1157
    static void timeSeriesResample(TIMESERIES *timeseries)
    Definition: event_estim.c:1905
    static SCIP_RETCODE subtreeSumGapReset(SCIP *scip, SUBTREESUMGAP *ssg)
    Definition: event_estim.c:912
    static SCIP_RETCODE updateTreeProfile(SCIP *scip, TREEPROFILE *treeprofile, SCIP_NODE *node)
    Definition: event_estim.c:731
    static SCIP_RETCODE createTreeData(SCIP *scip, TREEDATA **treedata)
    Definition: event_estim.c:1549
    static SCIP_RETCODE getEstimCompletion(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata, SCIP_Real *estim)
    Definition: event_estim.c:2216
    #define DEFAULT_HITCOUNTERLIM
    Definition: event_estim.c:261
    #define DISP_POSITION
    Definition: event_estim.c:121
    #define DES_ALPHA_SSG
    Definition: event_estim.c:137
    #define DES_BETA_OPENNODES
    Definition: event_estim.c:141
    static SCIP_Real calcGap(SCIP *scip, SCIP_Real lowerbound)
    Definition: event_estim.c:1124
    #define ESTIMMETHOD_OPEN
    Definition: event_estim.c:162
    #define DEFAULT_RESTARTACTPRICERS
    Definition: event_estim.c:260
    SCIP_Real SCIPgetTreesizeEstimation(SCIP *scip)
    Definition: event_estim.c:3024
    static SCIP_DECL_EVENTINIT(eventInitEstim)
    Definition: event_estim.c:2654
    static void timeSeriesFree(SCIP *scip, TIMESERIES **timeseries)
    Definition: event_estim.c:1792
    #define NTIMESERIES
    Definition: event_estim.c:200
    #define DEFAULT_RESTARTFACTOR
    Definition: event_estim.c:258
    #define SESCOEFF
    Definition: event_estim.c:125
    #define DISP_NAME
    Definition: event_estim.c:116
    static SCIP_DECL_SORTPTRCOMP(compareNodeInfos)
    Definition: event_estim.c:982
    #define DEFAULT_USELEAFTS
    Definition: event_estim.c:243
    SCIP_RETCODE SCIPincludeEventHdlrEstim(SCIP *scip)
    Definition: event_estim.c:2896
    #define DES_ALPHA_LEAFFREQUENCY
    Definition: event_estim.c:134
    #define DES_BETA_GAP
    Definition: event_estim.c:132
    static SCIP_RETCODE subtreeSumGapInsertChildren(SCIP *scip, SUBTREESUMGAP *ssg)
    Definition: event_estim.c:1228
    static SCIP_Real timeSeriesGetValue(TIMESERIES *timeseries)
    Definition: event_estim.c:1812
    RestartPolicy
    Definition: event_estim.c:93
    @ RESTARTPOLICY_COMPLETION
    Definition: event_estim.c:97
    @ RESTARTPOLICY_ALWAYS
    Definition: event_estim.c:95
    @ RESTARTPOLICY_ESTIMATION
    Definition: event_estim.c:96
    @ RESTARTPOLICY_NEVER
    Definition: event_estim.c:94
    static SCIP_Bool shouldApplyRestartCompletion(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata)
    Definition: event_estim.c:2418
    static SCIP_RETCODE extendMemoryTreeProfile(SCIP *scip, TREEPROFILE *treeprofile, int mindepth)
    Definition: event_estim.c:652
    static void subtreeSumGapFree(SCIP *scip, SUBTREESUMGAP **ssg)
    Definition: event_estim.c:959
    #define DISP_HEADER
    Definition: event_estim.c:118
    #define DECL_TIMESERIESUPDATE(x)
    Definition: event_estim.c:331
    static void timeSeriesReset(TIMESERIES *timeseries)
    Definition: event_estim.c:1728
    static SCIP_DECL_EVENTFREE(eventFreeEstim)
    Definition: event_estim.c:2636
    #define RESTARTPOLICY_CHAR_COMPLETION
    Definition: event_estim.c:104
    #define DISP_DESC
    Definition: event_estim.c:117
    #define DISP_WIDTH
    Definition: event_estim.c:119
    #define ESTIMMETHOD_WBE
    Definition: event_estim.c:158
    #define TABLE_EARLIEST_STAGE
    Definition: event_estim.c:113
    #define ESTIMMETHOD_TPROF
    Definition: event_estim.c:164
    static void doubleExpSmoothInit(DOUBLEEXPSMOOTH *des, SCIP_Real x1)
    Definition: event_estim.c:1674
    #define DEFAULT_COEFMONOSSG
    Definition: event_estim.c:247
    static SCIP_Bool isEqualTreeProfileStats(TREEPROFILESTATS *stats, TREEPROFILESTATS *other)
    Definition: event_estim.c:608
    static int timeSeriesGetResolution(TIMESERIES *timeseries)
    Definition: event_estim.c:1832
    #define ESTIMMETHODS
    Definition: event_estim.c:167
    static SCIP_RETCODE createTreeProfile(SCIP *scip, TREEPROFILE **treeprofile)
    Definition: event_estim.c:687
    #define DISP_STRIPLINE
    Definition: event_estim.c:122
    static void subtreeSumGapDelSubtrees(SCIP *scip, SUBTREESUMGAP *ssg)
    Definition: event_estim.c:872
    static SCIP_DECL_TABLEOUTPUT(tableOutputEstim)
    Definition: event_estim.c:2843
    static SCIP_RETCODE updateTimeseries(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata, TREEDATA *treedata, SCIP_Bool isleaf)
    Definition: event_estim.c:2511
    static void resetTreeProfileStats(TREEPROFILESTATS *treeprofilestats)
    Definition: event_estim.c:640
    #define TABLE_POSITION
    Definition: event_estim.c:112
    static SCIP_Real treeDataGetWbe(TREEDATA *treedata)
    Definition: event_estim.c:1622
    static void resetTimeSeries(SCIP_EVENTHDLRDATA *eventhdlrdata)
    Definition: event_estim.c:1990
    #define DEFAULT_COMPLETIONTYPE
    Definition: event_estim.c:248
    static SCIP_DECL_EVENTINITSOL(eventInitsolEstim)
    Definition: event_estim.c:2689
    #define EVENTHDLR_DESC
    Definition: event_estim.c:84
    #define EVENTTYPE_ESTIM
    Definition: event_estim.c:85
    static SCIP_RETCODE SCIPregForestFromFile(SCIP_REGFOREST **regforest, const char *filename)
    Definition: event_estim.c:471
    static RESTARTPOLICY getRestartPolicy(SCIP_EVENTHDLRDATA *eventhdlrdata)
    Definition: event_estim.c:2357
    static SCIP_Real doubleExpSmoothGetTrend(DOUBLEEXPSMOOTH *des)
    Definition: event_estim.c:1714
    static void doubleExpSmoothReset(DOUBLEEXPSMOOTH *des, SCIP_Real initialvalue)
    Definition: event_estim.c:1661
    static char * real2String(SCIP_Real num, char *buf, int digits)
    Definition: event_estim.c:384
    #define ESTIMMETHOD_SSG
    Definition: event_estim.c:163
    static SCIP_RETCODE subtreeSumGapUpdate(SCIP *scip, SUBTREESUMGAP *ssg, SCIP_NODE *node, int nchildren, SCIP_Longint nsolvednodes)
    Definition: event_estim.c:1450
    static void freeTimeSeries(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata)
    Definition: event_estim.c:2013
    static SCIP_Real predictTotalSizeTreeProfile(SCIP *scip, TREEPROFILE *treeprofile, SCIP_Real minnodesperdepth)
    Definition: event_estim.c:800
    #define DES_ALPHA_GAP
    Definition: event_estim.c:131
    #define ESTIMMETHOD_COMPL
    Definition: event_estim.c:157
    #define TREEPROFILE_MINSIZE
    Definition: event_estim.c:170
    #define COMPLETIONTYPE_AUTO
    Definition: event_estim.c:148
    static SCIP_DECL_DISPOUTPUT(dispOutputCompleted)
    Definition: event_estim.c:2866
    #define EVENTHDLR_NAME
    Definition: event_estim.c:83
    static SCIP_RETCODE subtreeSumGapStoreNode(SCIP *scip, SUBTREESUMGAP *ssg, SCIP_NODE *node, int subtreeidx)
    Definition: event_estim.c:1007
    static SCIP_RETCODE getSearchCompletion(SCIP_EVENTHDLRDATA *eventhdlrdata, SCIP_Real *completed)
    Definition: event_estim.c:2130
    #define RESTARTPOLICY_CHAR_ESTIMATION
    Definition: event_estim.c:105
    static SCIP_Real timeSeriesGetTargetValue(TIMESERIES *timeseries)
    Definition: event_estim.c:1823
    #define DEFAULT_ESTIMMETHOD
    Definition: event_estim.c:249
    #define SSG_STARTPRIMBOUND
    Definition: event_estim.c:171
    #define DEFAULT_RESTARTNONLINEAR
    Definition: event_estim.c:259
    #define DEFAULT_RESTARTPOLICY
    Definition: event_estim.c:254
    #define TABLE_DESC
    Definition: event_estim.c:111
    static SCIP_Bool shouldApplyRestartEstimation(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata)
    Definition: event_estim.c:2444
    #define DEFAULT_TREEPROFILE_MINNODESPERDEPTH
    Definition: event_estim.c:253
    static SCIP_DECL_EVENTEXITSOL(eventExitsolEstim)
    Definition: event_estim.c:2719
    #define DES_BETA_SSG
    Definition: event_estim.c:138
    #define DEFAULT_REGFORESTFILENAME
    Definition: event_estim.c:245
    event handler for tree size estimation and restarts
    SCIP_FILE * SCIPfopen(const char *path, const char *mode)
    Definition: fileio.c:153
    int SCIPfeof(SCIP_FILE *stream)
    Definition: fileio.c:227
    int SCIPfclose(SCIP_FILE *fp)
    Definition: fileio.c:232
    char * SCIPfgets(char *s, int size, SCIP_FILE *stream)
    Definition: fileio.c:200
    #define nnodes
    Definition: gastrans.c:74
    SCIP_STATUS SCIPgetStatus(SCIP *scip)
    Definition: scip_general.c:562
    SCIP_STAGE SCIPgetStage(SCIP *scip)
    Definition: scip_general.c:444
    void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
    Definition: misc.c:3095
    void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3284
    SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
    Definition: misc.c:3143
    SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
    Definition: misc.c:3061
    SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3466
    SCIP_RETCODE SCIPhashmapRemoveAll(SCIP_HASHMAP *hashmap)
    Definition: misc.c:3676
    SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3482
    void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:208
    void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:225
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
    Definition: scip_message.c:120
    SCIP_RETCODE SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:111
    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 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 SCIPaddStringParam(SCIP *scip, const char *name, const char *desc, char **valueptr, SCIP_Bool isadvanced, const char *defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:194
    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
    SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:57
    void ** SCIPpqueueElems(SCIP_PQUEUE *pqueue)
    Definition: misc.c:1540
    void SCIPpqueueDelPos(SCIP_PQUEUE *pqueue, int pos)
    Definition: misc.c:1435
    void SCIPpqueueFree(SCIP_PQUEUE **pqueue)
    Definition: misc.c:1324
    SCIP_RETCODE SCIPpqueueInsert(SCIP_PQUEUE *pqueue, void *elem)
    Definition: misc.c:1396
    int SCIPpqueueNElems(SCIP_PQUEUE *pqueue)
    Definition: misc.c:1529
    SCIP_RETCODE SCIPpqueueCreate(SCIP_PQUEUE **pqueue, int initsize, SCIP_Real sizefac, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), SCIP_DECL_PQUEUEELEMCHGPOS((*elemchgpos)))
    Definition: misc.c:1297
    void * SCIPpqueueFirst(SCIP_PQUEUE *pqueue)
    Definition: misc.c:1515
    const char * SCIPdispGetName(SCIP_DISP *disp)
    Definition: disp.c:335
    SCIP_RETCODE SCIPincludeDisp(SCIP *scip, const char *name, const char *desc, const char *header, SCIP_DISPSTATUS dispstatus, SCIP_DECL_DISPCOPY((*dispcopy)), SCIP_DECL_DISPFREE((*dispfree)), SCIP_DECL_DISPINIT((*dispinit)), SCIP_DECL_DISPEXIT((*dispexit)), SCIP_DECL_DISPINITSOL((*dispinitsol)), SCIP_DECL_DISPEXITSOL((*dispexitsol)), SCIP_DECL_DISPOUTPUT((*dispoutput)), SCIP_DISPDATA *dispdata, int width, int priority, int position, SCIP_Bool stripline)
    Definition: scip_disp.c:55
    SCIP_RETCODE SCIPsetEventhdlrInitsol(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_DECL_EVENTINITSOL((*eventinitsol)))
    Definition: scip_event.c:199
    SCIP_RETCODE SCIPsetEventhdlrCopy(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_DECL_EVENTCOPY((*eventcopy)))
    Definition: scip_event.c:143
    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
    SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
    Definition: scip_event.c:241
    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_RETCODE SCIPsetEventhdlrExit(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_DECL_EVENTEXIT((*eventexit)))
    Definition: scip_event.c:185
    SCIP_RETCODE SCIPsetEventhdlrInit(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_DECL_EVENTINIT((*eventinit)))
    Definition: scip_event.c:171
    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
    SCIP_Bool SCIPisExact(SCIP *scip)
    Definition: scip_exact.c:193
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    #define SCIPreallocMemoryArray(scip, ptr, newnum)
    Definition: scip_mem.h:70
    BMS_BLKMEM * SCIPblkmem(SCIP *scip)
    Definition: scip_mem.c:57
    #define SCIPallocMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:64
    #define SCIPallocClearBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:97
    int SCIPcalcMemGrowSize(SCIP *scip, int num)
    Definition: scip_mem.c:139
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPallocClearMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:66
    #define SCIPallocMemory(scip, ptr)
    Definition: scip_mem.h:60
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #define SCIPfreeMemoryArray(scip, ptr)
    Definition: scip_mem.h:80
    #define SCIPfreeMemory(scip, ptr)
    Definition: scip_mem.h:78
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
    Definition: scip_nlp.c:110
    SCIP_NODETYPE SCIPnodeGetType(SCIP_NODE *node)
    Definition: tree.c:8473
    SCIP_Real SCIPnodeGetLowerbound(SCIP_NODE *node)
    Definition: tree.c:8503
    SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
    Definition: tree.c:8483
    SCIP_NODE * SCIPnodeGetParent(SCIP_NODE *node)
    Definition: tree.c:8782
    int SCIPnodeGetDepth(SCIP_NODE *node)
    Definition: tree.c:8493
    int SCIPgetNActivePricers(SCIP *scip)
    Definition: scip_pricer.c:348
    SCIP_Real SCIPretransformObj(SCIP *scip, SCIP_Real obj)
    Definition: scip_sol.c:2132
    SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
    Definition: scip_solve.c:3603
    SCIP_Bool SCIPisInRestart(SCIP *scip)
    Definition: scip_solve.c:3709
    SCIP_Real SCIPgetPrimalbound(SCIP *scip)
    SCIP_Real SCIPgetUpperbound(SCIP *scip)
    SCIP_Longint SCIPgetNNodes(SCIP *scip)
    SCIP_Real SCIPgetDualbound(SCIP *scip)
    SCIP_Real SCIPgetLowerbound(SCIP *scip)
    int SCIPgetNRuns(SCIP *scip)
    int SCIPgetNRootIntFixingsRun(SCIP *scip)
    SCIP_RETCODE SCIPincludeTable(SCIP *scip, const char *name, const char *desc, SCIP_Bool active, SCIP_DECL_TABLECOPY((*tablecopy)), SCIP_DECL_TABLEFREE((*tablefree)), SCIP_DECL_TABLEINIT((*tableinit)), SCIP_DECL_TABLEEXIT((*tableexit)), SCIP_DECL_TABLEINITSOL((*tableinitsol)), SCIP_DECL_TABLEEXITSOL((*tableexitsol)), SCIP_DECL_TABLEOUTPUT((*tableoutput)), SCIP_DECL_TABLECOLLECT((*tablecollect)), SCIP_TABLEDATA *tabledata, int position, SCIP_STAGE earlieststage)
    Definition: scip_table.c:62
    SCIP_Real SCIPgetSolvingTime(SCIP *scip)
    Definition: scip_timing.c:378
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    int SCIPgetNSiblings(SCIP *scip)
    Definition: scip_tree.c:230
    int SCIPgetNChildren(SCIP *scip)
    Definition: scip_tree.c:188
    SCIP_RETCODE SCIPgetOpenNodesData(SCIP *scip, SCIP_NODE ***leaves, SCIP_NODE ***children, SCIP_NODE ***siblings, int *nleaves, int *nchildren, int *nsiblings)
    Definition: scip_tree.c:398
    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
    int SCIPgetNLeaves(SCIP *scip)
    Definition: scip_tree.c:272
    SCIP_Bool SCIPwasNodeLastBranchParent(SCIP *scip, SCIP_NODE *node)
    Definition: scip_tree.c:733
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
    Definition: misc.c:10955
    memory allocation routines
    #define BMSfreeMemory(ptr)
    Definition: memory.h:145
    #define BMSduplicateMemoryArray(ptr, source, num)
    Definition: memory.h:143
    #define BMSclearMemory(ptr)
    Definition: memory.h:129
    #define BMSallocMemoryArray(ptr, num)
    Definition: memory.h:123
    #define BMSfreeMemoryArray(ptr)
    Definition: memory.h:147
    #define BMSclearMemoryArray(ptr, num)
    Definition: memory.h:130
    #define BMSfreeMemoryArrayNull(ptr)
    Definition: memory.h:148
    #define BMSallocMemory(ptr)
    Definition: memory.h:118
    propagator for symmetry handling
    public methods for displaying runtime statistics
    public methods for managing events
    wrapper functions to map file i/o to standard or zlib file i/o
    struct SCIP_File SCIP_FILE
    Definition: pub_fileio.h:43
    public methods for message output
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    #define SCIPdebugMessage
    Definition: pub_message.h:96
    #define SCIPstatistic(x)
    Definition: pub_message.h:120
    public data structures and miscellaneous methods
    public methods for branch and bound tree
    public methods for display handler plugins
    public methods for event handler plugins and event handlers
    general public methods
    public methods for memory management
    public methods for message handling
    public methods for nonlinear relaxation
    public methods for numerical tolerances
    public methods for SCIP parameter handling
    public methods for variable pricer plugins
    public methods for solutions
    public solving methods
    public methods for querying solving statistics
    public methods for statistics table plugins
    public methods for timing
    public methods for the branch-and-bound tree
    SCIP_Real initialvalue
    Definition: event_estim.c:180
    SCIP_Real trend
    Definition: event_estim.c:179
    SCIP_Bool usetrendinlevel
    Definition: event_estim.c:181
    SCIP_Real level
    Definition: event_estim.c:178
    SCIP_Real alpha
    Definition: event_estim.c:176
    SCIP_Real beta
    Definition: event_estim.c:177
    SCIP_Real lowerbound
    Definition: event_estim.c:361
    SCIP_NODE * node
    Definition: event_estim.c:360
    int subtreeidx
    Definition: event_estim.c:363
    SCIP_Real * value
    Definition: event_estim.c:374
    SCIP_Longint nodelastsplit
    Definition: event_estim.c:323
    SCIP_Real scalingfactor
    Definition: event_estim.c:321
    SCIP_Real value
    Definition: event_estim.c:318
    SCIP_PQUEUE ** subtreepqueues
    Definition: event_estim.c:320
    SCIP_HASHMAP * nodes2info
    Definition: event_estim.c:319
    SCIP_Longint nminnodeslastsplit
    Definition: event_estim.c:324
    SCIP_Real pblastsplit
    Definition: event_estim.c:322
    SCIP_Longint nobs
    Definition: event_estim.c:349
    SCIP_Real * vals
    Definition: event_estim.c:343
    SCIP_Real * estimation
    Definition: event_estim.c:344
    int resolution
    Definition: event_estim.c:352
    SCIP_Real currentvalue
    Definition: event_estim.c:347
    DOUBLEEXPSMOOTH des
    Definition: event_estim.c:341
    char * name
    Definition: event_estim.c:342
    SCIP_Bool useleafts
    Definition: event_estim.c:353
    SCIP_Real initialvalue
    Definition: event_estim.c:348
    DECL_TIMESERIESUPDATE((*timeseriesupdate))
    SCIP_Real smoothestimation
    Definition: event_estim.c:345
    SCIP_Real targetvalue
    Definition: event_estim.c:346
    SCIP_Longint nvisited
    Definition: event_estim.c:311
    SCIP_Longint nopen
    Definition: event_estim.c:308
    SCIP_Longint nleaves
    Definition: event_estim.c:310
    long double weight
    Definition: event_estim.c:312
    SUBTREESUMGAP * ssg
    Definition: event_estim.c:313
    SCIP_Longint ninner
    Definition: event_estim.c:309
    SCIP_Longint nnodes
    Definition: event_estim.c:307
    SCIP_Longint * profile
    Definition: event_estim.c:233
    TREEPROFILESTATS lastestimatestats
    Definition: event_estim.c:237
    SCIP_Real lastestimate
    Definition: event_estim.c:236
    TREEPROFILESTATS stats
    Definition: event_estim.c:235
    type definitions for displaying runtime statistics
    @ SCIP_DISPSTATUS_AUTO
    Definition: type_disp.h:61
    type definitions for managing events
    struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
    Definition: type_event.h:160
    #define SCIP_EVENTTYPE_NODEBRANCHED
    Definition: type_event.h:96
    uint64_t SCIP_EVENTTYPE
    Definition: type_event.h:156
    #define SCIP_EVENTTYPE_NODEDELETE
    Definition: type_event.h:97
    type definitions for message output methods
    @ SCIP_VERBLEVEL_HIGH
    Definition: type_message.h:61
    @ SCIP_VERBLEVEL_FULL
    Definition: type_message.h:62
    type definitions for miscellaneous datastructures
    type definitions for return codes for SCIP methods
    @ SCIP_NOFILE
    Definition: type_retcode.h:47
    @ SCIP_INVALIDDATA
    Definition: type_retcode.h:52
    @ SCIP_PARAMETERWRONGVAL
    Definition: type_retcode.h:57
    @ SCIP_NOMEMORY
    Definition: type_retcode.h:44
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    @ SCIP_STAGE_SOLVED
    Definition: type_set.h:54
    @ SCIP_STAGE_INITSOLVE
    Definition: type_set.h:52
    type definitions for problem statistics
    @ SCIP_STATUS_UNKNOWN
    Definition: type_stat.h:42
    type definitions for displaying statistics tables
    @ SCIP_NODETYPE_CHILD
    Definition: type_tree.h:44
    @ SCIP_NODETYPE_DEADEND
    Definition: type_tree.h:46
    @ SCIP_NODETYPE_SIBLING
    Definition: type_tree.h:43
    @ SCIP_NODETYPE_LEAF
    Definition: type_tree.h:45