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   visual.c
17  * @ingroup OTHER_CFILES
18  * @brief  methods for creating output for visualization tools (VBC, BAK)
19  * @author Tobias Achterberg
20  * @author Marc Pfetsch
21  *
22  * Output can be generated for the following visualization tools:
23  *
24  * - VBCTOOL - a graphical interface for Visualization of Branch Cut algorithms @n
25  *   See <a href="http://www.informatik.uni-koeln.de/ls_juenger/research/vbctool">VBCTOOL</a>.
26  * - BAK: Branch-and-bound Analysis Kit @n
27  *   BAK is available through COIN-OR, see <a href="https://projects.coin-or.org/CoinBazaar/wiki/Projects/BAK">BAK</a>.
28  *   A description is <a href="http://www.optimization-online.org/DB_HTML/2007/09/1785.html">available</a> as well.
29  */
30 
31 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
32 
33 #include <stdio.h>
34 #include <assert.h>
35 
36 #include "blockmemshell/memory.h"
37 #include "scip/scip.h"
38 #include "scip/set.h"
39 #include "scip/stat.h"
40 #include "scip/clock.h"
41 #include "scip/var.h"
42 #include "scip/tree.h"
43 #include "scip/visual.h"
44 #include "scip/struct_visual.h"
45 
46 
47 /** returns the branching variable of the node, or NULL */
48 static
getBranchInfo(SCIP_NODE * node,SCIP_VAR ** var,SCIP_BOUNDTYPE * boundtype,SCIP_Real * bound)49 void getBranchInfo(
50    SCIP_NODE*            node,               /**< node */
51    SCIP_VAR**            var,                /**< pointer to store the branching variable */
52    SCIP_BOUNDTYPE*       boundtype,          /**< pointer to store the branching type: lower or upper bound */
53    SCIP_Real*            bound               /**< pointer to store the new bound of the branching variable */
54    )
55 {
56    SCIP_DOMCHGBOUND* domchgbound;
57 
58    (*var) = NULL;
59    (*bound) = 0.0;
60    (*boundtype) = SCIP_BOUNDTYPE_LOWER;
61 
62    assert(node != NULL);
63    if( node->domchg == NULL )
64       return;
65 
66    domchgbound = &node->domchg->domchgbound;
67    if( domchgbound->nboundchgs == 0 )
68       return;
69 
70    (*var) = domchgbound->boundchgs[0].var;
71    (*bound) = domchgbound->boundchgs[0].newbound;
72    (*boundtype) = (SCIP_BOUNDTYPE) domchgbound->boundchgs[0].boundtype;
73 }
74 
75 /** creates visualization data structure */
SCIPvisualCreate(SCIP_VISUAL ** visual,SCIP_MESSAGEHDLR * messagehdlr)76 SCIP_RETCODE SCIPvisualCreate(
77    SCIP_VISUAL**         visual,             /**< pointer to store visualization information */
78    SCIP_MESSAGEHDLR*     messagehdlr         /**< message handler */
79    )
80 {
81    SCIP_ALLOC( BMSallocMemory(visual) );
82 
83    (*visual)->vbcfile = NULL;
84    (*visual)->bakfile = NULL;
85    (*visual)->messagehdlr = messagehdlr;
86    (*visual)->nodenum = NULL;
87    (*visual)->timestep = 0;
88    (*visual)->lastnode = NULL;
89    (*visual)->lastcolor = SCIP_VBCCOLOR_NONE;
90    (*visual)->userealtime = FALSE;
91    (*visual)->lastlowerbound = SCIP_INVALID;
92 
93    return SCIP_OKAY;
94 }
95 
96 /** frees visualization data structure */
SCIPvisualFree(SCIP_VISUAL ** visual)97 void SCIPvisualFree(
98    SCIP_VISUAL**         visual              /**< pointer to store visualization information */
99    )
100 {
101    assert( visual != NULL );
102    assert( *visual != NULL );
103    assert( (*visual)->vbcfile == NULL );
104    assert( (*visual)->bakfile == NULL );
105    assert( (*visual)->nodenum == NULL );
106 
107    BMSfreeMemory(visual);
108 }
109 
110 /** initializes visualization information and creates a file for visualization output */
SCIPvisualInit(SCIP_VISUAL * visual,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr)111 SCIP_RETCODE SCIPvisualInit(
112    SCIP_VISUAL*          visual,             /**< visualization information */
113    BMS_BLKMEM*           blkmem,             /**< block memory */
114    SCIP_SET*             set,                /**< global SCIP settings */
115    SCIP_MESSAGEHDLR*     messagehdlr         /**< message handler */
116    )
117 {
118    assert( visual != NULL );
119    assert( set != NULL );
120    assert( set->visual_vbcfilename != NULL );
121    assert( set->visual_bakfilename != NULL );
122    assert( visual->nodenum == NULL );
123 
124    visual->lastlowerbound = -SCIPsetInfinity(set);
125 
126    /* check whether we should initialize VBC output */
127    if ( set->visual_vbcfilename[0] != '-' || set->visual_vbcfilename[1] != '\0' )
128    {
129       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_NORMAL,
130          "storing VBC information in file <%s>\n", set->visual_vbcfilename);
131       visual->vbcfile = fopen(set->visual_vbcfilename, "w");
132       visual->timestep = 0;
133       visual->lastnode = NULL;
134       visual->lastcolor = SCIP_VBCCOLOR_NONE;
135       visual->userealtime = set->visual_realtime;
136 
137       if( visual->vbcfile == NULL )
138       {
139          SCIPerrorMessage("error creating file <%s>\n", set->visual_vbcfilename);
140          SCIPprintSysError(set->visual_vbcfilename);
141          return SCIP_FILECREATEERROR;
142       }
143 
144       SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "#TYPE: COMPLETE TREE\n");
145       SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "#TIME: SET\n");
146       SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "#BOUNDS: SET\n");
147       SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "#INFORMATION: STANDARD\n");
148       SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "#NODE_NUMBER: NONE\n");
149    }
150 
151    /* check whether we should initialize BAK output */
152    if ( set->visual_bakfilename[0] != '-' || set->visual_bakfilename[1] != '\0' )
153    {
154       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_NORMAL,
155          "storing BAK information in file <%s>\n", set->visual_bakfilename);
156       visual->bakfile = fopen(set->visual_bakfilename, "w");
157       visual->timestep = 0;
158       visual->lastnode = NULL;
159       visual->lastcolor = SCIP_VBCCOLOR_NONE;
160       visual->userealtime = set->visual_realtime;
161 
162       if ( visual->bakfile == NULL )
163       {
164          SCIPerrorMessage("error creating file <%s>\n", set->visual_bakfilename);
165          SCIPprintSysError(set->visual_bakfilename);
166          return SCIP_FILECREATEERROR;
167       }
168    }
169 
170    /* possibly init hashmap for nodes */
171    if ( visual->vbcfile != NULL || visual->bakfile != NULL )
172    {
173       SCIP_CALL( SCIPhashmapCreate(&visual->nodenum, blkmem, SCIP_HASHSIZE_VBC) );
174    }
175 
176    return SCIP_OKAY;
177 }
178 
179 /** closes the visualization output file */
SCIPvisualExit(SCIP_VISUAL * visual,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr)180 void SCIPvisualExit(
181    SCIP_VISUAL*          visual,             /**< visualization information */
182    SCIP_SET*             set,                /**< global SCIP settings */
183    SCIP_MESSAGEHDLR*     messagehdlr         /**< message handler */
184    )
185 {
186    assert( visual != NULL );
187    assert( set != NULL );
188 
189    if ( visual->vbcfile != NULL )
190    {
191       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL, "closing VBC information file\n");
192 
193       fclose(visual->vbcfile);
194       visual->vbcfile = NULL;
195    }
196 
197    if ( visual->bakfile != NULL )
198    {
199       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL, "closing BAK information file\n");
200 
201       fclose(visual->bakfile);
202       visual->bakfile = NULL;
203    }
204 
205    if ( visual->nodenum )
206       SCIPhashmapFree(&visual->nodenum);
207 }
208 
209 /** prints current solution time to visualization output file */
210 static
printTime(SCIP_VISUAL * visual,SCIP_STAT * stat,SCIP_Bool vbc)211 void printTime(
212    SCIP_VISUAL*          visual,             /**< visualization information */
213    SCIP_STAT*            stat,               /**< problem statistics */
214    SCIP_Bool             vbc                 /**< whether we use vbc output (bak otherwise) */
215    )
216 {
217    SCIP_Longint step;
218    int hours;
219    int mins;
220    int secs;
221    int hunds;
222 
223    assert( visual != NULL );
224    assert( stat != NULL );
225 
226    if( visual->userealtime )
227    {
228       double time;
229       time = SCIPclockGetTime(stat->solvingtime);
230       step = (SCIP_Longint)(time * 100.0);
231    }
232    else
233    {
234       step = visual->timestep;
235       visual->timestep++;
236    }
237 
238    if ( vbc )
239    {
240       hours = (int)(step / (60*60*100));
241       step %= 60*60*100;
242       mins = (int)(step / (60*100));
243       step %= 60*100;
244       secs = (int)(step / 100);
245       step %= 100;
246       hunds = (int)step;
247 
248       SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "%02d:%02d:%02d.%02d ", hours, mins, secs, hunds);
249    }
250    else
251    {
252       SCIPmessageFPrintInfo(visual->messagehdlr, visual->bakfile, "%f ", (SCIP_Real) step/100.0);
253    }
254 }
255 
256 /** creates a new node entry in the visualization output file */
SCIPvisualNewChild(SCIP_VISUAL * visual,SCIP_SET * set,SCIP_STAT * stat,SCIP_NODE * node)257 SCIP_RETCODE SCIPvisualNewChild(
258    SCIP_VISUAL*          visual,             /**< visualization information */
259    SCIP_SET*             set,                /**< global SCIP settings */
260    SCIP_STAT*            stat,               /**< problem statistics */
261    SCIP_NODE*            node                /**< new node, that was created */
262    )
263 {
264    SCIP_VAR* branchvar;
265    SCIP_BOUNDTYPE branchtype;
266    SCIP_Real branchbound;
267    SCIP_Real lowerbound;
268    int parentnodenum;
269    int nodenum;
270 
271    assert( visual != NULL );
272    assert( stat != NULL );
273    assert( node != NULL );
274 
275    /* visualization is disabled on probing nodes */
276    if( SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE )
277       return SCIP_OKAY;
278 
279    /* check whether output should be created */
280    if ( visual->vbcfile == NULL && visual->bakfile == NULL )
281       return SCIP_OKAY;
282 
283    /* insert mapping node -> nodenum into hash map */
284    if( stat->ncreatednodesrun >= (SCIP_Longint)INT_MAX )
285    {
286       SCIPerrorMessage("too many nodes to store in the visualization file\n");
287       return SCIP_INVALIDDATA;
288    }
289 
290    nodenum = (int)stat->ncreatednodesrun;
291    assert(nodenum > 0);
292    SCIP_CALL( SCIPhashmapSetImageInt(visual->nodenum, node, nodenum) );
293 
294    /* get nodenum of parent node from hash map */
295    parentnodenum = (node->parent != NULL ? SCIPhashmapGetImageInt(visual->nodenum, node->parent) : 0);
296    assert(node->parent == NULL || parentnodenum > 0);
297 
298    /* get branching information */
299    getBranchInfo(node, &branchvar, &branchtype, &branchbound);
300 
301    /* determine lower bound */
302    if ( set->visual_objextern )
303       lowerbound = SCIPretransformObj(set->scip, SCIPnodeGetLowerbound(node));
304    else
305       lowerbound = SCIPnodeGetLowerbound(node);
306 
307    if ( visual->vbcfile != NULL )
308    {
309       printTime(visual, stat, TRUE);
310       SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "N %d %d %d\n", parentnodenum, nodenum, SCIP_VBCCOLOR_UNSOLVED);
311       printTime(visual, stat, TRUE);
312       if( branchvar != NULL )
313       {
314          SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t%s [%g,%g] %s %f\\nbound:\\t%f\n",
315             nodenum, nodenum, (void*)node, SCIPnodeGetDepth(node),
316             SCIPvarGetName(branchvar), SCIPvarGetLbLocal(branchvar), SCIPvarGetUbLocal(branchvar),
317             branchtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",  branchbound, lowerbound);
318       }
319       else
320       {
321          SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t-\\nbound:\\t%f\n",
322             nodenum, nodenum, (void*)node, SCIPnodeGetDepth(node), lowerbound);
323       }
324    }
325 
326    /* For BAK, not all available information is available here. Use SCIPvisualUpdateChild() instead */
327 
328    return SCIP_OKAY;
329 }
330 
331 /** updates a node entry in the visualization output file */
SCIPvisualUpdateChild(SCIP_VISUAL * visual,SCIP_SET * set,SCIP_STAT * stat,SCIP_NODE * node)332 SCIP_RETCODE SCIPvisualUpdateChild(
333    SCIP_VISUAL*          visual,             /**< visualization information */
334    SCIP_SET*             set,                /**< global SCIP settings */
335    SCIP_STAT*            stat,               /**< problem statistics */
336    SCIP_NODE*            node                /**< new node, that was created */
337    )
338 {
339    SCIP_VAR* branchvar;
340    SCIP_BOUNDTYPE branchtype;
341    SCIP_Real branchbound;
342    SCIP_Real lowerbound;
343    int nodenum;
344 
345    assert( visual != NULL );
346    assert( stat != NULL );
347    assert( node != NULL );
348 
349    /* check whether output should be created */
350    if ( visual->vbcfile == NULL && visual->bakfile == NULL )
351       return SCIP_OKAY;
352 
353    /* visualization is disabled on probing nodes */
354    if( SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE )
355       return SCIP_OKAY;
356 
357    /* get node num from hash map */
358    nodenum = SCIPhashmapGetImageInt(visual->nodenum, node);
359    assert(nodenum > 0);
360 
361    /* get branching information */
362    getBranchInfo(node, &branchvar, &branchtype, &branchbound);
363 
364    /* determine lower bound */
365    if ( set->visual_objextern )
366       lowerbound = SCIPretransformObj(set->scip, SCIPnodeGetLowerbound(node));
367    else
368       lowerbound = SCIPnodeGetLowerbound(node);
369 
370    if ( visual->vbcfile != NULL )
371    {
372       printTime(visual, stat, TRUE);
373       if( branchvar != NULL )
374       {
375          SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t%s [%g,%g] %s %f\\nbound:\\t%f\n",
376             nodenum, nodenum, (void*)node, SCIPnodeGetDepth(node),
377             SCIPvarGetName(branchvar), SCIPvarGetLbLocal(branchvar), SCIPvarGetUbLocal(branchvar),
378             branchtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",  branchbound, lowerbound);
379       }
380       else
381       {
382          SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t-\\nbound:\\t%f\n",
383             nodenum, nodenum, (void*)node, SCIPnodeGetDepth(node), lowerbound);
384       }
385    }
386 
387    if ( visual->bakfile != NULL )
388    {
389       int parentnodenum;
390       SCIP_Real* lpcandsfrac;
391       SCIP_Real sum = 0.0;
392       int nlpcands = 0;
393       char t = 'M';
394       const char* nodeinfo;
395       int j;
396 
397       /* determine branching type */
398       if ( branchvar != NULL )
399          t = (branchtype == SCIP_BOUNDTYPE_LOWER ? 'R' : 'L');
400 
401       /* get nodenum of parent node from hash map */
402       parentnodenum = (node->parent != NULL ? SCIPhashmapGetImageInt(visual->nodenum, node->parent) : 0);
403       assert(node->parent == NULL || parentnodenum > 0);
404 
405       /* update info depending on the node type */
406       switch( SCIPnodeGetType(node) )
407       {
408       case SCIP_NODETYPE_CHILD:
409          /* the child is a new candidate */
410          nodeinfo = "candidate";
411          break;
412       case SCIP_NODETYPE_FOCUSNODE:
413          /* the focus node is updated to a branch node */
414          nodeinfo = "branched";
415 
416          /* calculate infeasibility information only if the LP was solved to optimality */
417          if( SCIPgetLPSolstat(set->scip) == SCIP_LPSOLSTAT_OPTIMAL )
418          {
419             SCIP_CALL( SCIPgetLPBranchCands(set->scip, NULL, NULL, &lpcandsfrac, &nlpcands, NULL, NULL) );
420             for( j = 0; j < nlpcands; ++j )
421                sum += lpcandsfrac[j];
422          }
423 
424          break;
425       default:
426          SCIPerrorMessage("Error: Unexpected node type <%d> in Update Child Method", SCIPnodeGetType(node));
427          return SCIP_INVALIDDATA;
428       } /*lint !e788*/
429       /* append new status line with updated node information to the bakfile */
430       printTime(visual, stat, FALSE);
431       SCIPmessageFPrintInfo(visual->messagehdlr, visual->bakfile, "%s %d %d %c %f %f %d\n", nodeinfo, (int)nodenum, (int)parentnodenum, t,
432             lowerbound, sum, nlpcands);
433    }
434 
435    return SCIP_OKAY;
436 }
437 
438 /** changes the color of the node to the given color */
439 static
vbcSetColor(SCIP_VISUAL * visual,SCIP_STAT * stat,SCIP_NODE * node,SCIP_VBCCOLOR color)440 void vbcSetColor(
441    SCIP_VISUAL*          visual,             /**< visualization information */
442    SCIP_STAT*            stat,               /**< problem statistics */
443    SCIP_NODE*            node,               /**< node to change color for */
444    SCIP_VBCCOLOR         color               /**< new color of node, or SCIP_VBCCOLOR_NONE */
445    )
446 {
447    assert( visual != NULL );
448    assert( node != NULL );
449 
450    if( visual->vbcfile != NULL && color != SCIP_VBCCOLOR_NONE && (node != visual->lastnode || color != visual->lastcolor) )
451    {
452       int nodenum;
453 
454       nodenum = SCIPhashmapGetImageInt(visual->nodenum, node);
455       assert(nodenum > 0);
456       printTime(visual, stat, TRUE);
457       SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "P %d %d\n", (int)nodenum, color);
458       visual->lastnode = node;
459       visual->lastcolor = color;
460    }
461 }
462 
463 /** marks node as solved in visualization output file */
SCIPvisualSolvedNode(SCIP_VISUAL * visual,SCIP_SET * set,SCIP_STAT * stat,SCIP_NODE * node)464 void SCIPvisualSolvedNode(
465    SCIP_VISUAL*          visual,             /**< visualization information */
466    SCIP_SET*             set,                /**< global SCIP settings */
467    SCIP_STAT*            stat,               /**< problem statistics */
468    SCIP_NODE*            node                /**< node, that was solved */
469    )
470 {
471    SCIP_VAR* branchvar;
472    SCIP_BOUNDTYPE branchtype;
473    SCIP_Real branchbound;
474    SCIP_Real lowerbound;
475    int nodenum;
476 
477    assert( visual != NULL );
478    assert( stat != NULL );
479    assert( node != NULL );
480 
481    /* check whether output should be created */
482    if ( visual->vbcfile == NULL && visual->bakfile == NULL )
483       return;
484 
485    /* visualization is disabled on probing nodes */
486    if( SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE )
487       return;
488 
489    /* get node num from hash map */
490    nodenum = SCIPhashmapGetImageInt(visual->nodenum, node);
491    assert(nodenum > 0);
492 
493    /* get branching information */
494    getBranchInfo(node, &branchvar, &branchtype, &branchbound);
495 
496    /* determine lower bound */
497    if ( set->visual_objextern )
498       lowerbound = SCIPretransformObj(set->scip, SCIPnodeGetLowerbound(node));
499    else
500       lowerbound = SCIPnodeGetLowerbound(node);
501 
502    if ( visual->vbcfile != NULL )
503    {
504       printTime(visual, stat, TRUE);
505       if( branchvar != NULL )
506       {
507          SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t%s [%g,%g] %s %f\\nbound:\\t%f\\nnr:\\t%" SCIP_LONGINT_FORMAT "\n",
508             nodenum, nodenum, (void*)node, SCIPnodeGetDepth(node),
509             SCIPvarGetName(branchvar),  SCIPvarGetLbLocal(branchvar), SCIPvarGetUbLocal(branchvar),
510             branchtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",  branchbound, lowerbound, stat->nnodes);
511       }
512       else
513       {
514          SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t-\\nbound:\\t%f\\nnr:\\t%" SCIP_LONGINT_FORMAT "\n",
515             nodenum, nodenum, (void*)node, SCIPnodeGetDepth(node), lowerbound, stat->nnodes);
516       }
517       vbcSetColor(visual, stat, node, SCIP_VBCCOLOR_SOLVED);
518    }
519 
520    /* do nothing for BAK */
521 }
522 
523 /** changes the color of the node to the color of cutoff nodes */
SCIPvisualCutoffNode(SCIP_VISUAL * visual,SCIP_SET * set,SCIP_STAT * stat,SCIP_NODE * node,SCIP_Bool infeasible)524 void SCIPvisualCutoffNode(
525    SCIP_VISUAL*          visual,             /**< visualization information */
526    SCIP_SET*             set,                /**< global SCIP settings */
527    SCIP_STAT*            stat,               /**< problem statistics */
528    SCIP_NODE*            node,               /**< node, that was cut off */
529    SCIP_Bool             infeasible          /**< whether the node is infeasible (otherwise exceeded the cutoff bound) */
530    )
531 {
532    SCIP_VAR* branchvar;
533    SCIP_BOUNDTYPE branchtype;
534    SCIP_Real branchbound;
535    SCIP_Real lowerbound;
536    int nodenum;
537 
538    assert( visual != NULL );
539    assert( stat != NULL );
540    assert( node != NULL );
541 
542    /* check whether output should be created */
543    if ( visual->vbcfile == NULL && visual->bakfile == NULL )
544       return;
545 
546    /* visualization is disabled on probing nodes */
547    if( SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE )
548       return;
549 
550    /* get node num from hash map */
551    nodenum = SCIPhashmapGetImageInt(visual->nodenum, node);
552    assert(nodenum > 0);
553 
554    /* get branching information */
555    getBranchInfo(node, &branchvar, &branchtype, &branchbound);
556 
557    /* determine lower bound */
558    if ( set->visual_objextern )
559       lowerbound = SCIPretransformObj(set->scip, SCIPnodeGetLowerbound(node));
560    else
561       lowerbound = SCIPnodeGetLowerbound(node);
562 
563    if ( visual->vbcfile != NULL )
564    {
565       printTime(visual, stat, TRUE);
566       if( branchvar != NULL )
567       {
568          SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t%s [%g,%g] %s %f\\nbound:\\t%f\\nnr:\\t%" SCIP_LONGINT_FORMAT "\n",
569             nodenum, nodenum, (void*)node, SCIPnodeGetDepth(node),
570             SCIPvarGetName(branchvar),  SCIPvarGetLbLocal(branchvar), SCIPvarGetUbLocal(branchvar),
571             branchtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",  branchbound, lowerbound, stat->nnodes);
572       }
573       else
574       {
575          SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "I %d \\inode:\\t%d (%p)\\idepth:\\t%d\\nvar:\\t-\\nbound:\\t%f\\nnr:\\t%" SCIP_LONGINT_FORMAT "\n",
576             nodenum, nodenum, (void*)node, SCIPnodeGetDepth(node), lowerbound, stat->nnodes);
577       }
578       vbcSetColor(visual, stat, node, SCIP_VBCCOLOR_CUTOFF);
579    }
580 
581    if ( visual->bakfile != NULL )
582    {
583       int parentnodenum;
584       char t = 'M';
585 
586       /* determine branching type */
587       if ( branchvar != NULL )
588          t = (branchtype == SCIP_BOUNDTYPE_LOWER ? 'R' : 'L');
589 
590       /* get nodenum of parent node from hash map */
591       parentnodenum = (node->parent != NULL ? SCIPhashmapGetImageInt(visual->nodenum, node->parent) : 0);
592       assert(node->parent == NULL || parentnodenum > 0);
593 
594       printTime(visual, stat, FALSE);
595       if ( infeasible )
596          SCIPmessageFPrintInfo(visual->messagehdlr, visual->bakfile, "infeasible %d %d %c\n", nodenum, parentnodenum, t);
597       else
598          SCIPmessageFPrintInfo(visual->messagehdlr, visual->bakfile, "fathomed %d %d %c\n", nodenum, parentnodenum, t);
599    }
600 }
601 
602 /** changes the color of the node to the color of nodes where a conflict constraint was found */
SCIPvisualFoundConflict(SCIP_VISUAL * visual,SCIP_STAT * stat,SCIP_NODE * node)603 void SCIPvisualFoundConflict(
604    SCIP_VISUAL*          visual,             /**< visualization information */
605    SCIP_STAT*            stat,               /**< problem statistics */
606    SCIP_NODE*            node                /**< node, where the conflict was found */
607    )
608 {
609    assert(node != NULL);
610 
611    /* visualization is disabled on probing nodes */
612    if( SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE )
613       return;
614 
615    vbcSetColor(visual, stat, node, SCIP_VBCCOLOR_CONFLICT);
616 
617    /* do nothing for BAK */
618 }
619 
620 /** changes the color of the node to the color of nodes that were marked to be repropagated */
SCIPvisualMarkedRepropagateNode(SCIP_VISUAL * visual,SCIP_STAT * stat,SCIP_NODE * node)621 void SCIPvisualMarkedRepropagateNode(
622    SCIP_VISUAL*          visual,             /**< visualization information */
623    SCIP_STAT*            stat,               /**< problem statistics */
624    SCIP_NODE*            node                /**< node, that was marked to be repropagated */
625    )
626 {
627    assert(node != NULL);
628 
629    /* visualization is disabled on probing nodes */
630    if( SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE )
631       return;
632 
633    /* if the node number is zero, then SCIP is currently in probing and wants to mark a probing node; however this node
634     * is not part of the search tree */
635    if( SCIPnodeGetNumber(node) > 0 )
636       vbcSetColor(visual, stat, node, SCIP_VBCCOLOR_MARKREPROP);
637 
638    /* do nothing for BAK */
639 }
640 
641 /** changes the color of the node to the color of repropagated nodes */
SCIPvisualRepropagatedNode(SCIP_VISUAL * visual,SCIP_STAT * stat,SCIP_NODE * node)642 void SCIPvisualRepropagatedNode(
643    SCIP_VISUAL*          visual,             /**< visualization information */
644    SCIP_STAT*            stat,               /**< problem statistics */
645    SCIP_NODE*            node                /**< node, that was repropagated */
646    )
647 {
648    assert(node != NULL);
649 
650    /* visualization is disabled on probing nodes */
651    if( SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE )
652       return;
653 
654    vbcSetColor(visual, stat, node, SCIP_VBCCOLOR_REPROP);
655 
656    /* do nothing for BAK */
657 }
658 
659 /** changes the color of the node to the color of nodes with a primal solution */
SCIPvisualFoundSolution(SCIP_VISUAL * visual,SCIP_SET * set,SCIP_STAT * stat,SCIP_NODE * node,SCIP_Bool bettersol,SCIP_SOL * sol)660 void SCIPvisualFoundSolution(
661    SCIP_VISUAL*          visual,             /**< visualization information */
662    SCIP_SET*             set,                /**< global SCIP settings */
663    SCIP_STAT*            stat,               /**< problem statistics */
664    SCIP_NODE*            node,               /**< node where the solution was found, or NULL */
665    SCIP_Bool             bettersol,          /**< the solution was better than the previous ones */
666    SCIP_SOL*             sol                 /**< solution that has been found */
667    )
668 {
669    if( node == NULL || ! set->visual_dispsols )
670       return;
671 
672    if( visual->vbcfile != NULL )
673    {
674       SCIP_Real obj;
675       int nodenum;
676 
677       /* if we are in probing, determine original parent node */
678       while ( SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE )
679          node = SCIPnodeGetParent(node);
680 
681       /* get node num from hash map */
682       assert(node != NULL);
683       nodenum = SCIPhashmapGetImageInt(visual->nodenum, node);
684       assert(nodenum > 0);
685 
686       /* get objective of solution */
687       if( set->visual_objextern )
688          obj = SCIPgetSolOrigObj(set->scip, sol);
689       else
690          obj = SCIPgetSolTransObj(set->scip, sol);
691 
692       printTime(visual, stat, TRUE);
693       if( bettersol )
694       {
695          /* note that this output is in addition to the one by SCIPvisualUpperbound() */
696          SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "A %d \\nfound better solution: %f\n", (int)nodenum, obj);
697       }
698       else
699          SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "A %d \\nfound solution: %f\n", (int)nodenum, obj);
700 
701       vbcSetColor(visual, stat, node, SCIP_VBCCOLOR_SOLUTION);
702    }
703 
704    if( visual->bakfile != NULL && bettersol )
705    {
706       SCIP_Real obj;
707 
708       if( set->visual_objextern )
709          obj = SCIPgetSolOrigObj(set->scip, sol);
710       else
711          obj = SCIPgetSolTransObj(set->scip, sol);
712 
713       if( SCIPsolGetHeur(sol) == NULL )
714       {
715          /* if LP solution was feasible ... */
716          SCIP_VAR* branchvar;
717          SCIP_BOUNDTYPE branchtype;
718          SCIP_Real branchbound;
719          SCIP_NODE *pnode;
720          int parentnodenum;
721          int nodenum;
722          char t = 'M';
723 
724          /* find first parent that is not a probing node */
725          assert(node != NULL);
726          pnode = node;
727          while( pnode != NULL && SCIPnodeGetType(pnode) == SCIP_NODETYPE_PROBINGNODE )
728             pnode = pnode->parent;
729 
730          if( pnode != NULL )
731          {
732             /* get node num from hash map */
733             nodenum = SCIPhashmapGetImageInt(visual->nodenum, pnode);
734 
735             /* get nodenum of parent node from hash map */
736             parentnodenum = (pnode->parent != NULL ? SCIPhashmapGetImageInt(visual->nodenum, pnode->parent) : 0);
737             assert(pnode->parent == NULL || parentnodenum > 0);
738 
739             /* get branching information */
740             getBranchInfo(pnode, &branchvar, &branchtype, &branchbound);
741 
742             /* determine branching type */
743             if( branchvar != NULL )
744                t = (branchtype == SCIP_BOUNDTYPE_LOWER ? 'R' : 'L');
745 
746             printTime(visual, stat, FALSE);
747             SCIPmessageFPrintInfo(visual->messagehdlr, visual->bakfile, "integer %d %d %c %f\n", nodenum, parentnodenum, t, obj);
748          }
749       }  /*lint !e438*/
750       else
751       {
752          printTime(visual, stat, FALSE);
753          SCIPmessageFPrintInfo(visual->messagehdlr, visual->bakfile, "heuristic %f\n", obj);
754       }
755    }
756 }
757 
758 /** outputs a new global lower bound to the visualization output file */
SCIPvisualLowerbound(SCIP_VISUAL * visual,SCIP_SET * set,SCIP_STAT * stat,SCIP_Real lowerbound)759 void SCIPvisualLowerbound(
760    SCIP_VISUAL*          visual,             /**< visualization information */
761    SCIP_SET*             set,                /**< global SCIP settings */
762    SCIP_STAT*            stat,               /**< problem statistics */
763    SCIP_Real             lowerbound          /**< new lower bound */
764    )
765 {
766    assert(visual != NULL);
767 
768    /* do not output if not required */
769    if ( ! set->visual_displb )
770       return;
771 
772    /* check, if VBC output should be created */
773    if( visual->vbcfile == NULL )
774       return;
775 
776    /* only output if lowerbound has improved and is finite */
777    if ( ! SCIPsetIsInfinity(set, lowerbound) && SCIPsetIsGT(set, lowerbound, visual->lastlowerbound) )
778    {
779       visual->lastlowerbound = lowerbound;
780 
781       /* determine external lower bound */
782       if( set->visual_objextern )
783          lowerbound = SCIPretransformObj(set->scip, lowerbound);
784 
785       printTime(visual, stat, TRUE);
786       if( SCIPgetObjsense(set->scip) == SCIP_OBJSENSE_MINIMIZE )
787          SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "L %f\n", lowerbound);
788       else
789          SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "U %f\n", lowerbound);
790    }
791 
792    /* do nothing for BAK */
793 }
794 
795 /** outputs a new global upper bound to the visualization output file */
SCIPvisualUpperbound(SCIP_VISUAL * visual,SCIP_SET * set,SCIP_STAT * stat,SCIP_Real upperbound)796 void SCIPvisualUpperbound(
797    SCIP_VISUAL*          visual,             /**< visualization information */
798    SCIP_SET*             set,                /**< global SCIP settings */
799    SCIP_STAT*            stat,               /**< problem statistics */
800    SCIP_Real             upperbound          /**< new upper bound */
801    )
802 {
803    assert(visual != NULL);
804 
805    /* check, if VBC output should be created */
806    if( visual->vbcfile == NULL )
807       return;
808 
809    /* determine external upper bound */
810    if( set->visual_objextern )
811       upperbound = SCIPretransformObj(set->scip, upperbound);
812 
813    printTime(visual, stat, TRUE);
814    if( SCIPgetObjsense(set->scip) == SCIP_OBJSENSE_MINIMIZE )
815       SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "U %f\n", upperbound);
816    else
817       SCIPmessageFPrintInfo(visual->messagehdlr, visual->vbcfile, "L %f\n", upperbound);
818 
819    /* do nothing for BAK */
820 }
821