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