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