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