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