SCIP Doxygen Documentation
Loading...
Searching...
No Matches
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-2026 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file event_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 */
211};
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 {
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 not point towards the target;
1866 * in this case, return infinity
1867 */
1868 if( (targetval > val && trend <= tolerance) || (targetval < val && trend >= -tolerance) )
1869 return -1.0;
1870
1871 /* compute after how many additional steps the current trend reaches the target value; multiply by resolution */
1872 estimated = timeSeriesGetResolution(timeseries) * (timeseries->nvals + (targetval - val) / (SCIP_Real)trend);
1873 return timeseries->useleafts ? 2.0 * estimated - 1.0 : estimated;
1874}
1875
1876/** update time series smoothened estimation */
1877static
1879 TIMESERIES* timeseries, /**< time series */
1880 SCIP_Real estimation /**< estimation value */
1881 )
1882{
1883 if( timeseries->smoothestimation == SCIP_INVALID )/*lint !e777*/
1884 timeseries->smoothestimation = estimation;
1885 else
1886 {
1887 timeseries->smoothestimation *= (1.0 - SESCOEFF);
1888 timeseries->smoothestimation += SESCOEFF * estimation;
1889 }
1890}
1891
1892/** get smooth estimation of time series */
1893static
1895 TIMESERIES* timeseries /**< time series */
1896 )
1897{
1898 return timeseries->smoothestimation;
1899}
1900
1901/** resample to lower resolution */
1902static
1904 TIMESERIES* timeseries /**< time series */
1905 )
1906{
1907 DOUBLEEXPSMOOTH* des;
1908 int i;
1909
1910 assert(timeseries->nvals % 2 == 0);
1911
1912 des = &timeseries->des;
1913 doubleExpSmoothReset(des, timeseries->initialvalue);
1914
1915 /* compress vals array to store only every second entry */
1916 for( i = 0; i < timeseries->nvals / 2; ++i )
1917 {
1918 timeseries->vals[i] = timeseries->vals[2 * i];
1919 timeseries->estimation[i] = timeseries->estimation[2 * i];
1920 doubleExpSmoothUpdate(des, timeseries->vals[i]);
1921 timeSeriesUpdateSmoothEstimation(timeseries, timeseries->estimation[i]);
1922 }
1923
1924 timeseries->resolution *= 2;
1925 timeseries->nvals = timeseries->nvals / 2;
1926}
1927
1928/** update time series */
1929static
1931 SCIP* scip, /**< SCIP data structure */
1932 TIMESERIES* timeseries, /**< time series */
1933 TREEDATA* treedata, /**< tree data */
1934 SCIP_Bool isleaf /**< are we at a leaf node? */
1935 )
1936{
1937 SCIP_Real value;
1938
1939 assert(scip != NULL);
1940 assert(timeseries != NULL);
1941 assert(treedata != NULL);
1942
1943 /* call update callback */
1944 assert(timeseries->timeseriesupdate != NULL);
1945 SCIP_CALL( timeseries->timeseriesupdate(scip, timeseries, treedata, &value) );
1946
1947 /* store the value as current value */
1948 timeseries->currentvalue = value;
1949
1950 if( timeseries->useleafts && ! isleaf )
1951 return SCIP_OKAY;
1952
1953 timeseries->nobs++;
1954
1955 /* if this is a leaf that matches the time series resolution, store the value */
1956 if( timeseries->nobs % timeseries->resolution == 0 )
1957 {
1958 int tspos;
1959 SCIP_Real estimate;
1960
1961 assert(timeseries->nvals < timeseries->valssize);
1962 tspos = timeseries->nvals++;
1963 timeseries->vals[tspos] = value;
1964 doubleExpSmoothUpdate(&timeseries->des, value);
1965 estimate = timeSeriesEstimate(timeseries, treedata);
1966 timeseries->estimation[tspos] = estimate;
1967 timeSeriesUpdateSmoothEstimation(timeseries, estimate);
1968 }
1969
1970 /* if the time series has reached its capacity, resample and increase the resolution */
1971 if( timeseries->nvals == timeseries->valssize )
1972 timeSeriesResample(timeseries);
1973
1974 return SCIP_OKAY;
1975}
1976
1977/** get name of time series */
1978static
1980 TIMESERIES* timeseries /**< time series */
1981 )
1982{
1983 return timeseries->name;
1984}
1985
1986/** reset all time series */
1987static
1989 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */
1990 )
1991{
1992 TIMESERIES** tss = eventhdlrdata->timeseries;
1993 int t;
1994
1995 /* loop over time series and reset them */
1996 for( t = 0; t < NTIMESERIES; ++t )
1997 {
1998 assert(tss[t] != NULL);
1999 timeSeriesReset(tss[t]);
2000
2001 tss[t]->useleafts = eventhdlrdata->useleafts;
2002 }
2003}
2004
2005/*
2006 * Callback methods of event handler
2007 */
2008
2009/** free all time series */
2010static
2012 SCIP* scip, /**< SCIP data structure */
2013 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */
2014 )
2015{
2016 TIMESERIES** tss = eventhdlrdata->timeseries;
2017 int t;
2018
2019 /* loop over time series and reset them */
2020 for( t = 0; t < NTIMESERIES; ++t )
2021 {
2022 assert(tss[t] != NULL);
2023 timeSeriesFree(scip, &tss[t]);
2024 }
2025}
2026
2027/** get ensemble tree size estimation as a combination of the individual time series estimations
2028 *
2029 * the coefficients have been computed based on a nonlinear fit on a broad set of publicly available
2030 * MIP instances; please refer to the publication at the top of this file for further details.
2031 */
2032static
2034 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */
2035 )
2036{
2037 TREEDATA* treedata;
2038 SCIP_Real* coeffs;
2039 SCIP_Real estim;
2040 int t;
2041
2042 TSPOS tsposs[] = {
2043 TSPOS_GAP,
2046 TSPOS_SSG,
2048 };
2049
2050 /* coefficients for the early stage (tree weight <= 0.3) */
2051 SCIP_Real coeffs_early[] = {
2052 0.002, /* gap */
2053 0.381, /* tree weight */
2054 0.469, /* leaf-frequency */
2055 0.292, /* SSG */
2056 0.004 /* open-nodes */
2057 };
2058
2059 /* coefficients for the intermediate stage (0.3 < tree weight <= 0.6) */
2060 SCIP_Real coeffs_intermediate[] = {
2061 0.011, /* gap */
2062 0.193, /* tree weight */
2063 0.351, /* leaf-frequency */
2064 0.012, /* SSG */
2065 0.051 /* open-nodes */
2066 };
2067
2068 /* coefficients for the late stage (tree weight > 0.6) */
2069 SCIP_Real coeffs_late[] = {
2070 0.000, /* gap */
2071 0.033, /* tree weight */
2072 0.282, /* leaf-frequency */
2073 0.003, /* SSG */
2074 0.024 /* open-nodes */
2075 };
2076
2077 assert(eventhdlrdata != NULL);
2078 treedata = eventhdlrdata->treedata;
2079
2080 /* assign coeffs based on stage */
2081 if( treedata->weight <= 0.3 )
2082 {
2083 estim = 0.0;
2084 coeffs = coeffs_early;
2085 /* ensure that coeffs and time series are still aligned */
2086 assert(sizeof(coeffs_early)/sizeof(SCIP_Real) == NTIMESERIES); /*lint !e506*/
2087 }
2088 else if( treedata->weight <= 0.6 )
2089 {
2090 coeffs = coeffs_intermediate;
2091 /* ensure that coeffs and time series are still aligned */
2092 assert(sizeof(coeffs_intermediate)/sizeof(SCIP_Real) == NTIMESERIES); /*lint !e506*/
2093
2094 /* initialize by intermediate WBE coefficient */
2095 estim = 0.156 * treeDataGetWbe(treedata);
2096 }
2097 else
2098 {
2099 coeffs = coeffs_late;
2100 /* ensure that coeffs and time series are still aligned */
2101 assert(sizeof(coeffs_late)/sizeof(SCIP_Real) == NTIMESERIES); /*lint !e506*/
2102
2103 /* initialize by late WBE coefficient */
2104 estim = 0.579 * treeDataGetWbe(treedata);
2105 }
2106
2107 /* combine estimation using the stage-dependent coefficients */
2108 for( t = 0; t < NTIMESERIES; ++t )
2109 {
2110 SCIP_Real testim;
2111 TSPOS tspos = tsposs[t];
2112 testim = timeSeriesEstimate(eventhdlrdata->timeseries[tspos], treedata);
2113
2114 if( testim < 0.0 )
2115 testim = treedata->nnodes;
2116
2117 estim += coeffs[t] * testim;
2118 }
2119
2120 if( estim < treedata->nnodes )
2121 return (SCIP_Real)treedata->nnodes;
2122 else
2123 return estim;
2124}
2125
2126/** get approximation of search tree completion depending on the selected method */
2127static
2129 SCIP_EVENTHDLRDATA* eventhdlrdata, /**< event handler data */
2130 SCIP_Real* completed /**< pointer to store the search tree completion */
2131 )
2132{
2133 SCIP_Real values[9];
2134 TREEDATA* treedata;
2135 char completiontype;
2136
2137 assert(eventhdlrdata != NULL);
2138 treedata = eventhdlrdata->treedata;
2139 completiontype = eventhdlrdata->completiontypeparam;
2140
2141 /* infer automatic completion type
2142 *
2143 * use regression forest if available,
2144 * or
2145 * use monotone regression if both SSG and tree weight are meaningful;
2146 * or
2147 * use tree weight or SSG, depending which one is available,
2148 * or
2149 * use gap, which is always available
2150 */
2151 if( completiontype == COMPLETIONTYPE_AUTO )
2152 {
2153 SCIP_Bool useweight = eventhdlrdata->treeisbinary;
2154 SCIP_Bool usessg = treedata->ssg->pblastsplit != SSG_STARTPRIMBOUND;/*lint !e777*/
2155
2156 if( eventhdlrdata->regforest != NULL )
2157 completiontype = COMPLETIONTYPE_REGFOREST;
2158 else if( useweight && usessg )
2159 completiontype = COMPLETIONTYPE_MONOREG;
2160 else if( useweight )
2161 completiontype = COMPLETIONTYPE_TREEWEIGHT;
2162 else if( usessg )
2163 completiontype = COMPLETIONTYPE_SSG;
2164 else
2165 completiontype = COMPLETIONTYPE_GAP;
2166 }
2167
2168 /* compute the search tree completion based on the selected method */
2169 switch (completiontype)
2170 {
2171 /* use regression forest */
2173 values[0] = timeSeriesGetValue(eventhdlrdata->timeseries[TSPOS_TREEWEIGHT]);
2174 values[1] = doubleExpSmoothGetTrend(&eventhdlrdata->timeseries[TSPOS_TREEWEIGHT]->des);
2175 values[2] = timeSeriesGetValue(eventhdlrdata->timeseries[TSPOS_SSG]);
2176 values[3] = doubleExpSmoothGetTrend(&eventhdlrdata->timeseries[TSPOS_SSG]->des);
2177 values[4] = timeSeriesGetValue(eventhdlrdata->timeseries[TSPOS_LFREQ]);
2178 values[5] = doubleExpSmoothGetTrend(&eventhdlrdata->timeseries[TSPOS_LFREQ]->des);
2179 values[6] = timeSeriesGetValue(eventhdlrdata->timeseries[TSPOS_GAP]);
2180 values[7] = doubleExpSmoothGetTrend(&eventhdlrdata->timeseries[TSPOS_GAP]->des);
2181 values[8] = doubleExpSmoothGetTrend(&eventhdlrdata->timeseries[TSPOS_OPEN]->des) < 0 ? 1.0 : 0.0;
2182
2183 *completed = SCIPregForestPredict(eventhdlrdata->regforest, values);
2184 break;
2185
2186 /* interpolate between ssg and tree weight */
2188 *completed = eventhdlrdata->coefmonoweight * (SCIP_Real)treedata->weight +
2189 eventhdlrdata->coefmonossg * (1.0 - treedata->ssg->value);
2190 break;
2191
2193 *completed = (SCIP_Real)treedata->weight;
2194 break;
2195
2196 case COMPLETIONTYPE_GAP:
2197 *completed = timeSeriesGetValue(eventhdlrdata->timeseries[TSPOS_GAP]); /* gap is stored as 1 - gap */
2198 break;
2199
2200 case COMPLETIONTYPE_SSG:
2201 *completed = 1.0 - treedata->ssg->value; /* ssg is decreasing */
2202 break;
2203
2204 default:
2205 SCIPerrorMessage("Unsupported completion type '%c'\n", completiontype);
2206 SCIPABORT();
2208 }
2209 return SCIP_OKAY;
2210}
2211
2212/** tree size estimation based on search tree completion */
2213static
2215 SCIP* scip, /**< SCIP data structure */
2216 SCIP_EVENTHDLRDATA* eventhdlrdata, /**< event handler data */
2217 SCIP_Real* estim /**< pointer to store the estimation value */
2218 )
2219{
2220 SCIP_Real completed;
2221
2222 *estim = -1.0;
2223
2224 SCIP_CALL( getSearchCompletion(eventhdlrdata, &completed) );
2225
2226 completed = MIN(completed, 1.0);
2227
2228 if( completed > 0.0 )
2229 *estim = SCIPgetNNodes(scip) / completed;
2230
2231 return SCIP_OKAY;
2232}
2233
2234/** update callback at nodes */
2235static
2236DECL_TIMESERIESUPDATE(timeseriesUpdateGap)
2237{ /*lint --e{715}*/
2238 SCIP_Real primalbound;
2239 SCIP_Real dualbound;
2240
2241 assert(scip != NULL);
2242 assert(ts != NULL);
2243 assert(value != NULL);
2244
2245 /* avoid to call SCIPgetDualbound during a restart where the queue is simply emptied */
2246 if( SCIPisInRestart(scip) )
2247 {
2248 *value = timeSeriesGetValue(ts);
2249
2250 return SCIP_OKAY;
2251 }
2252
2253 primalbound = SCIPgetPrimalbound(scip);
2254 dualbound = SCIPgetDualbound(scip);
2255 if( SCIPisInfinity(scip, REALABS(primalbound)) || SCIPisInfinity(scip, REALABS(dualbound)) )
2256 *value = 0;
2257 else if( SCIPisEQ(scip, primalbound, dualbound) )
2258 *value = 1.0;
2259 else
2260 {
2261 SCIP_Real abspb;
2262 SCIP_Real absdb;
2263
2264 abspb = REALABS(primalbound);
2265 absdb = REALABS(dualbound);
2266 *value = 1.0 - REALABS(primalbound - dualbound)/MAX(abspb, absdb);
2267 }
2268
2269 /* using this max, we set the closed gap to 0 in the case where the primal and dual bound differ in their sign */
2270 *value = MAX(*value, 0.0);
2271
2272 return SCIP_OKAY;
2273}
2274
2275/** update callback at nodes */
2276static
2277DECL_TIMESERIESUPDATE(timeseriesUpdateTreeWeight)
2278{ /*lint --e{715}*/
2279 *value = (SCIP_Real)treedata->weight;
2280
2281 return SCIP_OKAY;
2282}
2283
2284/** update callback at nodes */
2285static
2286DECL_TIMESERIESUPDATE(timeseriesUpdateLeafFreq)
2287{ /*lint --e{715}*/
2288 if( treedata->nvisited == 0 )
2289 *value = -0.5;
2290 else
2291 *value = (treedata->nleaves - 0.5)/(SCIP_Real)treedata->nvisited;
2292
2293 return SCIP_OKAY;
2294}
2295
2296/** update callback at nodes */
2297static
2298DECL_TIMESERIESUPDATE(timeseriesUpdateSsg)
2299{ /*lint --e{715}*/
2300 if( treedata->nvisited == 0 )
2301 *value = 1.0;
2302 else
2303 *value = treedata->ssg->value;
2304
2305 return SCIP_OKAY;
2306}
2307
2308/** update callback at nodes */
2309static
2310DECL_TIMESERIESUPDATE(timeseriesUpdateOpenNodes)
2311{ /*lint --e{715}*/
2312 if( treedata->nvisited == 0 )
2313 *value = 0.0;
2314 else
2315 *value = (SCIP_Real)treedata->nopen;
2316
2317 return SCIP_OKAY;
2318}
2319
2320/** include time series to forecast into event handler */
2321static
2323 SCIP* scip, /**< SCIP data structure */
2324 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */
2325 )
2326{
2327 assert(scip != NULL);
2328 assert(eventhdlrdata != NULL);
2329
2330 /* include gap time series */
2331 SCIP_CALL( timeSeriesCreate(scip, &eventhdlrdata->timeseries[TSPOS_GAP], "gap", 1.0, 0.0,
2332 DES_ALPHA_GAP, DES_BETA_GAP, timeseriesUpdateGap) );
2333
2334 /* include tree weight time series */
2335 SCIP_CALL( timeSeriesCreate(scip, &eventhdlrdata->timeseries[TSPOS_TREEWEIGHT], "tree-weight", 1.0, 0.0,
2336 DES_ALPHA_TREEWEIGHT, DES_BETA_TREEWEIGHT, timeseriesUpdateTreeWeight) );
2337
2338 /* include leaf time series */
2339 SCIP_CALL( timeSeriesCreate(scip, &eventhdlrdata->timeseries[TSPOS_LFREQ], "leaf-frequency", 0.5, -0.5,
2340 DES_ALPHA_LEAFFREQUENCY, DES_BETA_LEAFFREQUENCY, timeseriesUpdateLeafFreq) );
2341
2342 /* include SSG time series */
2343 SCIP_CALL( timeSeriesCreate(scip, &eventhdlrdata->timeseries[TSPOS_SSG], "ssg", 0.0, 1.0,
2344 DES_ALPHA_SSG, DES_BETA_SSG, timeseriesUpdateSsg) );
2345
2346 /* include open nodes time series */
2347 SCIP_CALL( timeSeriesCreate(scip, &eventhdlrdata->timeseries[TSPOS_OPEN], "open-nodes", 0.0, 0.0,
2348 DES_ALPHA_OPENNODES, DES_BETA_OPENNODES, timeseriesUpdateOpenNodes) );
2349
2350 return SCIP_OKAY;
2351}
2352
2353/** get restartpolicy based on the value of the restart parameter */
2354static
2356 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */
2357 )
2358{
2359 switch (eventhdlrdata->restartpolicyparam)
2360 {
2362 return RESTARTPOLICY_ALWAYS;
2364 return RESTARTPOLICY_NEVER;
2369 default:
2370 SCIPerrorMessage("Unknown restart policy %c\n", eventhdlrdata->restartpolicyparam);
2371 break;
2372 }
2373
2374 return RESTARTPOLICY_NEVER;
2375}
2376
2377/** check if a restart is applicable considering limit and threshold user parameters */
2378static
2380 SCIP* scip, /**< SCIP data structure */
2381 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */
2382 )
2383{
2385
2386 /* if there are no root node integer fixings, restart is usually not helpful */
2388 return FALSE;
2389
2390 /* check whether to apply restarts when there are active pricers available */
2391 if( SCIPgetNActivePricers(scip) > 0 && ! eventhdlrdata->restartactpricers )
2392 return FALSE;
2393
2394 /* check whether to apply a restart when nonlinear constraints are present */
2395 if( SCIPisNLPConstructed(scip) && ! eventhdlrdata->restartnonlinear )
2396 return FALSE;
2397
2398 /* check if max number of restarts has been reached */
2399 if( eventhdlrdata->restartlimit != -1 && eventhdlrdata->nrestartsperformed >= eventhdlrdata->restartlimit )
2400 return FALSE;
2401
2402 /* check if number of nodes exceeds the minimum number of nodes */
2403 if( eventhdlrdata->countonlyleaves )
2404 nnodes = eventhdlrdata->treedata->nleaves;
2405 else
2406 nnodes = eventhdlrdata->treedata->nvisited;
2407
2408 if( nnodes < eventhdlrdata->minnodes )
2409 return FALSE;
2410
2411 return TRUE;
2412}
2413
2414/** should a restart be applied based on the value of the selected completion method? */ /*lint --e{715}*/
2415static
2417 SCIP* scip, /**< SCIP data structure */
2418 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */
2419 )
2420{ /*lint --e{715}*/
2421 SCIP_Real completion;
2422
2423 SCIP_CALL_ABORT( getSearchCompletion(eventhdlrdata, &completion) );
2424
2425 /* if the estimation exceeds the current number of nodes by a dramatic factor, restart */
2426 if( completion < 1.0 / eventhdlrdata->restartfactor )
2427 {
2430 "Completion %.5f less than restart threshold %.5f\n",
2431 completion, 1.0 / eventhdlrdata->restartfactor);
2432 )
2433
2434 return TRUE;
2435 }
2436
2437 return FALSE;
2438}
2439
2440/** should a restart be applied based on the value of the selected completion method? */
2441static
2443 SCIP* scip, /**< SCIP data structure */
2444 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */
2445 )
2446{
2447 SCIP_Real estimation;
2448
2449 estimation = SCIPgetTreesizeEstimation(scip);
2450
2451 if( estimation < 0.0 )
2452 {
2455 "Estimation %g is still unavailable\n",
2456 estimation);
2457 )
2458
2459 return TRUE;
2460 }
2461
2462 /* if the estimation exceeds the current number of nodes by a dramatic factor, restart */
2463 if( estimation > eventhdlrdata->treedata->nnodes * eventhdlrdata->restartfactor )
2464 {
2467 "Estimation %g exceeds number of estimation tree nodes %" SCIP_LONGINT_FORMAT " by a factor of %.1f\n",
2468 estimation, eventhdlrdata->treedata->nnodes, estimation / eventhdlrdata->treedata->nnodes);
2469 )
2470
2471 return TRUE;
2472 }
2473
2474 return FALSE;
2475}
2476
2477/** check if a restart should be performed based on the given restart policy */
2478static
2480 SCIP* scip, /**< SCIP data structure */
2481 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */
2482 )
2483{
2484 SCIP_Bool applyrestart = FALSE;
2485
2486 switch (getRestartPolicy(eventhdlrdata))
2487 {
2489 applyrestart = TRUE;
2490 break;
2492 applyrestart = FALSE;
2493 break;
2495 applyrestart = shouldApplyRestartCompletion(scip, eventhdlrdata);
2496 break;
2498 applyrestart = shouldApplyRestartEstimation(scip, eventhdlrdata);
2499 break;
2500 default:
2501 break;
2502 }
2503
2504 return applyrestart;
2505}
2506
2507/** update all time series */
2508static
2510 SCIP* scip, /**< SCIP data structure */
2511 SCIP_EVENTHDLRDATA* eventhdlrdata, /**< event handler data */
2512 TREEDATA* treedata, /**< tree data */
2513 SCIP_Bool isleaf /**< are we at a leaf node? */
2514 )
2515{
2516 TIMESERIES** tss = eventhdlrdata->timeseries;
2517 int t;
2518
2519 /* loop over time series */
2520 for( t = 0; t < NTIMESERIES; ++t )
2521 {
2522 assert(tss[t] != NULL);
2523 SCIP_CALL( timeSeriesUpdate(scip, tss[t], treedata, isleaf) );
2524
2525#ifdef SCIP_MORE_DEBUG
2527 "Update of time series '%s', current value %.4f (%" SCIP_LONGINT_FORMAT " observations)\n",
2528 timeSeriesGetName(tss[t]), timeSeriesGetValue(tss[t]), tss[t]->nobs);
2529#endif
2530 }
2531
2532 return SCIP_OKAY;
2533}
2534
2535/** print a treesize estimation report into the string buffer */
2536static
2538 SCIP* scip, /**< SCIP data structure */
2539 SCIP_EVENTHDLRDATA* eventhdlrdata, /**< event handler data */
2540 char* strbuf, /**< string buffer */
2541 int reportnum /**< report number, or 0 to omit number */
2542 )
2543{
2544 TREEDATA* treedata = eventhdlrdata->treedata;
2545 char* ptr = strbuf;
2546 SCIP_Real completed;
2547 SCIP_Real wbeestim;
2548 char wbeestimstr[SCIP_MAXSTRLEN];
2549 int t;
2550
2551 /* print report number */
2552 if( reportnum > 0 )
2553 ptr += SCIPsnprintf(ptr, SCIP_MAXSTRLEN, "Report %d\nTime Elapsed: %.2f\n", reportnum, SCIPgetSolvingTime(scip));
2554
2555 ptr += SCIPsnprintf(ptr, SCIP_MAXSTRLEN,
2556 "Estim. Tree Size :%11" SCIP_LONGINT_FORMAT "\n",
2558
2559 SCIP_CALL_ABORT( getSearchCompletion(eventhdlrdata, &completed) );
2560
2561 completed = MIN(1.0, completed);
2562 completed = MAX(0.0, completed);
2563
2564 /* print tree data */
2565 ptr += SCIPsnprintf(ptr, SCIP_MAXSTRLEN,
2566 "%-19s: %" SCIP_LONGINT_FORMAT " nodes ("
2567 "%" SCIP_LONGINT_FORMAT " visited, "
2568 "%" SCIP_LONGINT_FORMAT " internal, "
2569 "%" SCIP_LONGINT_FORMAT " leaves, "
2570 "%" SCIP_LONGINT_FORMAT " open), "
2571 "weight: %.4Lf completed %.4f\n",
2572 "Estimation Tree",
2573 treedata->nnodes,
2574 treedata->nvisited,
2575 treedata->ninner,
2576 treedata->nleaves,
2577 treedata->nopen,
2578 treedata->weight,
2579 completed
2580 );
2581
2582 /* print estimations */
2583 ptr += SCIPsnprintf(ptr, SCIP_MAXSTRLEN, "Estimations : %10s %10s %10s %10s %10s",
2584 "estim", "value", "trend", "resolution", "smooth");
2585 ptr += SCIPsnprintf(ptr, SCIP_MAXSTRLEN, "\n");
2586
2587 wbeestim = treeDataGetWbe(eventhdlrdata->treedata);
2588 ptr += SCIPsnprintf(ptr, SCIP_MAXSTRLEN, " wbe : %10s %10s %10s %10s %10s\n",
2589 real2String(wbeestim, wbeestimstr, 0), "-", "-", "-", "-");
2590
2591 ptr += SCIPsnprintf(ptr, SCIP_MAXSTRLEN, " tree-profile : %10.0f %10s %10s %10s %10s\n",
2592 predictTotalSizeTreeProfile(scip, eventhdlrdata->treeprofile, eventhdlrdata->treeprofile_minnodesperdepth),
2593 "-", "-", "-", "-");
2594
2595 /* print time series forecasts */
2596 for( t = 0; t < NTIMESERIES; ++t )
2597 {
2598 SCIP_Real trend;
2599 SCIP_Real smoothestim;
2600 TIMESERIES* ts = eventhdlrdata->timeseries[t];
2601 char trendstr[SCIP_MAXSTRLEN];
2602 char smoothestimstr[SCIP_MAXSTRLEN];
2603
2604 trend = doubleExpSmoothGetTrend(&ts->des);
2605 smoothestim = timeSeriesGetSmoothEstimation(ts);
2606
2607 ptr += SCIPsnprintf(ptr, SCIP_MAXSTRLEN, " %-17s: %10.0f %10.5f %10s %10d %10s\n",
2609 timeSeriesEstimate(ts, eventhdlrdata->treedata),
2611 real2String(trend, trendstr, 5),
2613 real2String(smoothestim, smoothestimstr, 0));
2614 }
2615
2616 if( reportnum > 0 )
2617 (void) SCIPsnprintf(ptr, SCIP_MAXSTRLEN, "End of Report %d\n", reportnum);
2618}
2619
2620
2621/** copy method for event handler plugins (called when SCIP copies plugins) */
2622static
2623SCIP_DECL_EVENTCOPY(eventCopyEstim)
2624{ /*lint --e{715}*/
2625 assert(scip != NULL);
2626
2628
2629 return SCIP_OKAY;
2630}
2631
2632/** destructor of event handler to free user data (called when SCIP is exiting) */
2633static
2634SCIP_DECL_EVENTFREE(eventFreeEstim)
2635{ /*lint --e{715}*/
2636 SCIP_EVENTHDLRDATA* eventhdlrdata;
2637
2638 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
2639 assert(eventhdlrdata != NULL);
2640
2641 freeTreeData(scip, &eventhdlrdata->treedata);
2642
2643 freeTimeSeries(scip, eventhdlrdata);
2644
2645 SCIPfreeMemory(scip, &eventhdlrdata);
2646
2647 return SCIP_OKAY;
2648}
2649
2650/** initialization method of event handler (called after problem was transformed) */
2651static
2652SCIP_DECL_EVENTINIT(eventInitEstim)
2653{ /*lint --e{715}*/
2654 SCIP_EVENTHDLRDATA* eventhdlrdata;
2655
2656 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
2657 assert(eventhdlrdata != NULL);
2658
2659 /* test if user specified a regression forest */
2660 if( 0 != strncmp(eventhdlrdata->regforestfilename, DEFAULT_REGFORESTFILENAME, strlen(DEFAULT_REGFORESTFILENAME)) )
2661 {
2662 SCIP_CALL( SCIPregForestFromFile(&eventhdlrdata->regforest, eventhdlrdata->regforestfilename) );
2663 }
2664
2665 eventhdlrdata->lastrestartrun = 0;
2666 eventhdlrdata->nrestartsperformed = 0;
2667
2668 return SCIP_OKAY;
2669}
2670
2671/** deinitialization method of event handler (called before transformed problem is freed) */
2672static
2673SCIP_DECL_EVENTEXIT(eventExitEstim)
2674{ /*lint --e{715}*/
2675 SCIP_EVENTHDLRDATA* eventhdlrdata;
2676
2677 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
2678 assert(eventhdlrdata != NULL);
2679
2680 SCIPregForestFree(&eventhdlrdata->regforest);
2681
2682 return SCIP_OKAY;
2683}
2684
2685/** solving process initialization method of event handler (called when branch and bound process is about to begin) */
2686static
2687SCIP_DECL_EVENTINITSOL(eventInitsolEstim)
2688{ /*lint --e{715}*/
2689 SCIP_EVENTHDLRDATA* eventhdlrdata;
2690
2691 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
2692 assert(eventhdlrdata != NULL);
2693
2694 eventhdlrdata->restarthitcounter = 0;
2695 eventhdlrdata->weightlastreport = 0.0;
2696 eventhdlrdata->nreports = 0;
2697
2698 /* reset tree data */
2699 SCIP_CALL( resetTreeData(scip, eventhdlrdata->treedata) );
2700
2701 resetTimeSeries(eventhdlrdata);
2702
2704
2705 if( eventhdlrdata->treeprofile_enabled )
2706 {
2707 SCIP_CALL( createTreeProfile(scip, &eventhdlrdata->treeprofile) );
2708 }
2709
2710 eventhdlrdata->treeisbinary = TRUE;
2711
2712 return SCIP_OKAY;
2713}
2714
2715/** solving process deinitialization method of event handler (called before branch and bound process data is freed) */
2716static
2717SCIP_DECL_EVENTEXITSOL(eventExitsolEstim)
2718{ /*lint --e{715}*/
2719 SCIP_EVENTHDLRDATA* eventhdlrdata;
2720
2721 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
2722 assert(eventhdlrdata != NULL);
2723
2724 if( eventhdlrdata->treeprofile != NULL )
2725 freeTreeProfile(scip, &eventhdlrdata->treeprofile);
2726
2727 SCIP_CALL( SCIPdropEvent(scip, EVENTTYPE_ESTIM, eventhdlr, NULL, -1) );
2728
2729 return SCIP_OKAY;
2730}
2731
2732/** execution method of event handler */
2733static
2734SCIP_DECL_EVENTEXEC(eventExecEstim)
2735{ /*lint --e{715}*/
2736 SCIP_EVENTHDLRDATA* eventhdlrdata;
2737 SCIP_EVENTTYPE eventtype;
2738 TREEDATA* treedata;
2739 char strbuf[SCIP_MAXSTRLEN];
2740
2741 assert(scip != NULL);
2742 assert(eventhdlr != NULL);
2743
2744 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
2745 assert(eventhdlrdata != NULL);
2746 eventtype = SCIPeventGetType(event);
2747 treedata = eventhdlrdata->treedata;
2748
2749 if( SCIPisExact(scip) )
2750 return SCIP_OKAY;
2751
2752 /* actual leaf nodes for our tree data are children/siblings/leaves or the focus node itself (deadend)
2753 * if it has not been branched on
2754 */
2755 if( eventtype == SCIP_EVENTTYPE_NODEBRANCHED || ( eventtype == SCIP_EVENTTYPE_NODEDELETE
2761 {
2762 SCIP_NODE* eventnode;
2763 int nchildren = 0;
2764
2765 if( eventtype == SCIP_EVENTTYPE_NODEBRANCHED )
2766 {
2767 nchildren = SCIPgetNChildren(scip);
2768
2769 /* update whether the tree is still binary */
2770 if( nchildren != 2 )
2771 eventhdlrdata->treeisbinary = FALSE;
2772 }
2773
2774 eventnode = SCIPeventGetNode(event);
2775 SCIP_CALL( updateTreeData(scip, treedata, eventnode, nchildren) );
2776 SCIP_CALL( updateTreeProfile(scip, eventhdlrdata->treeprofile, eventnode) );
2777
2778#ifdef SCIP_DEBUG
2779 SCIPdebugMsg(scip, "%s\n", treeDataPrint(treedata, strbuf));
2780#endif
2781
2782 SCIP_CALL( updateTimeseries(scip, eventhdlrdata, treedata, nchildren == 0) );
2783
2784 /* should a new report be printed? */
2785 if( eventhdlrdata->reportfreq >= 0 && SCIPgetStatus(scip) == SCIP_STATUS_UNKNOWN &&
2786 (eventhdlrdata->reportfreq == 0
2787 || treedata->weight >= eventhdlrdata->weightlastreport + 1.0 / (SCIP_Real)eventhdlrdata->reportfreq) )
2788 {
2789 printReport(scip, eventhdlrdata, strbuf, ++eventhdlrdata->nreports);
2790 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "%s\n", strbuf);
2791
2792 if( eventhdlrdata->reportfreq > 0 )
2793 eventhdlrdata->weightlastreport = 1 / (SCIP_Real)eventhdlrdata->reportfreq * SCIPfloor(scip, ((SCIP_Real)treedata->weight * eventhdlrdata->reportfreq));
2794 else
2795 eventhdlrdata->weightlastreport = (SCIP_Real)treedata->weight;
2796 }
2797 }
2798
2799 /* if nodes have been pruned, things are progressing, don't restart right now */
2800 if( eventtype == SCIP_EVENTTYPE_NODEDELETE )
2801 return SCIP_OKAY;
2802
2803 /* check if all conditions are met such that the event handler should run */
2804 if( !isRestartApplicable(scip, eventhdlrdata) )
2805 return SCIP_OKAY;
2806
2807 /* test if a restart should be applied */
2808 if( shouldApplyRestart(scip, eventhdlrdata) )
2809 {
2810 eventhdlrdata->restarthitcounter++;
2811
2812 if( eventhdlrdata->restarthitcounter >= eventhdlrdata->hitcounterlim )
2813 {
2814 /* safe that we triggered a restart at this run */
2815 if( !SCIPisExact(scip) && SCIPgetNRuns(scip) > eventhdlrdata->lastrestartrun )
2816 {
2817 eventhdlrdata->nrestartsperformed++;
2818
2820 "Restart triggered after %d consecutive estimations that the remaining tree will be large\n",
2821 eventhdlrdata->restarthitcounter);
2822 }
2823
2824 eventhdlrdata->lastrestartrun = SCIPgetNRuns(scip);
2825
2827 }
2828 }
2829 else
2830 {
2831 eventhdlrdata->restarthitcounter = 0;
2832 }
2833
2834 return SCIP_OKAY;
2835}
2836
2837/** output method of statistics table to output file stream 'file' */
2838static
2839SCIP_DECL_TABLEOUTPUT(tableOutputEstim)
2840{ /*lint --e{715}*/
2841 SCIP_EVENTHDLR* eventhdlr;
2842 SCIP_EVENTHDLRDATA* eventhdlrdata;
2843
2845 assert(eventhdlr != NULL);
2846
2847 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
2848 assert(eventhdlrdata != NULL);
2849
2850 if( eventhdlrdata->showstats )
2851 {
2852 char strbuf[SCIP_MAXSTRLEN];
2853 printReport(scip, eventhdlrdata, strbuf, 0);
2854 SCIPinfoMessage(scip, file, "%s", strbuf);
2855 }
2856
2857 return SCIP_OKAY;
2858}
2859
2860/** output method of search tree completion display column to output file stream 'file' */
2861static
2862SCIP_DECL_DISPOUTPUT(dispOutputCompleted)
2863{ /*lint --e{715}*/
2864 SCIP_EVENTHDLR* eventhdlr;
2865 SCIP_EVENTHDLRDATA* eventhdlrdata;
2866 TREEDATA* treedata;
2867 SCIP_Real completed;
2868
2869 assert(disp != NULL);
2870 assert(strcmp(SCIPdispGetName(disp), DISP_NAME) == 0);
2871 assert(scip != NULL);
2872
2874 assert(eventhdlr != NULL);
2875 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
2876 assert(eventhdlrdata != NULL);
2877 treedata = eventhdlrdata->treedata;
2878
2879 SCIP_CALL( getSearchCompletion(eventhdlrdata, &completed) );
2880
2881 completed = MIN(completed, 1.0);
2882
2883 if( treedata->weight >= 0.005 && completed > 0 )
2884 SCIPinfoMessage(scip, file, "%7.2f%%", 100.0 * completed);
2885 else
2886 SCIPinfoMessage(scip, file, " unknown");
2887
2888 return SCIP_OKAY;
2889}
2890
2891/** creates event handler for tree size estimation */
2893 SCIP* scip /**< SCIP data structure */
2894 )
2895{
2896 SCIP_RETCODE retcode;
2897 SCIP_EVENTHDLRDATA* eventhdlrdata = NULL;
2898 SCIP_EVENTHDLR* eventhdlr = NULL;
2899
2900 /* create estim event handler data */
2901 SCIP_CALL( SCIPallocMemory(scip, &eventhdlrdata) );
2902 BMSclearMemory(eventhdlrdata);
2903
2904 SCIP_CALL_TERMINATE( retcode, createTreeData(scip, &eventhdlrdata->treedata), TERMINATE );
2905
2907 eventExecEstim, eventhdlrdata) );
2908 assert(eventhdlr != NULL);
2909
2910 /* set non fundamental callbacks via setter functions */
2911 SCIP_CALL( SCIPsetEventhdlrCopy(scip, eventhdlr, eventCopyEstim) );
2912 SCIP_CALL( SCIPsetEventhdlrFree(scip, eventhdlr, eventFreeEstim) );
2913 SCIP_CALL( SCIPsetEventhdlrInit(scip, eventhdlr, eventInitEstim) );
2914 SCIP_CALL( SCIPsetEventhdlrExit(scip, eventhdlr, eventExitEstim) );
2915 SCIP_CALL( SCIPsetEventhdlrInitsol(scip, eventhdlr, eventInitsolEstim) );
2916 SCIP_CALL( SCIPsetEventhdlrExitsol(scip, eventhdlr, eventExitsolEstim) );
2917
2918 /* add estimation event handler parameters */
2919 SCIP_CALL( SCIPaddCharParam(scip, "estimation/restarts/restartpolicy", "restart policy: (a)lways, (c)ompletion, (e)stimation, (n)ever",
2920 &eventhdlrdata->restartpolicyparam, FALSE, DEFAULT_RESTARTPOLICY, "acen", NULL, NULL) );
2921
2922 SCIP_CALL( SCIPaddCharParam(scip, "estimation/method",
2923 "tree size estimation method: (c)ompletion, (e)nsemble, "
2924 "time series forecasts on either (g)ap, (l)eaf frequency, (o)open nodes, tree (w)eight, (s)sg, "
2925 "or (t)ree profile or w(b)e",
2926 &eventhdlrdata->estimmethod, FALSE, DEFAULT_ESTIMMETHOD, ESTIMMETHODS, NULL, NULL) );
2927
2928 SCIP_CALL( SCIPaddIntParam(scip, "estimation/restarts/restartlimit", "restart limit",
2929 &eventhdlrdata->restartlimit, FALSE, DEFAULT_RESTARTLIMIT, -1, INT_MAX, NULL, NULL) );
2930
2931 SCIP_CALL( SCIPaddLongintParam(scip, "estimation/restarts/minnodes", "minimum number of nodes before restart",
2932 &eventhdlrdata->minnodes, FALSE, DEFAULT_MINNODES, -1L, SCIP_LONGINT_MAX, NULL, NULL) );
2933
2934 SCIP_CALL( SCIPaddBoolParam(scip, "estimation/restarts/countonlyleaves", "should only leaves count for the minnodes parameter?",
2935 &eventhdlrdata->countonlyleaves, DEFAULT_COUNTONLYLEAVES, FALSE, NULL, NULL) );
2936
2937 SCIP_CALL( SCIPaddRealParam(scip, "estimation/restarts/restartfactor",
2938 "factor by which the estimated number of nodes should exceed the current number of nodes",
2939 &eventhdlrdata->restartfactor, FALSE, DEFAULT_RESTARTFACTOR, 1.0, SCIP_REAL_MAX, NULL, NULL) );
2940
2941 SCIP_CALL( SCIPaddBoolParam(scip, "estimation/restarts/restartnonlinear",
2942 "whether to apply a restart when nonlinear constraints are present",
2943 &eventhdlrdata->restartnonlinear, FALSE, DEFAULT_RESTARTNONLINEAR, NULL, NULL) );
2944
2945 SCIP_CALL( SCIPaddBoolParam(scip, "estimation/restarts/restartactpricers",
2946 "whether to apply a restart when active pricers are used",
2947 &eventhdlrdata->restartactpricers, FALSE, DEFAULT_RESTARTACTPRICERS, NULL, NULL) );
2948
2949 SCIP_CALL( SCIPaddRealParam(scip, "estimation/coefmonoweight",
2950 "coefficient of tree weight in monotone approximation of search completion",
2951 &eventhdlrdata->coefmonoweight, FALSE, DEFAULT_COEFMONOWEIGHT, 0.0, 1.0, NULL, NULL) );
2952
2953 SCIP_CALL( SCIPaddRealParam(scip, "estimation/coefmonossg",
2954 "coefficient of 1 - SSG in monotone approximation of search completion",
2955 &eventhdlrdata->coefmonossg, FALSE, DEFAULT_COEFMONOSSG, 0.0, 1.0, NULL, NULL) );
2956
2957 SCIP_CALL( SCIPaddIntParam(scip, "estimation/restarts/hitcounterlim", "limit on the number of successive samples to really trigger a restart",
2958 &eventhdlrdata->hitcounterlim, FALSE, DEFAULT_HITCOUNTERLIM, 1, INT_MAX, NULL, NULL) );
2959
2960 SCIP_CALL( SCIPaddIntParam(scip, "estimation/reportfreq",
2961 "report frequency on estimation: -1: never, 0:always, k >= 1: k times evenly during search",
2962 &eventhdlrdata->reportfreq, TRUE, DEFAULT_REPORTFREQ, -1, INT_MAX / 2, NULL, NULL) );
2963
2964 SCIP_CALL( SCIPaddStringParam(scip, "estimation/regforestfilename", "user regression forest in RFCSV format",
2965 &eventhdlrdata->regforestfilename, FALSE, DEFAULT_REGFORESTFILENAME, NULL, NULL) );
2966
2967 SCIP_CALL( SCIPaddCharParam(scip, "estimation/completiontype",
2968 "approximation of search tree completion: (a)uto, (g)ap, tree (w)eight, (m)onotone regression, (r)egression forest, (s)sg",
2969 &eventhdlrdata->completiontypeparam, FALSE, DEFAULT_COMPLETIONTYPE, "agmrsw", NULL, NULL) );
2970
2971 SCIP_CALL( SCIPaddBoolParam(scip, "estimation/treeprofile/enabled",
2972 "should the event handler collect data?",
2973 &eventhdlrdata->treeprofile_enabled, FALSE, DEFAULT_TREEPROFILE_ENABLED, NULL, NULL) );
2974
2975 SCIP_CALL( SCIPaddRealParam(scip, "estimation/treeprofile/minnodesperdepth",
2976 "minimum average number of nodes at each depth before producing estimations",
2977 &eventhdlrdata->treeprofile_minnodesperdepth, FALSE, DEFAULT_TREEPROFILE_MINNODESPERDEPTH, 1.0, SCIP_REAL_MAX, NULL, NULL) );
2978
2979 SCIP_CALL( SCIPaddBoolParam(scip, "estimation/useleafts",
2980 "use leaf nodes as basic observations for time series, or all nodes?",
2981 &eventhdlrdata->useleafts, TRUE, DEFAULT_USELEAFTS, NULL, NULL) );
2982
2983 SCIP_CALL( SCIPaddBoolParam(scip, "estimation/showstats",
2984 "should statistics be shown at the end?",
2985 &eventhdlrdata->showstats, TRUE, DEFAULT_SHOWSTATS, NULL, NULL) );
2986
2987 /* SSG parameters */
2988 SCIP_CALL( SCIPaddIntParam(scip, "estimation/ssg/nmaxsubtrees",
2989 "the maximum number of individual SSG subtrees; -1: no limit",
2990 &eventhdlrdata->treedata->ssg->nmaxsubtrees, FALSE, DEFAULT_SSG_NMAXSUBTREES, -1, INT_MAX / 2, NULL, NULL) );
2991
2992 SCIP_CALL( SCIPaddLongintParam(scip, "estimation/ssg/nminnodeslastsplit",
2993 "minimum number of nodes to process between two consecutive SSG splits",
2994 &eventhdlrdata->treedata->ssg->nminnodeslastsplit, FALSE, DEFAULT_SSG_NMINNODESLASTSPLIT, 0L, SCIP_LONGINT_MAX, NULL, NULL) );
2995
2996 /* include statistics table */
2998 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputEstim, NULL,
3000
3001 /* include time series into event handler */
3002 SCIP_CALL( includeTimeseries(scip, eventhdlrdata) );
3003
3004 /* include display column */
3006 NULL, NULL, NULL, NULL, NULL, NULL, dispOutputCompleted,
3008
3009TERMINATE:
3010 if( retcode != SCIP_OKAY )
3011 {
3012 freeTreeData(scip, &eventhdlrdata->treedata);
3013 SCIPfreeMemory(scip, &eventhdlrdata);
3014 }
3015
3016 return retcode;
3017}
3018
3019/** return an estimation of the final tree size */
3021 SCIP* scip /**< SCIP data structure */
3022 )
3023{
3024 SCIP_EVENTHDLR* eventhdlr;
3025 SCIP_EVENTHDLRDATA* eventhdlrdata;
3026 TSPOS tspos = TSPOS_NONE;
3027 SCIP_Real estim;
3028
3029 assert(scip != NULL);
3030
3032 if( eventhdlr == NULL )
3033 {
3034 SCIPwarningMessage(scip, "SCIPgetTreesizeEstimation() called, but event handler " EVENTHDLR_NAME " is missing.\n");
3035 return -1.0;
3036 }
3037
3038 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
3039 assert(eventhdlrdata != NULL);
3040
3041 switch (eventhdlrdata->estimmethod)
3042 {
3043 case ESTIMMETHOD_COMPL:
3044 SCIP_CALL_ABORT( getEstimCompletion(scip, eventhdlrdata, &estim) );
3045 return estim;
3046
3047 case ESTIMMETHOD_ENSMBL:
3048 return getEnsembleEstimation(eventhdlrdata);
3049
3050 /* for the requested time series methods, we specify the array position */
3051 case ESTIMMETHOD_GAP:
3052 tspos = TSPOS_GAP;
3053 break;
3054
3055 case ESTIMMETHOD_LFREQ:
3056 tspos = TSPOS_LFREQ;
3057 break;
3058
3059 case ESTIMMETHOD_OPEN:
3060 tspos = TSPOS_OPEN;
3061 break;
3062
3064 tspos = TSPOS_TREEWEIGHT;
3065 break;
3066
3067 case ESTIMMETHOD_SSG:
3068 tspos = TSPOS_SSG;
3069 break;
3070
3071 /* tree profile estimation */
3072 case ESTIMMETHOD_TPROF:
3073 return predictTotalSizeTreeProfile(scip, eventhdlrdata->treeprofile, eventhdlrdata->treeprofile_minnodesperdepth);
3074
3075 /* Weighted backtrack estimation */
3076 case ESTIMMETHOD_WBE:
3077 return treeDataGetWbe(eventhdlrdata->treedata);
3078
3079 default:
3080 SCIPerrorMessage("Unknown estimation '%c' method specified, should be one of [%s]\n",
3081 eventhdlrdata->estimmethod, ESTIMMETHODS);
3082 SCIPABORT();
3083 break;
3084 }
3085
3086 assert(tspos != TSPOS_NONE);
3087 return (tspos == TSPOS_NONE ? -1.0 : timeSeriesEstimate(eventhdlrdata->timeseries[tspos], eventhdlrdata->treedata));
3088}
#define EVENTHDLR_NAME
#define EVENTHDLR_DESC
#define NULL
Definition def.h:255
#define SCIP_MAXSTRLEN
Definition def.h:276
#define SCIP_Longint
Definition def.h:148
#define SCIP_REAL_MAX
Definition def.h:165
#define SCIP_INVALID
Definition def.h:185
#define SCIP_Bool
Definition def.h:98
#define MIN(x, y)
Definition def.h:231
#define SCIP_ALLOC(x)
Definition def.h:373
#define SCIP_ALLOC_TERMINATE(retcode, x, TERM)
Definition def.h:393
#define SCIP_Real
Definition def.h:163
#define TRUE
Definition def.h:100
#define FALSE
Definition def.h:101
#define MAX(x, y)
Definition def.h:227
#define SCIP_CALL_ABORT(x)
Definition def.h:341
#define SCIP_CALL_TERMINATE(retcode, x, TERM)
Definition def.h:383
#define SCIP_LONGINT_FORMAT
Definition def.h:155
#define SCIPABORT()
Definition def.h:334
#define REALABS(x)
Definition def.h:189
#define SCIP_LONGINT_MAX
Definition def.h:149
#define EPSZ(x, eps)
Definition def.h:195
#define SCIP_CALL(x)
Definition def.h:362
static void SCIPregForestFree(SCIP_REGFOREST **regforest)
static char * timeSeriesGetName(TIMESERIES *timeseries)
static SCIP_RETCODE subtreeSumGapComputeFromScratchEfficiently(SCIP *scip, SUBTREESUMGAP *ssg, SCIP_Bool updatescaling)
enum RestartPolicy RESTARTPOLICY
#define DEFAULT_COEFMONOWEIGHT
static SCIP_RETCODE subtreeSumGapSplit(SCIP *scip, SUBTREESUMGAP *ssg, SCIP_Bool addfocusnode)
#define DES_BETA_TREEWEIGHT
static void freeTreeProfile(SCIP *scip, TREEPROFILE **treeprofile)
static SCIP_RETCODE updateTreeData(SCIP *scip, TREEDATA *treedata, SCIP_NODE *node, int nchildren)
#define DEFAULT_SHOWSTATS
#define DEFAULT_RESTARTLIMIT
static SCIP_Real getEnsembleEstimation(SCIP_EVENTHDLRDATA *eventhdlrdata)
static SCIP_Bool shouldApplyRestart(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata)
#define DES_ALPHA_TREEWEIGHT
#define DES_ALPHA_OPENNODES
#define MAX_REGFORESTSIZE
#define RESTARTPOLICY_CHAR_ALWAYS
TsPos
@ TSPOS_TREEWEIGHT
@ TSPOS_GAP
@ TSPOS_NONE
@ TSPOS_OPEN
@ TSPOS_SSG
@ TSPOS_LFREQ
#define RESTARTPOLICY_CHAR_NEVER
#define INITIALSIZE
struct TreeProfile TREEPROFILE
static SCIP_Bool isRestartApplicable(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata)
#define DEFAULT_REPORTFREQ
struct TimeSeries TIMESERIES
static void printReport(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata, char *strbuf, int reportnum)
static SCIP_Real timeSeriesGetSmoothEstimation(TIMESERIES *timeseries)
static SCIP_RETCODE subtreeSumGapCreate(SCIP *scip, SUBTREESUMGAP **ssg)
static void doubleExpSmoothUpdate(DOUBLEEXPSMOOTH *des, SCIP_Real xnew)
static void copyTreeProfileStats(TREEPROFILESTATS *dest, TREEPROFILESTATS *src)
#define DEFAULT_SSG_NMAXSUBTREES
#define DES_BETA_LEAFFREQUENCY
#define TABLE_NAME
#define ESTIMMETHOD_GAP
#define DEFAULT_SSG_NMINNODESLASTSPLIT
#define DISP_PRIORITY
#define DEFAULT_MINNODES
#define COMPLETIONTYPE_REGFOREST
#define DES_USETRENDINLEVEL
#define COMPLETIONTYPE_MONOREG
#define ESTIMMETHOD_TREEWEIGHT
#define COMPLETIONTYPE_TREEWEIGHT
#define ESTIMMETHOD_LFREQ
static SCIP_RETCODE timeSeriesUpdate(SCIP *scip, TIMESERIES *timeseries, TREEDATA *treedata, SCIP_Bool isleaf)
#define DEFAULT_TREEPROFILE_ENABLED
struct TreeProfileStats TREEPROFILESTATS
static SCIP_Real SCIPregForestPredict(SCIP_REGFOREST *regforest, SCIP_Real *datapoint)
static void freeTreeData(SCIP *scip, TREEDATA **treedata)
static SCIP_RETCODE resetTreeData(SCIP *scip, TREEDATA *treedata)
static SCIP_Real timeSeriesEstimate(TIMESERIES *timeseries, TREEDATA *treedata)
enum TsPos TSPOS
static SCIP_RETCODE includeTimeseries(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata)
#define ESTIMMETHOD_ENSMBL
#define COMPLETIONTYPE_GAP
#define COMPLETIONTYPE_SSG
static void timeSeriesUpdateSmoothEstimation(TIMESERIES *timeseries, SCIP_Real estimation)
#define DEFAULT_COUNTONLYLEAVES
static SCIP_RETCODE subtreeSumGapRemoveNode(SCIP *scip, SUBTREESUMGAP *ssg, SCIP_NODE *node)
static void timeSeriesResample(TIMESERIES *timeseries)
static SCIP_RETCODE subtreeSumGapReset(SCIP *scip, SUBTREESUMGAP *ssg)
static SCIP_RETCODE updateTreeProfile(SCIP *scip, TREEPROFILE *treeprofile, SCIP_NODE *node)
static SCIP_RETCODE createTreeData(SCIP *scip, TREEDATA **treedata)
static SCIP_RETCODE getEstimCompletion(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata, SCIP_Real *estim)
#define DEFAULT_HITCOUNTERLIM
#define DISP_POSITION
#define DES_ALPHA_SSG
#define DES_BETA_OPENNODES
static SCIP_Real calcGap(SCIP *scip, SCIP_Real lowerbound)
#define ESTIMMETHOD_OPEN
static SCIP_RETCODE timeSeriesCreate(SCIP *scip, TIMESERIES **timeseries, const char *name, SCIP_Real targetvalue, SCIP_Real initialvalue, SCIP_Real alpha, SCIP_Real beta,)
#define DEFAULT_RESTARTACTPRICERS
SCIP_Real SCIPgetTreesizeEstimation(SCIP *scip)
static void timeSeriesFree(SCIP *scip, TIMESERIES **timeseries)
#define NTIMESERIES
#define DEFAULT_RESTARTFACTOR
#define SESCOEFF
#define DISP_NAME
#define DEFAULT_USELEAFTS
SCIP_RETCODE SCIPincludeEventHdlrEstim(SCIP *scip)
#define DES_ALPHA_LEAFFREQUENCY
#define DES_BETA_GAP
static SCIP_RETCODE subtreeSumGapInsertChildren(SCIP *scip, SUBTREESUMGAP *ssg)
static SCIP_Real timeSeriesGetValue(TIMESERIES *timeseries)
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)
static SCIP_RETCODE extendMemoryTreeProfile(SCIP *scip, TREEPROFILE *treeprofile, int mindepth)
static void subtreeSumGapFree(SCIP *scip, SUBTREESUMGAP **ssg)
#define DISP_HEADER
#define DECL_TIMESERIESUPDATE(x)
static void timeSeriesReset(TIMESERIES *timeseries)
#define RESTARTPOLICY_CHAR_COMPLETION
#define DISP_DESC
#define DISP_WIDTH
#define ESTIMMETHOD_WBE
#define TABLE_EARLIEST_STAGE
#define ESTIMMETHOD_TPROF
static void doubleExpSmoothInit(DOUBLEEXPSMOOTH *des, SCIP_Real x1)
#define DEFAULT_COEFMONOSSG
static SCIP_Bool isEqualTreeProfileStats(TREEPROFILESTATS *stats, TREEPROFILESTATS *other)
static int timeSeriesGetResolution(TIMESERIES *timeseries)
#define ESTIMMETHODS
static SCIP_RETCODE createTreeProfile(SCIP *scip, TREEPROFILE **treeprofile)
#define DISP_STRIPLINE
static void subtreeSumGapDelSubtrees(SCIP *scip, SUBTREESUMGAP *ssg)
static SCIP_RETCODE updateTimeseries(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata, TREEDATA *treedata, SCIP_Bool isleaf)
struct TreeData TREEDATA
static void resetTreeProfileStats(TREEPROFILESTATS *treeprofilestats)
#define TABLE_POSITION
static SCIP_Real treeDataGetWbe(TREEDATA *treedata)
static void resetTimeSeries(SCIP_EVENTHDLRDATA *eventhdlrdata)
#define DEFAULT_COMPLETIONTYPE
struct SubtreeSumGap SUBTREESUMGAP
#define EVENTTYPE_ESTIM
Definition event_estim.c:85
static SCIP_RETCODE SCIPregForestFromFile(SCIP_REGFOREST **regforest, const char *filename)
static RESTARTPOLICY getRestartPolicy(SCIP_EVENTHDLRDATA *eventhdlrdata)
struct NodeInfo NODEINFO
static SCIP_Real doubleExpSmoothGetTrend(DOUBLEEXPSMOOTH *des)
struct DoubleExpSmooth DOUBLEEXPSMOOTH
static void doubleExpSmoothReset(DOUBLEEXPSMOOTH *des, SCIP_Real initialvalue)
static char * real2String(SCIP_Real num, char *buf, int digits)
#define ESTIMMETHOD_SSG
static SCIP_RETCODE subtreeSumGapUpdate(SCIP *scip, SUBTREESUMGAP *ssg, SCIP_NODE *node, int nchildren, SCIP_Longint nsolvednodes)
static void freeTimeSeries(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata)
static SCIP_Real predictTotalSizeTreeProfile(SCIP *scip, TREEPROFILE *treeprofile, SCIP_Real minnodesperdepth)
#define DES_ALPHA_GAP
#define ESTIMMETHOD_COMPL
#define TREEPROFILE_MINSIZE
#define COMPLETIONTYPE_AUTO
static SCIP_RETCODE subtreeSumGapStoreNode(SCIP *scip, SUBTREESUMGAP *ssg, SCIP_NODE *node, int subtreeidx)
static SCIP_RETCODE getSearchCompletion(SCIP_EVENTHDLRDATA *eventhdlrdata, SCIP_Real *completed)
#define RESTARTPOLICY_CHAR_ESTIMATION
static SCIP_Real timeSeriesGetTargetValue(TIMESERIES *timeseries)
#define DEFAULT_ESTIMMETHOD
#define SSG_STARTPRIMBOUND
#define DEFAULT_RESTARTNONLINEAR
#define DEFAULT_RESTARTPOLICY
#define TABLE_DESC
static SCIP_Bool shouldApplyRestartEstimation(SCIP *scip, SCIP_EVENTHDLRDATA *eventhdlrdata)
#define DEFAULT_TREEPROFILE_MINNODESPERDEPTH
#define DES_BETA_SSG
struct SCIP_RegForest SCIP_REGFOREST
#define DEFAULT_REGFORESTFILENAME
event handler for tree size estimation and restarts
SCIP_FILE * SCIPfopen(const char *path, const char *mode)
Definition fileio.c:154
int SCIPfeof(SCIP_FILE *stream)
Definition fileio.c:228
int SCIPfclose(SCIP_FILE *fp)
Definition fileio.c:233
char * SCIPfgets(char *s, int size, SCIP_FILE *stream)
Definition fileio.c:201
#define nnodes
Definition gastrans.c:74
SCIP_STATUS SCIPgetStatus(SCIP *scip)
SCIP_STAGE SCIPgetStage(SCIP *scip)
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition misc.c:3095
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3284
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition misc.c:3143
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition misc.c:3061
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3466
SCIP_RETCODE SCIPhashmapRemoveAll(SCIP_HASHMAP *hashmap)
Definition misc.c:3676
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3482
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
#define SCIPdebugMsg
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
SCIP_RETCODE SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:111
SCIP_RETCODE SCIPaddCharParam(SCIP *scip, const char *name, const char *desc, char *valueptr, SCIP_Bool isadvanced, char defaultvalue, const char *allowedvalues, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:167
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:83
SCIP_RETCODE SCIPaddStringParam(SCIP *scip, const char *name, const char *desc, char **valueptr, SCIP_Bool isadvanced, const char *defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:194
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:139
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:57
void ** SCIPpqueueElems(SCIP_PQUEUE *pqueue)
Definition misc.c:1540
void SCIPpqueueDelPos(SCIP_PQUEUE *pqueue, int pos)
Definition misc.c:1435
SCIP_RETCODE SCIPpqueueCreate(SCIP_PQUEUE **pqueue, int initsize, SCIP_Real sizefac, SCIP_DECL_SORTPTRCOMP((*ptrcomp)),)
Definition misc.c:1297
void SCIPpqueueFree(SCIP_PQUEUE **pqueue)
Definition misc.c:1324
SCIP_RETCODE SCIPpqueueInsert(SCIP_PQUEUE *pqueue, void *elem)
Definition misc.c:1396
int SCIPpqueueNElems(SCIP_PQUEUE *pqueue)
Definition misc.c:1529
void * SCIPpqueueFirst(SCIP_PQUEUE *pqueue)
Definition misc.c:1515
const char * SCIPdispGetName(SCIP_DISP *disp)
Definition disp.c:335
SCIP_RETCODE SCIPincludeDisp(SCIP *scip, const char *name, const char *desc, const char *header, SCIP_DISPSTATUS dispstatus, SCIP_DECL_DISPCOPY((*dispcopy)), SCIP_DECL_DISPFREE((*dispfree)), SCIP_DECL_DISPINIT((*dispinit)), SCIP_DECL_DISPEXIT((*dispexit)), SCIP_DECL_DISPINITSOL((*dispinitsol)), SCIP_DECL_DISPEXITSOL((*dispexitsol)), SCIP_DECL_DISPOUTPUT((*dispoutput)), SCIP_DISPDATA *dispdata, int width, int priority, int position, SCIP_Bool stripline)
Definition scip_disp.c:55
SCIP_RETCODE SCIPsetEventhdlrFree(SCIP *scip, SCIP_EVENTHDLR *eventhdlr,)
Definition scip_event.c:157
SCIP_RETCODE SCIPsetEventhdlrInitsol(SCIP *scip, SCIP_EVENTHDLR *eventhdlr,)
Definition scip_event.c:199
SCIP_RETCODE SCIPsetEventhdlrCopy(SCIP *scip, SCIP_EVENTHDLR *eventhdlr,)
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_RETCODE SCIPsetEventhdlrExit(SCIP *scip, SCIP_EVENTHDLR *eventhdlr,)
Definition scip_event.c:185
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition scip_event.c:241
SCIP_RETCODE SCIPsetEventhdlrExitsol(SCIP *scip, SCIP_EVENTHDLR *eventhdlr,)
Definition scip_event.c:213
SCIP_EVENTHDLRDATA * SCIPeventhdlrGetData(SCIP_EVENTHDLR *eventhdlr)
Definition event.c:406
SCIP_RETCODE SCIPsetEventhdlrInit(SCIP *scip, SCIP_EVENTHDLR *eventhdlr,)
Definition scip_event.c:171
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition event.c:1194
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition scip_event.c:293
SCIP_NODE * SCIPeventGetNode(SCIP_EVENT *event)
Definition event.c:1530
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition scip_event.c:333
SCIP_Bool SCIPisExact(SCIP *scip)
Definition scip_exact.c:193
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:110
#define SCIPreallocMemoryArray(scip, ptr, newnum)
Definition scip_mem.h:70
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition scip_mem.c:57
#define SCIPallocMemoryArray(scip, ptr, num)
Definition scip_mem.h:64
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:97
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition scip_mem.h:124
#define SCIPallocClearMemoryArray(scip, ptr, num)
Definition scip_mem.h:66
#define SCIPallocMemory(scip, ptr)
Definition scip_mem.h:60
#define SCIPfreeBufferArray(scip, ptr)
Definition scip_mem.h:136
#define SCIPfreeMemoryArray(scip, ptr)
Definition scip_mem.h:80
#define SCIPfreeMemory(scip, ptr)
Definition scip_mem.h:78
#define SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition scip_nlp.c:110
SCIP_NODETYPE SCIPnodeGetType(SCIP_NODE *node)
Definition tree.c:8512
SCIP_Real SCIPnodeGetLowerbound(SCIP_NODE *node)
Definition tree.c:8542
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition tree.c:8522
SCIP_NODE * SCIPnodeGetParent(SCIP_NODE *node)
Definition tree.c:8821
int SCIPnodeGetDepth(SCIP_NODE *node)
Definition tree.c:8532
int SCIPgetNActivePricers(SCIP *scip)
SCIP_Real SCIPretransformObj(SCIP *scip, SCIP_Real obj)
Definition scip_sol.c:2136
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
SCIP_Bool SCIPisInRestart(SCIP *scip)
SCIP_Real SCIPgetPrimalbound(SCIP *scip)
SCIP_Real SCIPgetUpperbound(SCIP *scip)
SCIP_Longint SCIPgetNNodes(SCIP *scip)
SCIP_Real SCIPgetDualbound(SCIP *scip)
SCIP_Real SCIPgetLowerbound(SCIP *scip)
int SCIPgetNRuns(SCIP *scip)
int SCIPgetNRootIntFixingsRun(SCIP *scip)
SCIP_RETCODE SCIPincludeTable(SCIP *scip, const char *name, const char *desc, SCIP_Bool active, SCIP_DECL_TABLECOPY((*tablecopy)), SCIP_DECL_TABLEFREE((*tablefree)), SCIP_DECL_TABLEINIT((*tableinit)), SCIP_DECL_TABLEEXIT((*tableexit)), SCIP_DECL_TABLEINITSOL((*tableinitsol)), SCIP_DECL_TABLEEXITSOL((*tableexitsol)), SCIP_DECL_TABLEOUTPUT((*tableoutput)), SCIP_DECL_TABLECOLLECT((*tablecollect)), SCIP_TABLEDATA *tabledata, int position, SCIP_STAGE earlieststage)
Definition scip_table.c:62
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPgetNSiblings(SCIP *scip)
Definition scip_tree.c:230
int SCIPgetNChildren(SCIP *scip)
Definition scip_tree.c:188
SCIP_RETCODE SCIPgetOpenNodesData(SCIP *scip, SCIP_NODE ***leaves, SCIP_NODE ***children, SCIP_NODE ***siblings, int *nleaves, int *nchildren, int *nsiblings)
Definition scip_tree.c:398
SCIP_RETCODE SCIPgetChildren(SCIP *scip, SCIP_NODE ***children, int *nchildren)
Definition scip_tree.c:164
SCIP_NODE * SCIPgetFocusNode(SCIP *scip)
Definition scip_tree.c:72
int SCIPgetNLeaves(SCIP *scip)
Definition scip_tree.c:272
SCIP_Bool SCIPwasNodeLastBranchParent(SCIP *scip, SCIP_NODE *node)
Definition scip_tree.c:733
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10827
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition misc.c:10955
return SCIP_OKAY
int depth
assert(minobj< SCIPgetCutoffbound(scip))
SCIP_Real alpha
memory allocation routines
#define BMSfreeMemory(ptr)
Definition memory.h:145
#define BMSduplicateMemoryArray(ptr, source, num)
Definition memory.h:143
#define BMSclearMemory(ptr)
Definition memory.h:129
#define BMSallocMemoryArray(ptr, num)
Definition memory.h:123
#define BMSfreeMemoryArray(ptr)
Definition memory.h:147
#define BMSclearMemoryArray(ptr, num)
Definition memory.h:130
#define BMSfreeMemoryArrayNull(ptr)
Definition memory.h:148
#define BMSallocMemory(ptr)
Definition memory.h:118
propagator for symmetry handling
public methods for displaying runtime statistics
public methods for managing events
wrapper functions to map file i/o to standard or zlib file i/o
struct SCIP_File SCIP_FILE
Definition pub_fileio.h:43
public methods for message output
#define SCIPerrorMessage
Definition pub_message.h:64
#define SCIPdebugMessage
Definition pub_message.h:96
#define SCIPstatistic(x)
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
SCIP_Real trend
SCIP_Bool usetrendinlevel
SCIP_Real level
SCIP_Real alpha
SCIP_Real lowerbound
SCIP_NODE * node
int subtreeidx
SCIP_Real * value
SCIP_Longint nodelastsplit
SCIP_Real scalingfactor
SCIP_Real value
SCIP_PQUEUE ** subtreepqueues
SCIP_HASHMAP * nodes2info
SCIP_Longint nminnodeslastsplit
SCIP_Real pblastsplit
SCIP_Longint nobs
SCIP_Real * vals
SCIP_Real * estimation
SCIP_Real currentvalue
DOUBLEEXPSMOOTH des
char * name
SCIP_Bool useleafts
SCIP_Real initialvalue
DECL_TIMESERIESUPDATE((*timeseriesupdate))
SCIP_Real smoothestimation
SCIP_Real targetvalue
SCIP_Longint nvisited
SCIP_Longint nopen
SCIP_Longint nleaves
long double weight
SUBTREESUMGAP * ssg
SCIP_Longint ninner
SCIP_Longint nnodes
SCIP_Longint * profile
TREEPROFILESTATS lastestimatestats
SCIP_Real lastestimate
TREEPROFILESTATS stats
type definitions for displaying runtime statistics
#define SCIP_DECL_DISPOUTPUT(x)
Definition type_disp.h:140
@ SCIP_DISPSTATUS_AUTO
Definition type_disp.h:61
type definitions for managing events
struct SCIP_Eventhdlr SCIP_EVENTHDLR
Definition type_event.h:159
#define SCIP_DECL_EVENTINITSOL(x)
Definition type_event.h:224
#define SCIP_DECL_EVENTEXIT(x)
Definition type_event.h:213
struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
Definition type_event.h:160
#define SCIP_DECL_EVENTEXEC(x)
Definition type_event.h:259
#define SCIP_EVENTTYPE_NODEBRANCHED
Definition type_event.h:96
#define SCIP_DECL_EVENTCOPY(x)
Definition type_event.h:189
#define SCIP_DECL_EVENTINIT(x)
Definition type_event.h:205
#define SCIP_DECL_EVENTFREE(x)
Definition type_event.h:197
uint64_t SCIP_EVENTTYPE
Definition type_event.h:156
#define SCIP_DECL_EVENTEXITSOL(x)
Definition type_event.h:235
#define SCIP_EVENTTYPE_NODEDELETE
Definition type_event.h:97
type definitions for message output methods
@ SCIP_VERBLEVEL_HIGH
@ SCIP_VERBLEVEL_FULL
type definitions for miscellaneous datastructures
#define SCIP_DECL_PQUEUEELEMCHGPOS(x)
Definition type_misc.h:209
struct SCIP_HashMap SCIP_HASHMAP
Definition type_misc.h:106
#define SCIP_DECL_SORTPTRCOMP(x)
Definition type_misc.h:189
struct SCIP_PQueue SCIP_PQUEUE
Definition type_misc.h:82
type definitions for return codes for SCIP methods
@ SCIP_NOFILE
@ SCIP_INVALIDDATA
@ SCIP_PARAMETERWRONGVAL
@ SCIP_NOMEMORY
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
@ 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
#define SCIP_DECL_TABLEOUTPUT(x)
Definition type_table.h:124
struct SCIP_Node SCIP_NODE
Definition type_tree.h:63
@ 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