1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the program and library             */
4    	/*         SCIP --- Solving Constraint Integer Programs                      */
5    	/*                                                                           */
6    	/*  Copyright (c) 2002-2023 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   stat.c
26   	 * @ingroup OTHER_CFILES
27   	 * @brief  methods for problem statistics
28   	 * @author Tobias Achterberg
29   	 * @author Stefan Heinz
30   	 * @author Gregor Hendel
31   	 * @author Gerald Gamrath
32   	 * @author Marc Pfetsch
33   	 * @author Stefan Vigerske
34   	 */
35   	
36   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
37   	
38   	#include "scip/clock.h"
39   	#include "scip/history.h"
40   	#include "scip/mem.h"
41   	#include "scip/prob.h"
42   	#include "scip/pub_message.h"
43   	#include "scip/pub_misc.h"
44   	#include "scip/pub_var.h"
45   	#include "scip/set.h"
46   	#include "scip/stat.h"
47   	#include "scip/struct_set.h"
48   	#include "scip/struct_stat.h"
49   	#include "scip/var.h"
50   	#include "scip/visual.h"
51   	
52   	
53   	
54   	/** creates problem statistics data */
55   	SCIP_RETCODE SCIPstatCreate(
56   	   SCIP_STAT**           stat,               /**< pointer to problem statistics data */
57   	   BMS_BLKMEM*           blkmem,             /**< block memory */
58   	   SCIP_SET*             set,                /**< global SCIP settings */
59   	   SCIP_PROB*            transprob,          /**< transformed problem, or NULL */
60   	   SCIP_PROB*            origprob,           /**< original problem, or NULL */
61   	   SCIP_MESSAGEHDLR*     messagehdlr         /**< message handler */
62   	   )
63   	{
64   	   assert(stat != NULL);
65   	   assert(set != NULL);
66   	
67   	   SCIP_ALLOC( BMSallocMemory(stat) );
68   	
69   	   SCIP_CALL( SCIPclockCreate(&(*stat)->solvingtime, SCIP_CLOCKTYPE_DEFAULT) );
70   	   SCIP_CALL( SCIPclockCreate(&(*stat)->solvingtimeoverall, SCIP_CLOCKTYPE_DEFAULT) );
71   	   SCIP_CALL( SCIPclockCreate(&(*stat)->presolvingtime, SCIP_CLOCKTYPE_DEFAULT) );
72   	   SCIP_CALL( SCIPclockCreate(&(*stat)->presolvingtimeoverall, SCIP_CLOCKTYPE_DEFAULT) );
73   	   SCIP_CALL( SCIPclockCreate(&(*stat)->primallptime, SCIP_CLOCKTYPE_DEFAULT) );
74   	   SCIP_CALL( SCIPclockCreate(&(*stat)->duallptime, SCIP_CLOCKTYPE_DEFAULT) );
75   	   SCIP_CALL( SCIPclockCreate(&(*stat)->lexduallptime, SCIP_CLOCKTYPE_DEFAULT) );
76   	   SCIP_CALL( SCIPclockCreate(&(*stat)->barrierlptime, SCIP_CLOCKTYPE_DEFAULT) );
77   	   SCIP_CALL( SCIPclockCreate(&(*stat)->resolveinstablelptime, SCIP_CLOCKTYPE_DEFAULT) );
78   	   SCIP_CALL( SCIPclockCreate(&(*stat)->divinglptime, SCIP_CLOCKTYPE_DEFAULT) );
79   	   SCIP_CALL( SCIPclockCreate(&(*stat)->strongbranchtime, SCIP_CLOCKTYPE_DEFAULT) );
80   	   SCIP_CALL( SCIPclockCreate(&(*stat)->conflictlptime, SCIP_CLOCKTYPE_DEFAULT) );
81   	   SCIP_CALL( SCIPclockCreate(&(*stat)->lpsoltime, SCIP_CLOCKTYPE_DEFAULT) );
82   	   SCIP_CALL( SCIPclockCreate(&(*stat)->relaxsoltime, SCIP_CLOCKTYPE_DEFAULT) );
83   	   SCIP_CALL( SCIPclockCreate(&(*stat)->pseudosoltime, SCIP_CLOCKTYPE_DEFAULT) );
84   	   SCIP_CALL( SCIPclockCreate(&(*stat)->sbsoltime, SCIP_CLOCKTYPE_DEFAULT) );
85   	   SCIP_CALL( SCIPclockCreate(&(*stat)->nodeactivationtime, SCIP_CLOCKTYPE_DEFAULT) );
86   	   SCIP_CALL( SCIPclockCreate(&(*stat)->nlpsoltime, SCIP_CLOCKTYPE_DEFAULT) );
87   	   SCIP_CALL( SCIPclockCreate(&(*stat)->copyclock, SCIP_CLOCKTYPE_DEFAULT) );
88   	   SCIP_CALL( SCIPclockCreate(&(*stat)->strongpropclock, SCIP_CLOCKTYPE_DEFAULT) );
89   	   SCIP_CALL( SCIPclockCreate(&(*stat)->reoptupdatetime, SCIP_CLOCKTYPE_DEFAULT) );
90   	
91   	   /* turn statistic timing on or off, depending on the user parameter */
92   	   SCIPstatEnableOrDisableStatClocks(*stat, set->time_statistictiming);
93   	
94   	   SCIP_CALL( SCIPhistoryCreate(&(*stat)->glbhistory, blkmem) );
95   	   SCIP_CALL( SCIPhistoryCreate(&(*stat)->glbhistorycrun, blkmem) );
96   	   SCIP_CALL( SCIPvisualCreate(&(*stat)->visual, messagehdlr) );
97   	
98   	   SCIP_CALL( SCIPregressionCreate(&(*stat)->regressioncandsobjval) );
99   	
100  	   (*stat)->status = SCIP_STATUS_UNKNOWN;
101  	   (*stat)->marked_nvaridx = 0;
102  	   (*stat)->marked_ncolidx = 0;
103  	   (*stat)->marked_nrowidx = 0;
104  	   (*stat)->subscipdepth = 0;
105  	   (*stat)->detertimecnt = 0.0;
106  	   (*stat)->nreoptruns = 0;
107  	
108  	   SCIPstatReset(*stat, set, transprob, origprob);
109  	
110  	   return SCIP_OKAY;
111  	}
112  	
113  	/** frees problem statistics data */
114  	SCIP_RETCODE SCIPstatFree(
115  	   SCIP_STAT**           stat,               /**< pointer to problem statistics data */
116  	   BMS_BLKMEM*           blkmem              /**< block memory */
117  	   )
118  	{
119  	   assert(stat != NULL);
120  	   assert(*stat != NULL);
121  	
122  	   SCIPclockFree(&(*stat)->solvingtime);
123  	   SCIPclockFree(&(*stat)->solvingtimeoverall);
124  	   SCIPclockFree(&(*stat)->presolvingtime);
125  	   SCIPclockFree(&(*stat)->presolvingtimeoverall);
126  	   SCIPclockFree(&(*stat)->primallptime);
127  	   SCIPclockFree(&(*stat)->duallptime);
128  	   SCIPclockFree(&(*stat)->lexduallptime);
129  	   SCIPclockFree(&(*stat)->barrierlptime);
130  	   SCIPclockFree(&(*stat)->resolveinstablelptime);
131  	   SCIPclockFree(&(*stat)->divinglptime);
132  	   SCIPclockFree(&(*stat)->strongbranchtime);
133  	   SCIPclockFree(&(*stat)->conflictlptime);
134  	   SCIPclockFree(&(*stat)->lpsoltime);
135  	   SCIPclockFree(&(*stat)->relaxsoltime);
136  	   SCIPclockFree(&(*stat)->pseudosoltime);
137  	   SCIPclockFree(&(*stat)->sbsoltime);
138  	   SCIPclockFree(&(*stat)->nodeactivationtime);
139  	   SCIPclockFree(&(*stat)->nlpsoltime);
140  	   SCIPclockFree(&(*stat)->copyclock);
141  	   SCIPclockFree(&(*stat)->strongpropclock);
142  	   SCIPclockFree(&(*stat)->reoptupdatetime);
143  	
144  	   SCIPhistoryFree(&(*stat)->glbhistory, blkmem);
145  	   SCIPhistoryFree(&(*stat)->glbhistorycrun, blkmem);
146  	   SCIPvisualFree(&(*stat)->visual);
147  	
148  	   SCIPregressionFree(&(*stat)->regressioncandsobjval);
149  	
150  	   BMSfreeMemory(stat);
151  	
152  	   return SCIP_OKAY;
153  	}
154  	
155  	/** diables the collection of any statistic for a variable */
156  	void SCIPstatDisableVarHistory(
157  	   SCIP_STAT*            stat                /**< problem statistics data */
158  	   )
159  	{
160  	   assert(stat != NULL);
161  	
162  	   stat->collectvarhistory = FALSE;
163  	}
164  	
165  	/** enables the collection of statistics for a variable */
166  	void SCIPstatEnableVarHistory(
167  	   SCIP_STAT*            stat                /**< problem statistics data */
168  	   )
169  	{
170  	   assert(stat != NULL);
171  	
172  	   stat->collectvarhistory = TRUE;
173  	}
174  	
175  	/** marks statistics to be able to reset them when solving process is freed */
176  	void SCIPstatMark(
177  	   SCIP_STAT*            stat                /**< problem statistics data */
178  	   )
179  	{
180  	   assert(stat != NULL);
181  	
182  	   stat->marked_nvaridx = stat->nvaridx;
183  	   stat->marked_ncolidx = stat->ncolidx;
184  	   stat->marked_nrowidx = stat->nrowidx;
185  	}
186  	
187  	/** reset statistics to the data before solving started */
188  	void SCIPstatReset(
189  	   SCIP_STAT*            stat,               /**< problem statistics data */
190  	   SCIP_SET*             set,                /**< global SCIP settings */
191  	   SCIP_PROB*            transprob,          /**< transformed problem, or NULL */
192  	   SCIP_PROB*            origprob            /**< original problem, or NULL */
193  	   )
194  	{
195  	   assert(stat != NULL);
196  	   assert(stat->marked_nvaridx >= 0);
197  	   assert(stat->marked_ncolidx >= 0);
198  	   assert(stat->marked_nrowidx >= 0);
199  	
200  	   SCIPclockReset(stat->solvingtime);
201  	   SCIPclockReset(stat->presolvingtime);
202  	   SCIPclockReset(stat->primallptime);
203  	   SCIPclockReset(stat->duallptime);
204  	   SCIPclockReset(stat->lexduallptime);
205  	   SCIPclockReset(stat->barrierlptime);
206  	   SCIPclockReset(stat->resolveinstablelptime);
207  	   SCIPclockReset(stat->divinglptime);
208  	   SCIPclockReset(stat->strongbranchtime);
209  	   SCIPclockReset(stat->conflictlptime);
210  	   SCIPclockReset(stat->lpsoltime);
211  	   SCIPclockReset(stat->relaxsoltime);
212  	   SCIPclockReset(stat->pseudosoltime);
213  	   SCIPclockReset(stat->sbsoltime);
214  	   SCIPclockReset(stat->nodeactivationtime);
215  	   SCIPclockReset(stat->nlpsoltime);
216  	   SCIPclockReset(stat->copyclock);
217  	   SCIPclockReset(stat->strongpropclock);
218  	
219  	   SCIPhistoryReset(stat->glbhistory);
220  	
221  	   stat->lastsblpsolstats[0] = stat->lastsblpsolstats[1] = SCIP_LPSOLSTAT_NOTSOLVED;
222  	
223  	   stat->vsidsweight = 1.0;
224  	   stat->nlpiterations = 0;
225  	   stat->nrootlpiterations = 0;
226  	   stat->nrootfirstlpiterations = 0;
227  	   stat->nprimallpiterations = 0;
228  	   stat->nduallpiterations = 0;
229  	   stat->nlexduallpiterations = 0;
230  	   stat->nbarrierlpiterations = 0;
231  	   stat->nprimalresolvelpiterations = 0;
232  	   stat->ndualresolvelpiterations = 0;
233  	   stat->nlexdualresolvelpiterations = 0;
234  	   stat->nnodelpiterations = 0;
235  	   stat->ninitlpiterations = 0;
236  	   stat->ndivinglpiterations = 0;
237  	   stat->nsbdivinglpiterations = 0;
238  	   stat->nsblpiterations = 0;
239  	   stat->nsbtimesiterlimhit = 0L;
240  	   stat->nrootsblpiterations = 0;
241  	   stat->nconflictlpiterations = 0;
242  	   stat->nresolveinstablelps = 0;
243  	   stat->nresolveinstablelpiters = 0;
244  	   stat->ntotalnodes = 0;
245  	   stat->ntotalinternalnodes = 0;
246  	   stat->ntotalnodesmerged = 0;
247  	   stat->ncreatednodes = 0;
248  	   stat->nlpsolsfound = 0;
249  	   stat->nrelaxsolsfound = 0;
250  	   stat->npssolsfound = 0;
251  	   stat->nsbsolsfound = 0;
252  	   stat->nlpbestsolsfound = 0;
253  	   stat->nrelaxbestsolsfound = 0;
254  	   stat->npsbestsolsfound = 0;
255  	   stat->nsbbestsolsfound = 0;
256  	   stat->nexternalsolsfound = 0;
257  	   stat->domchgcount = 0;
258  	   stat->nboundchgs = 0;
259  	   stat->nholechgs = 0;
260  	   stat->nprobboundchgs = 0;
261  	   stat->nprobholechgs = 0;
262  	   stat->nsbdowndomchgs = 0;
263  	   stat->nsbupdomchgs = 0;
264  	   stat->nruns = 0;
265  	   stat->nconfrestarts = 0;
266  	   stat->nrootboundchgs = 0;
267  	   stat->nrootintfixings = 0;
268  	   stat->prevrunnvars = 0;
269  	   stat->nvaridx = stat->marked_nvaridx;
270  	   stat->ncolidx = stat->marked_ncolidx;
271  	   stat->nrowidx = stat->marked_nrowidx;
272  	   stat->nnz = 0;
273  	   stat->avgnnz = 0;
274  	   stat->lpcount = 0;
275  	   stat->relaxcount = 0;
276  	   stat->nlps = 0;
277  	   stat->nrootlps = 0;
278  	   stat->nprimallps = 0;
279  	   stat->nprimalzeroitlps = 0;
280  	   stat->nduallps = 0;
281  	   stat->ndualzeroitlps = 0;
282  	   stat->nlexduallps = 0;
283  	   stat->nbarrierlps = 0;
284  	   stat->nbarrierzeroitlps = 0;
285  	   stat->nprimalresolvelps = 0;
286  	   stat->ndualresolvelps = 0;
287  	   stat->nlexdualresolvelps = 0;
288  	   stat->nnodelps = 0;
289  	   stat->nnodezeroitlps = 0;
290  	   stat->nisstoppedcalls = 0;
291  	   stat->ninitlps = 0;
292  	   stat->ndivinglps = 0;
293  	   stat->nsbdivinglps = 0;
294  	   stat->nnumtroublelpmsgs = 0;
295  	   stat->nstrongbranchs = 0;
296  	   stat->nrootstrongbranchs = 0;
297  	   stat->nconflictlps = 0;
298  	   stat->nnlps = 0;
299  	   stat->maxtotaldepth = -1;
300  	   stat->nactiveconss = 0;
301  	   stat->nenabledconss = 0;
302  	   stat->solindex = 0;
303  	   stat->memsavemode = FALSE;
304  	   stat->nnodesbeforefirst = -1;
305  	   stat->ninitconssadded = 0;
306  	   stat->nactiveconssadded = 0;
307  	   stat->externmemestim = 0;
308  	   stat->exprlastvisitedtag = 0;
309  	   stat->exprlastsoltag = 0;
310  	   stat->exprlastdifftag = 0;
311  	   stat->nrunsbeforefirst = -1;
312  	   stat->firstprimalheur = NULL;
313  	   stat->firstprimaltime = SCIP_DEFAULT_INFINITY;
314  	   stat->firstprimalbound = SCIP_DEFAULT_INFINITY;
315  	   stat->firstsolgap = SCIP_DEFAULT_INFINITY;
316  	   stat->lastsolgap = SCIP_DEFAULT_INFINITY;
317  	   stat->primalzeroittime = 0.0;
318  	   stat->dualzeroittime = 0.0;
319  	   stat->barrierzeroittime = 0.0;
320  	   stat->maxcopytime = SCIP_REAL_MIN;
321  	   stat->mincopytime = SCIP_REAL_MAX;
322  	   stat->firstlptime = 0.0;
323  	   stat->firstlpdualbound = SCIP_UNKNOWN;
324  	   stat->ncopies = 0;
325  	   stat->nclockskipsleft = 0;
326  	   stat->nactiveexpriter = 0;
327  	   stat->marked_nvaridx = -1;
328  	   stat->marked_ncolidx = -1;
329  	   stat->marked_nrowidx = -1;
330  	   stat->branchedunbdvar = FALSE;
331  	   stat->bestefficacy = 0.0;
332  	   stat->minefficacyfac = 0.5;
333  	   stat->ncutpoolfails = 0;
334  	
335  	   stat->ndivesetlpiterations = 0;
336  	   stat->ndivesetcalls = 0;
337  	   stat->ndivesetlps = 0;
338  	   stat->totaldivesetdepth = 0;
339  	
340  	   stat->userinterrupt = FALSE;
341  	   stat->userrestart = FALSE;
342  	   stat->inrestart = FALSE;
343  	   stat->collectvarhistory = TRUE;
344  	   stat->performpresol = FALSE;
345  	   stat->disableenforelaxmsg = FALSE;
346  	
347  	   SCIPstatResetImplications(stat);
348  	   SCIPstatResetPresolving(stat, set, transprob, origprob);
349  	   SCIPstatResetPrimalDualIntegrals(stat, set, FALSE);
350  	}
351  	
352  	/** reset implication counter */
353  	void SCIPstatResetImplications(
354  	   SCIP_STAT*            stat                /**< problem statistics data */
355  	   )
356  	{
357  	   assert(stat != NULL);
358  	
359  	   stat->nimplications = 0;
360  	}
361  	
362  	/** reset presolving and current run specific statistics */
363  	void SCIPstatResetPresolving(
364  	   SCIP_STAT*            stat,               /**< problem statistics data */
365  	   SCIP_SET*             set,                /**< global SCIP settings */
366  	   SCIP_PROB*            transprob,          /**< transformed problem, or NULL if not yet existing */
367  	   SCIP_PROB*            origprob            /**< original problem, or NULL */
368  	   )
369  	{
370  	   assert(stat != NULL);
371  	
372  	   stat->npresolrounds = 0;
373  	   stat->npresolroundsfast = 0;
374  	   stat->npresolroundsmed = 0;
375  	   stat->npresolroundsext = 0;
376  	   stat->npresolfixedvars = 0;
377  	   stat->npresolaggrvars = 0;
378  	   stat->npresolchgvartypes = 0;
379  	   stat->npresolchgbds = 0;
380  	   stat->npresoladdholes = 0;
381  	   stat->npresoldelconss = 0;
382  	   stat->npresoladdconss = 0;
383  	   stat->npresolupgdconss = 0;
384  	   stat->npresolchgcoefs = 0;
385  	   stat->npresolchgsides = 0;
386  	
387  	   SCIPstatResetCurrentRun(stat, set, transprob, origprob, FALSE);
388  	}
389  	
390  	/** reset primal-dual, primal-reference, and reference-dual integral */
391  	void SCIPstatResetPrimalDualIntegrals(
392  	   SCIP_STAT*            stat,               /**< problem statistics data */
393  	   SCIP_SET*             set,                /**< global SCIP settings */
394  	   SCIP_Bool             partialreset        /**< should time and integral value be kept? (in combination with no statistical
395  	                                              *   reset, integrals are added for each problem to be solved) */
396  	   )
397  	{
398  	   assert(stat != NULL);
399  	
400  	   stat->previousgap = 100.0;
401  	   stat->previousdualrefgap = 100.0;
402  	   stat->previousprimalrefgap = 100.0;
403  	   stat->lastprimalbound = SCIP_UNKNOWN;
404  	   stat->lastdualbound = SCIP_UNKNOWN;
405  	   stat->lastlowerbound = -SCIPsetInfinity(set);
406  	   stat->lastupperbound = SCIPsetInfinity(set);
407  	
408  	   /* partial resets keep the integral value and previous evaluation time */
409  	   if( !partialreset )
410  	   {
411  	      stat->previntegralevaltime = 0.0;
412  	      stat->dualrefintegral = 0.0;
413  	      stat->primalrefintegral = 0.0;
414  	      stat->primaldualintegral = 0.0;
415  	   }
416  	}
417  	
418  	/** returns the gap bounded by 100 */
419  	static
420  	SCIP_Real getGap(
421  	   SCIP_SET*             set,                /**< global SCIP settings */
422  	   SCIP_Real             primalbound,        /**< current primal bound */
423  	   SCIP_Real             dualbound,          /**< current dual bound */
424  	   SCIP_Real             upperbound,         /**< current upper bound in transformed problem, or infinity */
425  	   SCIP_Real             lowerbound          /**< current lower bound in transformed space, or -infinity */
426  	   )
427  	{
428  	   SCIP_Real gap;
429  	
430  	   /* computation of the gap, special cases are handled first */
431  	   if( primalbound >= SCIP_UNKNOWN || dualbound >= SCIP_UNKNOWN ) /*lint !e777*/
432  	      gap = 100.0;
433  	   /* the gap is 0.0 if bounds coincide */
434  	   else if( SCIPsetIsGE(set, lowerbound, upperbound) || SCIPsetIsEQ(set, primalbound, dualbound) )
435  	      gap = 0.0;
436  	   /* the gap is 100.0 if bounds have different signs */
437  	   else if( primalbound * dualbound <= 0.0 ) /*lint !e777*/
438  	      gap = 100.0;
439  	   else if( !SCIPsetIsInfinity(set, REALABS(primalbound)) && !SCIPsetIsInfinity(set, REALABS(dualbound)) )
440  	   {
441  	      SCIP_Real absprim = REALABS(primalbound);
442  	      SCIP_Real absdual = REALABS(dualbound);
443  	
444  	      /* The gap in the definition of the primal-dual integral differs from the default SCIP gap function.
445  	       * Here, the MAX(primalbound, dualbound) is taken for gap quotient in order to ensure a gap <= 100.
446  	       */
447  	      gap = 100.0 * REALABS(primalbound - dualbound) / MAX(absprim, absdual);
448  	      assert(SCIPsetIsLE(set, gap, 100.0));
449  	   }
450  	   else
451  	      gap = 100.0;
452  	
453  	   return gap;
454  	}
455  	
456  	/** update the primal-dual, primal-reference, and reference-dual integral statistics.
457  	 *  method accepts + and - SCIPsetInfinity() as values for upper and lower bound, respectively
458  	 */
459  	void SCIPstatUpdatePrimalDualIntegrals(
460  	   SCIP_STAT*            stat,               /**< problem statistics data */
461  	   SCIP_SET*             set,                /**< global SCIP settings */
462  	   SCIP_PROB*            transprob,          /**< transformed problem */
463  	   SCIP_PROB*            origprob,           /**< original problem */
464  	   SCIP_Real             upperbound,         /**< current upper bound in transformed problem, or infinity */
465  	   SCIP_Real             lowerbound          /**< current lower bound in transformed space, or -infinity */
466  	   )
467  	{
468  	   SCIP_Real currentgap;
469  	   SCIP_Real currentdualrefgap;
470  	   SCIP_Real currentprimalrefgap;
471  	   SCIP_Real solvingtime;
472  	   SCIP_Real primalbound;
473  	   SCIP_Real dualbound;
474  	   SCIP_Real deltatime;
475  	
476  	   assert(stat != NULL);
477  	   assert(set != NULL);
478  	
479  	   solvingtime = SCIPclockGetTime(stat->solvingtime);
480  	   assert(solvingtime >= stat->previntegralevaltime);
481  	
482  	   if( !SCIPsetIsInfinity(set, upperbound) ) /*lint !e777*/
483  	   {
484  	      /* get value in original space for gap calculation */
485  	      primalbound = SCIPprobExternObjval(transprob, origprob, set, upperbound);
486  	
487  	      if( SCIPsetIsZero(set, primalbound) )
488  	         primalbound = 0.0;
489  	   }
490  	   else
491  	   {
492  	      /* no new upper bound: use stored values from last update */
493  	      upperbound = stat->lastupperbound;
494  	      primalbound = stat->lastprimalbound;
495  	      assert(SCIPsetIsZero(set, primalbound) == (primalbound == 0.0)); /*lint !e777*/
496  	   }
497  	
498  	   if( !SCIPsetIsInfinity(set, -lowerbound) ) /*lint !e777*/
499  	   {
500  	      /* get value in original space for gap calculation */
501  	      dualbound = SCIPprobExternObjval(transprob, origprob, set, lowerbound);
502  	
503  	      if( SCIPsetIsZero(set, dualbound) )
504  	         dualbound = 0.0;
505  	   }
506  	   else
507  	   {
508  	      /* no new lower bound: use stored values from last update */
509  	      lowerbound = stat->lastlowerbound;
510  	      dualbound = stat->lastdualbound;
511  	      assert(SCIPsetIsZero(set, dualbound) == (dualbound == 0.0)); /*lint !e777*/
512  	   }
513  	
514  	   /* calculate primal-dual and dual reference gap */
515  	   currentgap = getGap(set, primalbound, dualbound, upperbound, lowerbound);
516  	
517  	   /* if primal and dual bound have opposite signs, the gap always evaluates to 100.0% */
518  	   assert(currentgap == 0.0 || currentgap == 100.0 || SCIPsetIsGE(set, primalbound * dualbound, 0.0));
519  	
520  	   /* update the integral based on previous information */
521  	   deltatime = solvingtime - stat->previntegralevaltime;
522  	   stat->primaldualintegral += deltatime * stat->previousgap;
523  	   stat->dualrefintegral += deltatime * stat->previousdualrefgap;
524  	   stat->primalrefintegral += deltatime * stat->previousprimalrefgap;
525  	
526  	   if( !SCIPsetIsInfinity(set, REALABS(set->misc_referencevalue)) )
527  	   {
528  	      currentdualrefgap = getGap(set, set->misc_referencevalue, dualbound, upperbound, lowerbound);
529  	      assert(currentdualrefgap == 0.0 || currentdualrefgap == 100.0 || SCIPsetIsGE(set, set->misc_referencevalue * dualbound, 0.0));
530  	
531  	      currentprimalrefgap = getGap(set, primalbound, set->misc_referencevalue, upperbound, lowerbound);
532  	      assert(currentprimalrefgap == 0.0 || currentprimalrefgap == 100.0 || SCIPsetIsGE(set, primalbound * set->misc_referencevalue, 0.0));
533  	   }
534  	   else
535  	   {
536  	      currentdualrefgap = 100.0;
537  	      currentprimalrefgap = 100.0;
538  	   }
539  	
540  	   /* update all relevant information for next evaluation */
541  	   stat->previousgap = currentgap;
542  	   stat->previousdualrefgap = currentdualrefgap;
543  	   stat->previousprimalrefgap = currentprimalrefgap;
544  	   stat->previntegralevaltime = solvingtime;
545  	   stat->lastprimalbound = primalbound;
546  	   stat->lastdualbound = dualbound;
547  	   stat->lastlowerbound = lowerbound;
548  	   stat->lastupperbound = upperbound;
549  	}
550  	
551  	/** optionally update and return the reference-dual integral statistic */
552  	SCIP_Real SCIPstatGetDualReferenceIntegral(
553  	   SCIP_STAT*            stat,               /**< problem statistics data */
554  	   SCIP_SET*             set,                /**< global SCIP settings */
555  	   SCIP_PROB*            transprob,          /**< transformed problem */
556  	   SCIP_PROB*            origprob,           /**< original problem */
557  	   SCIP_Bool             update              /**< should the value be updated first? */
558  	   )
559  	{
560  	   assert(stat != NULL);
561  	   assert(set != NULL);
562  	   assert(transprob != NULL);
563  	   assert(origprob != NULL);
564  	
565  	   /* update the reference-dual integral first */
566  	   if( update )
567  	      SCIPstatUpdatePrimalDualIntegrals(stat, set, transprob, origprob, SCIPsetInfinity(set), -SCIPsetInfinity(set));
568  	
569  	   return stat->dualrefintegral;
570  	}
571  	
572  	/** optionally update and return the primal-reference integral statistic */
573  	SCIP_Real SCIPstatGetPrimalReferenceIntegral(
574  	   SCIP_STAT*            stat,               /**< problem statistics data */
575  	   SCIP_SET*             set,                /**< global SCIP settings */
576  	   SCIP_PROB*            transprob,          /**< transformed problem */
577  	   SCIP_PROB*            origprob,           /**< original problem */
578  	   SCIP_Bool             update              /**< should the value be updated first? */
579  	   )
580  	{
581  	   assert(stat != NULL);
582  	   assert(set != NULL);
583  	   assert(transprob != NULL);
584  	   assert(origprob != NULL);
585  	
586  	   /* update the primal-reference integral first */
587  	   if( update )
588  	      SCIPstatUpdatePrimalDualIntegrals(stat, set, transprob, origprob, SCIPsetInfinity(set), -SCIPsetInfinity(set));
589  	
590  	   return stat->primalrefintegral;
591  	}
592  	
593  	/** optionally update and return the primal-dual integral statistic */
594  	SCIP_Real SCIPstatGetPrimalDualIntegral(
595  	   SCIP_STAT*            stat,               /**< problem statistics data */
596  	   SCIP_SET*             set,                /**< global SCIP settings */
597  	   SCIP_PROB*            transprob,          /**< transformed problem */
598  	   SCIP_PROB*            origprob,           /**< original problem */
599  	   SCIP_Bool             update              /**< should the value be updated first? */
600  	   )
601  	{
602  	   assert(stat != NULL);
603  	   assert(set != NULL);
604  	   assert(transprob != NULL);
605  	   assert(origprob != NULL);
606  	
607  	   /* update the primal dual reference integral first */
608  	   if( update )
609  	      SCIPstatUpdatePrimalDualIntegrals(stat, set, transprob, origprob, SCIPsetInfinity(set), -SCIPsetInfinity(set));
610  	
611  	   return stat->primaldualintegral;
612  	}
613  	
614  	/** reset current branch and bound run specific statistics */
615  	void SCIPstatResetCurrentRun(
616  	   SCIP_STAT*            stat,               /**< problem statistics data */
617  	   SCIP_SET*             set,                /**< global SCIP settings */
618  	   SCIP_PROB*            transprob,          /**< transformed problem, or NULL */
619  	   SCIP_PROB*            origprob,           /**< original problem, or NULL */
620  	   SCIP_Bool             solved              /**< is problem already solved? */
621  	   )
622  	{
623  	   assert(stat != NULL);
624  	
625  	   stat->nnodes = 0;
626  	   stat->ninternalnodes = 0;
627  	   stat->ncreatednodesrun = 0;
628  	   stat->nactivatednodes = 0;
629  	   stat->ndeactivatednodes = 0;
630  	   stat->nbacktracks = 0;
631  	   stat->ndelayedcutoffs = 0;
632  	   stat->nreprops = 0;
633  	   stat->nrepropboundchgs = 0;
634  	   stat->nrepropcutoffs = 0;
635  	   stat->lastdivenode = 0;
636  	   stat->lastconflictnode = 0;
637  	   stat->bestsolnode = 0;
638  	   stat->rootlowerbound = SCIP_REAL_MIN;
639  	   stat->lastbranchvalue = SCIP_UNKNOWN;
640  	   stat->rootlpbestestimate = SCIP_INVALID;
641  	   stat->lastbranchvar = NULL;
642  	   stat->lastbranchdir = SCIP_BRANCHDIR_DOWNWARDS;
643  	   stat->nrootboundchgsrun = 0;
644  	   stat->nrootintfixingsrun = 0;
645  	   stat->npricerounds = 0;
646  	   stat->nseparounds = 0;
647  	   stat->maxdepth = -1;
648  	   stat->plungedepth = 0;
649  	   stat->nobjleaves = 0;
650  	   stat->ninfeasleaves = 0;
651  	   stat->nfeasleaves = 0;
652  	   stat->branchedunbdvar = FALSE;
653  	   stat->nnumtroublelpmsgs = 0;
654  	
655  	   stat->nearlybacktracks = 0;
656  	   stat->nnodesaboverefbound = 0;
657  	
658  	   assert(transprob == NULL || origprob != NULL);
659  	   /* calculate the reference bound in transformed space from the reference value */
660  	   if( transprob != NULL && !SCIPsetIsInfinity(set, SCIPsetGetReferencevalue(set)) )
661  	      stat->referencebound = SCIPprobInternObjval(transprob, origprob, set, SCIPsetGetReferencevalue(set));
662  	   else
663  	      stat->referencebound = SCIPsetInfinity(set);
664  	
665  	   if( !solved )
666  	      stat->status = SCIP_STATUS_UNKNOWN;
667  	
668  	   SCIPhistoryReset(stat->glbhistorycrun);
669  	
670  	   SCIPregressionReset(stat->regressioncandsobjval);
671  	
672  	   SCIPstatResetDisplay(stat);
673  	}
674  	
675  	/** resets display statistics, such that a new header line is displayed before the next display line */
676  	void SCIPstatResetDisplay(
677  	   SCIP_STAT*            stat                /**< problem statistics data */
678  	   )
679  	{
680  	   assert(stat != NULL);
681  	
682  	   stat->lastdispnode = 0;
683  	   stat->ndisplines = 0;
684  	}
685  	
686  	/** increases LP count, such that all lazy updates depending on the LP are enforced again */
687  	void SCIPstatEnforceLPUpdates(
688  	   SCIP_STAT*            stat                /**< problem statistics data */
689  	   )
690  	{
691  	   assert(stat != NULL);
692  	
693  	   stat->lpcount++;
694  	}
695  	
696  	/** depending on the current memory usage, switches mode flag to standard or memory saving mode */
697  	void SCIPstatUpdateMemsaveMode(
698  	   SCIP_STAT*            stat,               /**< problem statistics data */
699  	   SCIP_SET*             set,                /**< global SCIP settings */
700  	   SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
701  	   SCIP_MEM*             mem                 /**< block memory pools */
702  	   )
703  	{
704  	   assert(stat != NULL);
705  	   assert(set != NULL);
706  	
707  	   if( SCIPsetIsLT(set, set->mem_savefac, 1.0) )
708  	   {
709  	      SCIP_Longint memused;
710  	
711  	      memused = SCIPmemGetTotal(mem);
712  	      if( !stat->memsavemode && memused >= set->mem_savefac * set->limit_memory * 1024.0 * 1024.0 )
713  	      {
714  	         /* switch to memory saving mode */
715  	         SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_HIGH,
716  	            "(node %" SCIP_LONGINT_FORMAT ") switching to memory saving mode (mem: %.1fM/%.1fM)\n",
717  	            stat->nnodes, (SCIP_Real)memused/(1024.0*1024.0), set->limit_memory);
718  	         stat->memsavemode = TRUE;
719  	         set->nodesel = NULL;
720  	      }
721  	      else if( stat->memsavemode && memused < 0.5 * set->mem_savefac * set->limit_memory * 1024.0 * 1024.0 )
722  	      {
723  	         /* switch to standard mode */
724  	         SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_HIGH,
725  	            "(node %" SCIP_LONGINT_FORMAT ") switching to standard mode (mem: %.1fM/%.1fM)\n",
726  	            stat->nnodes, (SCIP_Real)memused/(1024.0*1024.0), set->limit_memory);
727  	         stat->memsavemode = FALSE;
728  	         set->nodesel = NULL;
729  	      }
730  	   }
731  	   else
732  	      stat->memsavemode = FALSE;
733  	}
734  	
735  	/** returns the estimated number of bytes used by extern software, e.g., the LP solver */
736  	SCIP_Longint SCIPstatGetMemExternEstim(
737  	   SCIP_STAT*            stat                /**< dynamic SCIP statistics */
738  	   )
739  	{
740  	   return stat->externmemestim;
741  	}
742  	
743  	/** enables or disables all statistic clocks of \p stat concerning LP execution time, strong branching time, etc.
744  	 *
745  	 *  @note: The (pre-)solving time clocks which are relevant for the output during (pre-)solving
746  	 *         are not affected by this method
747  	 *
748  	 *  @see: For completely disabling all timing of SCIP, consider setting the parameter timing/enabled to FALSE
749  	 */
750  	void SCIPstatEnableOrDisableStatClocks(
751  	   SCIP_STAT*            stat,               /**< SCIP statistics */
752  	   SCIP_Bool             enable              /**< should the LP clocks be enabled? */
753  	   )
754  	{
755  	   assert(stat != NULL);
756  	
757  	   SCIPclockEnableOrDisable(stat->primallptime, enable);
758  	   SCIPclockEnableOrDisable(stat->duallptime, enable);
759  	   SCIPclockEnableOrDisable(stat->lexduallptime, enable);
760  	   SCIPclockEnableOrDisable(stat->barrierlptime, enable);
761  	   SCIPclockEnableOrDisable(stat->resolveinstablelptime, enable);
762  	   SCIPclockEnableOrDisable(stat->divinglptime, enable);
763  	   SCIPclockEnableOrDisable(stat->strongbranchtime, enable);
764  	   SCIPclockEnableOrDisable(stat->conflictlptime, enable);
765  	   SCIPclockEnableOrDisable(stat->lpsoltime, enable);
766  	   SCIPclockEnableOrDisable(stat->relaxsoltime, enable);
767  	   SCIPclockEnableOrDisable(stat->pseudosoltime, enable);
768  	   SCIPclockEnableOrDisable(stat->sbsoltime, enable);
769  	   SCIPclockEnableOrDisable(stat->nodeactivationtime, enable);
770  	   SCIPclockEnableOrDisable(stat->nlpsoltime, enable);
771  	   SCIPclockEnableOrDisable(stat->copyclock, enable);
772  	   SCIPclockEnableOrDisable(stat->strongpropclock, enable);
773  	}
774  	
775  	/** recompute root LP best-estimate from scratch */
776  	void SCIPstatComputeRootLPBestEstimate(
777  	   SCIP_STAT*            stat,               /**< SCIP statistics */
778  	   SCIP_SET*             set,                /**< global SCIP settings */
779  	   SCIP_Real             rootlpobjval,       /**< root LP objective value */
780  	   SCIP_VAR**            vars,               /**< problem variables */
781  	   int                   nvars               /**< number of variables */
782  	   )
783  	{
784  	   int v;
785  	   stat->rootlpbestestimate = rootlpobjval;
786  	
787  	   /* compute best-estimate contribution for every variable */
788  	   for( v = 0; v < nvars; ++v )
789  	   {
790  	      SCIP_Real rootlpsol;
791  	      SCIP_Real varminpseudoscore;
792  	
793  	      /* stop at the first continuous variable */
794  	      if( !SCIPvarIsIntegral(vars[v]) )
795  	         break;
796  	
797  	      rootlpsol = SCIPvarGetRootSol(vars[v]);
798  	      varminpseudoscore = SCIPvarGetMinPseudocostScore(vars[v], stat, set, rootlpsol);
799  	      assert(varminpseudoscore >= 0);
800  	      stat->rootlpbestestimate += varminpseudoscore;
801  	
802  	      SCIPstatDebugMsg(stat, "Root LP Estimate initialization: <%s> + %15.9f\n", SCIPvarGetName(vars[v]), varminpseudoscore);
803  	   }
804  	}
805  	
806  	/** update root LP best-estimate with changed variable pseudo-costs */
807  	SCIP_RETCODE SCIPstatUpdateVarRootLPBestEstimate(
808  	   SCIP_STAT*            stat,               /**< SCIP statistics */
809  	   SCIP_SET*             set,                /**< global SCIP settings */
810  	   SCIP_VAR*             var,                /**< variable with changed pseudo costs */
811  	   SCIP_Real             oldrootpscostscore  /**< old minimum pseudo cost score of variable */
812  	   )
813  	{
814  	   SCIP_Real rootlpsol;
815  	   SCIP_Real varminpseudoscore;
816  	
817  	   assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE );
818  	
819  	   /* entire root LP best-estimate must be computed from scratch first */
820  	   if( stat->rootlpbestestimate == SCIP_INVALID ) /*lint !e777*/
821  	      return SCIP_OKAY;
822  	
823  	   rootlpsol = SCIPvarGetRootSol(var);
824  	
825  	   /* LP root estimate only works for variables with fractional LP root solution */
826  	   if( SCIPsetIsFeasIntegral(set, rootlpsol) )
827  	      return SCIP_OKAY;
828  	
829  	   /* subtract old pseudo cost contribution and add new contribution afterwards */
830  	   stat->rootlpbestestimate -= oldrootpscostscore;
831  	
832  	   varminpseudoscore = SCIPvarGetMinPseudocostScore(var, stat, set, rootlpsol);
833  	   assert(varminpseudoscore >= 0.0);
834  	   stat->rootlpbestestimate += varminpseudoscore;
835  	
836  	   SCIPstatDebugMsg(stat, "Root LP estimate update: <%s> - %15.9f + %15.9f\n", SCIPvarGetName(var), oldrootpscostscore, varminpseudoscore);
837  	
838  	   return SCIP_OKAY;
839  	}
840  	
841  	/** prints a debug message */
842  	void SCIPstatPrintDebugMessage(
843  	   SCIP_STAT*            stat,               /**< SCIP statistics */
844  	   const char*           sourcefile,         /**< name of the source file that called the function */
845  	   int                   sourceline,         /**< line in the source file where the function was called */
846  	   const char*           formatstr,          /**< format string like in printf() function */
847  	   ...                                       /**< format arguments line in printf() function */
848  	   )
849  	{
850  	   const char* filename;
851  	   va_list ap;
852  	
853  	   assert( sourcefile != NULL );
854  	   assert( stat != NULL );
855  	
856  	   /* strip directory from filename */
857  	#if defined(_WIN32) || defined(_WIN64)
858  	   filename = strrchr(sourcefile, '\\');
859  	#else
860  	   filename = strrchr(sourcefile, '/');
861  	#endif
862  	   if ( filename == NULL )
863  	      filename = sourcefile;
864  	   else
865  	      ++filename;
866  	
867  	   if ( stat->subscipdepth > 0 )
868  	      printf("%d: [%s:%d] debug: ", stat->subscipdepth, filename, sourceline);
869  	   else
870  	      printf("[%s:%d] debug: ", filename, sourceline);
871  	
872  	   va_start(ap, formatstr); /*lint !e838*/
873  	   printf(formatstr, ap);
874  	   va_end(ap);
875  	}
876  	
877  	/** prints a debug message without precode */
878  	void SCIPstatDebugMessagePrint(
879  	   SCIP_STAT*            stat,               /**< SCIP statistics */
880  	   const char*           formatstr,          /**< format string like in printf() function */
881  	   ...                                       /**< format arguments line in printf() function */
882  	   )
883  	{  /*lint --e{715}*/
884  	   va_list ap;
885  	
886  	   assert(stat != NULL);
887  	
888  	   va_start(ap, formatstr); /*lint !e838*/
889  	   printf(formatstr, ap);
890  	   va_end(ap);
891  	}
892