Scippy

SCIP

Solving Constraint Integer Programs

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