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   disp.c
17  * @ingroup OTHER_CFILES
18  * @brief  methods and datastructures for displaying runtime statistics
19  * @author Tobias Achterberg
20  * @author Timo Berthold
21  */
22 
23 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
24 
25 #include <stdio.h>
26 #include <assert.h>
27 #include <string.h>
28 
29 #include "scip/def.h"
30 #include "blockmemshell/memory.h"
31 #include "scip/set.h"
32 #include "scip/stat.h"
33 #include "scip/scip.h"
34 #include "scip/disp.h"
35 #include "scip/pub_message.h"
36 #include "scip/pub_misc.h"
37 #include "scip/syncstore.h"
38 #include "scip/struct_disp.h"
39 
40 
41 
42 /*
43  * display column methods
44  */
45 
46 /** parameter change information method to autoselect display columns again */
SCIP_DECL_PARAMCHGD(SCIPparamChgdDispActive)47 SCIP_DECL_PARAMCHGD(SCIPparamChgdDispActive)
48 {  /*lint --e{715}*/
49    /* automatically select the now active display columns */
50    SCIP_CALL( SCIPautoselectDisps(scip) );
51 
52    return SCIP_OKAY;
53 }
54 
55 /** copies the given display to a new scip */
SCIPdispCopyInclude(SCIP_DISP * disp,SCIP_SET * set)56 SCIP_RETCODE SCIPdispCopyInclude(
57    SCIP_DISP*            disp,               /**< display column */
58    SCIP_SET*             set                 /**< SCIP_SET of SCIP to copy to */
59    )
60 {
61    assert(disp != NULL);
62    assert(set != NULL);
63    assert(set->scip != NULL);
64 
65    if( disp->dispcopy != NULL )
66    {
67       SCIPsetDebugMsg(set, "including display column %s in subscip %p\n", SCIPdispGetName(disp), (void*)set->scip);
68       SCIP_CALL( disp->dispcopy(set->scip, disp) );
69    }
70    return SCIP_OKAY;
71 }
72 
73 /** internal method for creating a display column */
74 static
doDispCreate(SCIP_DISP ** disp,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,BMS_BLKMEM * blkmem,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)75 SCIP_RETCODE doDispCreate(
76    SCIP_DISP**           disp,               /**< pointer to store display column */
77    SCIP_SET*             set,                /**< global SCIP settings */
78    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
79    BMS_BLKMEM*           blkmem,             /**< block memory for parameter settings */
80    const char*           name,               /**< name of display column */
81    const char*           desc,               /**< description of display column */
82    const char*           header,             /**< head line of display column */
83    SCIP_DISPSTATUS       dispstatus,         /**< display activation status of display column */
84    SCIP_DECL_DISPCOPY    ((*dispcopy)),      /**< copy method of display column or NULL if you don't want to copy your plugin into sub-SCIPs */
85    SCIP_DECL_DISPFREE    ((*dispfree)),      /**< destructor of display column */
86    SCIP_DECL_DISPINIT    ((*dispinit)),      /**< initialize display column */
87    SCIP_DECL_DISPEXIT    ((*dispexit)),      /**< deinitialize display column */
88    SCIP_DECL_DISPINITSOL ((*dispinitsol)),   /**< solving process initialization method of display column */
89    SCIP_DECL_DISPEXITSOL ((*dispexitsol)),   /**< solving process deinitialization method of display column */
90    SCIP_DECL_DISPOUTPUT  ((*dispoutput)),    /**< output method */
91    SCIP_DISPDATA*        dispdata,           /**< display column data */
92    int                   width,              /**< width of display column (no. of chars used) */
93    int                   priority,           /**< priority of display column */
94    int                   position,           /**< relative position of display column */
95    SCIP_Bool             stripline           /**< should the column be separated with a line from its right neighbor? */
96    )
97 {
98    char paramname[SCIP_MAXSTRLEN];
99    char paramdesc[SCIP_MAXSTRLEN];
100 
101    assert(disp != NULL);
102    assert(name != NULL);
103    assert(desc != NULL);
104    assert(header != NULL);
105    assert(dispoutput != NULL);
106    assert(width >= 0);
107 
108    SCIP_ALLOC( BMSallocMemory(disp) );
109    BMSclearMemory(*disp);
110 
111    SCIP_ALLOC( BMSduplicateMemoryArray(&(*disp)->name, name, strlen(name)+1) );
112    SCIP_ALLOC( BMSduplicateMemoryArray(&(*disp)->desc, desc, strlen(desc)+1) );
113    SCIP_ALLOC( BMSduplicateMemoryArray(&(*disp)->header, header, strlen(header)+1) );
114    (*disp)->dispstatus = dispstatus;
115    (*disp)->dispcopy = dispcopy;
116    (*disp)->dispfree = dispfree;
117    (*disp)->dispinit = dispinit;
118    (*disp)->dispexit = dispexit;
119    (*disp)->dispinitsol = dispinitsol;
120    (*disp)->dispexitsol = dispexitsol;
121    (*disp)->dispoutput = dispoutput;
122    (*disp)->dispdata = dispdata;
123    (*disp)->width = width;
124    (*disp)->priority = priority;
125    (*disp)->position = position;
126    (*disp)->stripline = stripline;
127    (*disp)->initialized = FALSE;
128    (*disp)->active = (dispstatus == SCIP_DISPSTATUS_ON);
129    (*disp)->mode = SCIP_DISPMODE_DEFAULT;
130 
131    /* add parameters */
132    (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "display/%s/active", name);
133    (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "display activation status of display column <%s> (0: off, 1: auto, 2:on)", name);
134    SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname, paramdesc,
135          (int*)(&(*disp)->dispstatus), FALSE, (int)dispstatus, 0, 2, SCIPparamChgdDispActive, NULL) );
136 
137    return SCIP_OKAY;
138 }
139 
140 /** creates a display column */
SCIPdispCreate(SCIP_DISP ** disp,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,BMS_BLKMEM * blkmem,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)141 SCIP_RETCODE SCIPdispCreate(
142    SCIP_DISP**           disp,               /**< pointer to store display column */
143    SCIP_SET*             set,                /**< global SCIP settings */
144    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
145    BMS_BLKMEM*           blkmem,             /**< block memory for parameter settings */
146    const char*           name,               /**< name of display column */
147    const char*           desc,               /**< description of display column */
148    const char*           header,             /**< head line of display column */
149    SCIP_DISPSTATUS       dispstatus,         /**< display activation status of display column */
150    SCIP_DECL_DISPCOPY    ((*dispcopy)),      /**< copy method of display column or NULL if you don't want to copy your plugin into sub-SCIPs */
151    SCIP_DECL_DISPFREE    ((*dispfree)),      /**< destructor of display column */
152    SCIP_DECL_DISPINIT    ((*dispinit)),      /**< initialize display column */
153    SCIP_DECL_DISPEXIT    ((*dispexit)),      /**< deinitialize display column */
154    SCIP_DECL_DISPINITSOL ((*dispinitsol)),   /**< solving process initialization method of display column */
155    SCIP_DECL_DISPEXITSOL ((*dispexitsol)),   /**< solving process deinitialization method of display column */
156    SCIP_DECL_DISPOUTPUT  ((*dispoutput)),    /**< output method */
157    SCIP_DISPDATA*        dispdata,           /**< display column data */
158    int                   width,              /**< width of display column (no. of chars used) */
159    int                   priority,           /**< priority of display column */
160    int                   position,           /**< relative position of display column */
161    SCIP_Bool             stripline           /**< should the column be separated with a line from its right neighbor? */
162    )
163 {
164    assert(disp != NULL);
165    assert(name != NULL);
166    assert(desc != NULL);
167    assert(header != NULL);
168    assert(dispoutput != NULL);
169    assert(width >= 0);
170 
171    SCIP_CALL_FINALLY( doDispCreate(disp, set, messagehdlr, blkmem, name, desc, header, dispstatus, dispcopy,
172       dispfree, dispinit, dispexit, dispinitsol, dispexitsol, dispoutput, dispdata, width, priority, position,
173       stripline), (void) SCIPdispFree(disp, set) );
174 
175    return SCIP_OKAY;
176 }
177 
178 /** frees memory of display column */
SCIPdispFree(SCIP_DISP ** disp,SCIP_SET * set)179 SCIP_RETCODE SCIPdispFree(
180    SCIP_DISP**           disp,               /**< pointer to display column data structure */
181    SCIP_SET*             set                 /**< global SCIP settings */
182    )
183 {
184    assert(disp != NULL);
185    if( *disp == NULL )
186       return SCIP_OKAY;
187    assert(!(*disp)->initialized);
188    assert(set != NULL);
189 
190    /* call destructor of display column */
191    if( (*disp)->dispfree != NULL )
192    {
193       SCIP_CALL( (*disp)->dispfree(set->scip, *disp) );
194    }
195 
196    BMSfreeMemoryArrayNull(&(*disp)->name);
197    BMSfreeMemoryArrayNull(&(*disp)->desc);
198    BMSfreeMemoryArrayNull(&(*disp)->header);
199    BMSfreeMemory(disp);
200 
201    return SCIP_OKAY;
202 }
203 
204 /** initializes display column */
SCIPdispInit(SCIP_DISP * disp,SCIP_SET * set)205 SCIP_RETCODE SCIPdispInit(
206    SCIP_DISP*            disp,               /**< display column */
207    SCIP_SET*             set                 /**< global SCIP settings */
208    )
209 {
210    assert(disp != NULL);
211    assert(set != NULL);
212 
213    if( disp->initialized )
214    {
215       SCIPerrorMessage("display column <%s> already initialized\n", disp->name);
216       return SCIP_INVALIDCALL;
217    }
218 
219    if( disp->dispinit != NULL )
220    {
221       SCIP_CALL( disp->dispinit(set->scip, disp) );
222    }
223    disp->initialized = TRUE;
224 
225    return SCIP_OKAY;
226 }
227 
228 /** deinitializes display column */
SCIPdispExit(SCIP_DISP * disp,SCIP_SET * set)229 SCIP_RETCODE SCIPdispExit(
230    SCIP_DISP*            disp,               /**< display column */
231    SCIP_SET*             set                 /**< global SCIP settings */
232    )
233 {
234    assert(disp != NULL);
235    assert(set != NULL);
236 
237    if( !disp->initialized )
238    {
239       SCIPerrorMessage("display column <%s> not initialized\n", disp->name);
240       return SCIP_INVALIDCALL;
241    }
242 
243    if( disp->dispexit != NULL )
244    {
245       SCIP_CALL( disp->dispexit(set->scip, disp) );
246    }
247    disp->initialized = FALSE;
248 
249    return SCIP_OKAY;
250 }
251 
252 /** informs display column that the branch and bound process is being started */
SCIPdispInitsol(SCIP_DISP * disp,SCIP_SET * set)253 SCIP_RETCODE SCIPdispInitsol(
254    SCIP_DISP*            disp,               /**< display column */
255    SCIP_SET*             set                 /**< global SCIP settings */
256    )
257 {
258    assert(disp != NULL);
259    assert(set != NULL);
260 
261    /* call solving process initialization method of display column */
262    if( disp->dispinitsol != NULL )
263    {
264       SCIP_CALL( disp->dispinitsol(set->scip, disp) );
265    }
266 
267    return SCIP_OKAY;
268 }
269 
270 /** informs display column that the branch and bound process data is being freed */
SCIPdispExitsol(SCIP_DISP * disp,SCIP_SET * set)271 SCIP_RETCODE SCIPdispExitsol(
272    SCIP_DISP*            disp,               /**< display column */
273    SCIP_SET*             set                 /**< global SCIP settings */
274    )
275 {
276    assert(disp != NULL);
277    assert(set != NULL);
278 
279    /* call solving process deinitialization method of display column */
280    if( disp->dispexitsol != NULL )
281    {
282       SCIP_CALL( disp->dispexitsol(set->scip, disp) );
283    }
284 
285    return SCIP_OKAY;
286 }
287 
288 /** output display column to screen */
SCIPdispOutput(SCIP_DISP * disp,SCIP_SET * set,FILE * file)289 SCIP_RETCODE SCIPdispOutput(
290    SCIP_DISP*            disp,               /**< display column */
291    SCIP_SET*             set,                /**< global SCIP settings */
292    FILE*                 file                /**< output file (or NULL for standard output) */
293    )
294 {
295    assert(disp != NULL);
296    assert(disp->dispoutput != NULL);
297    assert(set != NULL);
298 
299    SCIP_CALL( disp->dispoutput(set->scip, disp, file) );
300 
301    return SCIP_OKAY;
302 }
303 
304 /** gets user data of display column */
SCIPdispGetData(SCIP_DISP * disp)305 SCIP_DISPDATA* SCIPdispGetData(
306    SCIP_DISP*            disp                /**< display column */
307    )
308 {
309    assert(disp != NULL);
310 
311    return disp->dispdata;
312 }
313 
314 /** sets user data of display column; user has to free old data in advance! */
SCIPdispSetData(SCIP_DISP * disp,SCIP_DISPDATA * dispdata)315 void SCIPdispSetData(
316    SCIP_DISP*            disp,               /**< display column */
317    SCIP_DISPDATA*        dispdata            /**< new display column user data */
318    )
319 {
320    assert(disp != NULL);
321 
322    disp->dispdata = dispdata;
323 }
324 
325 /** gets name of display column */
SCIPdispGetName(SCIP_DISP * disp)326 const char* SCIPdispGetName(
327    SCIP_DISP*            disp                /**< display column */
328    )
329 {
330    assert(disp != NULL);
331 
332    return disp->name;
333 }
334 
335 /** gets description of display column */
SCIPdispGetDesc(SCIP_DISP * disp)336 const char* SCIPdispGetDesc(
337    SCIP_DISP*            disp                /**< display column */
338    )
339 {
340    assert(disp != NULL);
341 
342    return disp->desc;
343 }
344 
345 /** gets head line of display column */
SCIPdispGetHeader(SCIP_DISP * disp)346 const char* SCIPdispGetHeader(
347    SCIP_DISP*            disp                /**< display column */
348    )
349 {
350    assert(disp != NULL);
351 
352    return disp->header;
353 }
354 
355 /** gets width of display column */
SCIPdispGetWidth(SCIP_DISP * disp)356 int SCIPdispGetWidth(
357    SCIP_DISP*            disp                /**< display column */
358    )
359 {
360    assert(disp != NULL);
361 
362    return disp->width;
363 }
364 
365 /** gets priority of display column */
SCIPdispGetPriority(SCIP_DISP * disp)366 int SCIPdispGetPriority(
367    SCIP_DISP*            disp                /**< display column */
368    )
369 {
370    assert(disp != NULL);
371 
372    return disp->priority;
373 }
374 
375 /** gets position of display column */
SCIPdispGetPosition(SCIP_DISP * disp)376 int SCIPdispGetPosition(
377    SCIP_DISP*            disp                /**< display column */
378    )
379 {
380    assert(disp != NULL);
381 
382    return disp->position;
383 }
384 
385 /** gets status of display column */
SCIPdispGetStatus(SCIP_DISP * disp)386 SCIP_DISPSTATUS SCIPdispGetStatus(
387    SCIP_DISP*            disp                /**< display column */
388    )
389 {
390    assert(disp != NULL);
391 
392    return disp->dispstatus;
393 }
394 
395 /** is display column initialized? */
SCIPdispIsInitialized(SCIP_DISP * disp)396 SCIP_Bool SCIPdispIsInitialized(
397    SCIP_DISP*            disp                /**< display column */
398    )
399 {
400    assert(disp != NULL);
401 
402    return disp->initialized;
403 }
404 
405 /** prints one line of output with the active display columns */
SCIPdispPrintLine(SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat,FILE * file,SCIP_Bool forcedisplay,SCIP_Bool endline)406 SCIP_RETCODE SCIPdispPrintLine(
407    SCIP_SET*             set,                /**< global SCIP settings */
408    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
409    SCIP_STAT*            stat,               /**< problem statistics data */
410    FILE*                 file,               /**< output file (or NULL for standard output) */
411    SCIP_Bool             forcedisplay,       /**< should the line be printed without regarding frequency? */
412    SCIP_Bool             endline             /**< should the line be terminated with a newline symbol? */
413    )
414 {
415    assert(set != NULL);
416    assert(set->disp_freq >= -1);
417    assert(set->disp_headerfreq >= -1);
418    assert(stat != NULL);
419 
420    if( (SCIP_VERBLEVEL)set->disp_verblevel < SCIP_VERBLEVEL_NORMAL || set->disp_freq == -1 )
421       return SCIP_OKAY;
422 
423    if( forcedisplay
424       || (stat->nnodes != stat->lastdispnode
425          && set->disp_freq > 0
426          && (stat->nnodes % set->disp_freq == 0 || stat->nnodes == 1)) )
427    {
428       int i;
429       int j;
430       SCIP_Bool stripline;
431 
432       /* display header line */
433       if( (set->disp_headerfreq == 0 && stat->ndisplines == 0)
434          || (set->disp_headerfreq > 0 && stat->ndisplines % set->disp_headerfreq == 0) )
435       {
436          int fillspace;
437 
438          stripline = FALSE;
439          for( i = 0; i < set->ndisps; ++i )
440          {
441             assert(set->disps[i] != NULL);
442             if( set->disps[i]->active )
443             {
444                if( stripline )
445                   SCIPmessageFPrintInfo(messagehdlr, file, "|");
446                fillspace = set->disps[i]->width - (int)strlen(set->disps[i]->header);
447                for( j = 0; j < (fillspace)/2; ++j )
448                   SCIPmessageFPrintInfo(messagehdlr, file, " ");
449                SCIPmessageFPrintInfo(messagehdlr, file, "%s", (const char*)set->disps[i]->header);
450                for( j = 0; j < (fillspace+1)/2; ++j )
451                   SCIPmessageFPrintInfo(messagehdlr, file, " ");
452                stripline = set->disps[i]->stripline;
453             }
454          }
455          SCIPmessageFPrintInfo(messagehdlr, file, "\n");
456       }
457 
458       /* display node information line */
459       stripline = FALSE;
460       for( i = 0; i < set->ndisps; ++i )
461       {
462          assert(set->disps[i] != NULL);
463          if( set->disps[i]->active )
464          {
465             if( stripline )
466                SCIPmessageFPrintInfo(messagehdlr, file, "|");
467             SCIP_CALL( SCIPdispOutput(set->disps[i], set, file) );
468             stripline = set->disps[i]->stripline;
469          }
470       }
471       if( endline )
472       {
473          SCIPmessageFPrintInfo(messagehdlr, file, "\n");
474       }
475       fflush(stdout);
476 
477       stat->lastdispnode = stat->nnodes;
478       stat->ndisplines++;
479    }
480 
481    return SCIP_OKAY;
482 }
483 
484 /** comparison method for display columns */
485 static
SCIP_DECL_SORTPTRCOMP(dispComp)486 SCIP_DECL_SORTPTRCOMP(dispComp)
487 {  /*lint --e{715}*/
488    return ((SCIP_DISP*)elem2)->priority - ((SCIP_DISP*)elem1)->priority;
489 }
490 
491 /** activates all display lines fitting in the display w.r. to priority */
SCIPdispAutoActivate(SCIP_SET * set)492 SCIP_RETCODE SCIPdispAutoActivate(
493    SCIP_SET*             set                 /**< global SCIP settings */
494    )
495 {
496    SCIP_DISP** disps;
497    SCIP_SYNCSTORE* syncstore;
498    SCIP_DISPMODE mode;
499    int totalwidth;
500    int width;
501    int i;
502 
503    assert(set != NULL);
504 
505    syncstore = SCIPgetSyncstore(set->scip);
506    assert(syncstore != NULL);
507 
508    /* sort display columns w.r. to their priority */
509    SCIP_ALLOC( BMSduplicateMemoryArray(&disps, set->disps, set->ndisps) );
510    SCIPsortPtr((void**)disps, dispComp, set->ndisps);
511 
512    totalwidth = 0;
513 
514    if( SCIPsyncstoreIsInitialized(syncstore) )
515       mode = SCIP_DISPMODE_CONCURRENT;
516    else
517       mode = SCIP_DISPMODE_DEFAULT;
518 
519    /* first activate all columns with display status ON */
520    for( i = 0; i < set->ndisps; ++i )
521    {
522       width = disps[i]->width;
523       if( disps[i]->stripline )
524          width++;
525       if( disps[i]->dispstatus == SCIP_DISPSTATUS_ON && (disps[i]->mode & mode) )
526       {
527          disps[i]->active = TRUE;
528          totalwidth += width;
529       }
530       else
531          disps[i]->active = FALSE;
532    }
533 
534    /* beginning with highest priority display column, activate AUTO columns as long as it fits into display width */
535    for( i = 0; i < set->ndisps; ++i )
536    {
537       if( disps[i]->dispstatus == SCIP_DISPSTATUS_AUTO )
538       {
539          assert(!disps[i]->active);
540 
541          width = disps[i]->width;
542          if( disps[i]->stripline )
543             width++;
544          if( totalwidth + width <= set->disp_width && (disps[i]->mode & mode) )
545          {
546             disps[i]->active = TRUE;
547             totalwidth += width;
548          }
549       }
550    }
551 
552    /* free temporary memory */
553    BMSfreeMemoryArray(&disps);
554 
555    return SCIP_OKAY;
556 }
557 
558 /** changes the display column mode */
SCIPdispChgMode(SCIP_DISP * disp,SCIP_DISPMODE mode)559 void SCIPdispChgMode(
560    SCIP_DISP*            disp,               /**< display column */
561    SCIP_DISPMODE         mode                /**< the display column mode */
562    )
563 {
564    disp->mode = mode;
565 }
566 
567 static
568 const char decpowerchar[] = {' ', 'k', 'M', 'G', 'T', 'P', 'E'};
569 #define MAXDECPOWER 6
570 
571 /** displays a long integer in decimal form fitting in a given width */
SCIPdispLongint(SCIP_MESSAGEHDLR * messagehdlr,FILE * file,SCIP_Longint val,int width)572 void SCIPdispLongint(
573    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
574    FILE*                 file,               /**< output stream */
575    SCIP_Longint          val,                /**< value to display */
576    int                   width               /**< width to fit into */
577    )
578 {
579    assert(width >= 1);
580 
581    if( width == 1 )
582    {
583       if( val < 0 )
584          SCIPmessageFPrintInfo(messagehdlr, file, "-");
585       else if( val < 10 )
586          SCIPmessageFPrintInfo(messagehdlr, file, "%" SCIP_LONGINT_FORMAT, val);
587       else
588          SCIPmessageFPrintInfo(messagehdlr, file, "+");
589    }
590    else
591    {
592       char format[SCIP_MAXSTRLEN];
593       SCIP_Longint maxval;
594       int decpower;
595       int i;
596 
597       maxval = 1;
598       for( i = 0; i < width-1; ++i )
599          maxval *= 10;
600       if( val < 0 )
601          maxval /= 10;
602       decpower = 0;
603       while( ABS(val) >= maxval && decpower < MAXDECPOWER )
604       {
605          decpower++;
606          val /= 1000;
607       }
608       (void) SCIPsnprintf(format, SCIP_MAXSTRLEN, "%%%d" SCIP_LONGINT_FORMAT "%c", width-1, decpowerchar[decpower]);
609 
610       if( width == 2 && val < 0 )
611          SCIPmessageFPrintInfo(messagehdlr, file, "-%c", decpowerchar[decpower]);
612       else
613          SCIPmessageFPrintInfo(messagehdlr, file, (const char*)format, val);
614    }
615 }
616 
617 /** displays an integer in decimal form fitting in a given width */
SCIPdispInt(SCIP_MESSAGEHDLR * messagehdlr,FILE * file,int val,int width)618 void SCIPdispInt(
619    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
620    FILE*                 file,               /**< output stream */
621    int                   val,                /**< value to display */
622    int                   width               /**< width to fit into */
623    )
624 {
625    SCIPdispLongint(messagehdlr, file, (SCIP_Longint)val, width);
626 }
627 
628 
629 static const char timepowerchar[] = {'s', 'm', 'h', 'd', 'y'};
630 static const SCIP_Real timepowerval[] = {1.0, 60.0, 60.0, 24.0, 365.0};
631 #define MAXTIMEPOWER 4
632 
633 /** displays a time value fitting in a given width */
SCIPdispTime(SCIP_MESSAGEHDLR * messagehdlr,FILE * file,SCIP_Real val,int width)634 void SCIPdispTime(
635    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
636    FILE*                 file,               /**< output stream */
637    SCIP_Real             val,                /**< value in seconds to display */
638    int                   width               /**< width to fit into */
639    )
640 {
641    assert(width >= 1);
642 
643    if( width == 1 )
644    {
645       if( val < 0.0 )
646          SCIPmessageFPrintInfo(messagehdlr, file, "-");
647       else if( val < 10.0 )
648          SCIPmessageFPrintInfo(messagehdlr, file, "%.0f", val);
649       else
650          SCIPmessageFPrintInfo(messagehdlr, file, "+");
651    }
652    else
653    {
654       char format[SCIP_MAXSTRLEN];
655       SCIP_Longint maxval;
656       int timepower;
657       int i;
658 
659       maxval = 1;
660       for( i = 0; i < width-1; ++i )
661          maxval *= 10;
662       if( val < 0.0 )
663          maxval /= 10;
664       timepower = 0;
665       while( REALABS(val) + 0.5 >= maxval && timepower < MAXTIMEPOWER )
666       {
667          timepower++;
668          val /= timepowerval[timepower];
669       }
670       if( REALABS(val) + 0.05 < maxval/100.0 )
671          (void) SCIPsnprintf(format, SCIP_MAXSTRLEN, "%%%d.1f%c", width-1, timepowerchar[timepower]);
672       else
673          (void) SCIPsnprintf(format, SCIP_MAXSTRLEN, "%%%d.0f%c", width-1, timepowerchar[timepower]);
674 
675       if( width == 2 && val < 0.0 )
676          SCIPmessageFPrintInfo(messagehdlr, file, "-%c", timepowerchar[timepower]);
677       else
678          SCIPmessageFPrintInfo(messagehdlr, file, (const char*)format, val);
679    }
680 }
681