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   tree.c
17  * @ingroup OTHER_CFILES
18  * @brief  methods for branch and bound tree
19  * @author Tobias Achterberg
20  * @author Timo Berthold
21  * @author Gerald Gamrath
22  */
23 
24 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
25 
26 #include <assert.h>
27 
28 #include "scip/def.h"
29 #include "scip/set.h"
30 #include "scip/stat.h"
31 #include "scip/clock.h"
32 #include "scip/visual.h"
33 #include "scip/event.h"
34 #include "scip/lp.h"
35 #include "scip/relax.h"
36 #include "scip/var.h"
37 #include "scip/implics.h"
38 #include "scip/primal.h"
39 #include "scip/tree.h"
40 #include "scip/reopt.h"
41 #include "scip/conflictstore.h"
42 #include "scip/solve.h"
43 #include "scip/cons.h"
44 #include "scip/nodesel.h"
45 #include "scip/prop.h"
46 #include "scip/debug.h"
47 #include "scip/prob.h"
48 #include "scip/scip.h"
49 #include "scip/struct_event.h"
50 #include "scip/pub_message.h"
51 #include "scip/struct_branch.h"
52 #include "lpi/lpi.h"
53 
54 
55 #define MAXREPROPMARK       511  /**< maximal subtree repropagation marker; must correspond to node data structure */
56 
57 
58 /*
59  * dynamic memory arrays
60  */
61 
62 /** resizes children arrays to be able to store at least num nodes */
63 static
treeEnsureChildrenMem(SCIP_TREE * tree,SCIP_SET * set,int num)64 SCIP_RETCODE treeEnsureChildrenMem(
65    SCIP_TREE*            tree,               /**< branch and bound tree */
66    SCIP_SET*             set,                /**< global SCIP settings */
67    int                   num                 /**< minimal number of node slots in array */
68    )
69 {
70    assert(tree != NULL);
71    assert(set != NULL);
72 
73    if( num > tree->childrensize )
74    {
75       int newsize;
76 
77       newsize = SCIPsetCalcMemGrowSize(set, num);
78       SCIP_ALLOC( BMSreallocMemoryArray(&tree->children, newsize) );
79       SCIP_ALLOC( BMSreallocMemoryArray(&tree->childrenprio, newsize) );
80       tree->childrensize = newsize;
81    }
82    assert(num <= tree->childrensize);
83 
84    return SCIP_OKAY;
85 }
86 
87 /** resizes path array to be able to store at least num nodes */
88 static
treeEnsurePathMem(SCIP_TREE * tree,SCIP_SET * set,int num)89 SCIP_RETCODE treeEnsurePathMem(
90    SCIP_TREE*            tree,               /**< branch and bound tree */
91    SCIP_SET*             set,                /**< global SCIP settings */
92    int                   num                 /**< minimal number of node slots in path */
93    )
94 {
95    assert(tree != NULL);
96    assert(set != NULL);
97 
98    if( num > tree->pathsize )
99    {
100       int newsize;
101 
102       newsize = SCIPsetCalcPathGrowSize(set, num);
103       SCIP_ALLOC( BMSreallocMemoryArray(&tree->path, newsize) );
104       SCIP_ALLOC( BMSreallocMemoryArray(&tree->pathnlpcols, newsize) );
105       SCIP_ALLOC( BMSreallocMemoryArray(&tree->pathnlprows, newsize) );
106       tree->pathsize = newsize;
107    }
108    assert(num <= tree->pathsize);
109 
110    return SCIP_OKAY;
111 }
112 
113 /** resizes pendingbdchgs array to be able to store at least num nodes */
114 static
treeEnsurePendingbdchgsMem(SCIP_TREE * tree,SCIP_SET * set,int num)115 SCIP_RETCODE treeEnsurePendingbdchgsMem(
116    SCIP_TREE*            tree,               /**< branch and bound tree */
117    SCIP_SET*             set,                /**< global SCIP settings */
118    int                   num                 /**< minimal number of node slots in path */
119    )
120 {
121    assert(tree != NULL);
122    assert(set != NULL);
123 
124    if( num > tree->pendingbdchgssize )
125    {
126       int newsize;
127 
128       newsize = SCIPsetCalcMemGrowSize(set, num);
129       SCIP_ALLOC( BMSreallocMemoryArray(&tree->pendingbdchgs, newsize) );
130       tree->pendingbdchgssize = newsize;
131    }
132    assert(num <= tree->pendingbdchgssize);
133 
134    return SCIP_OKAY;
135 }
136 
137 
138 
139 
140 /*
141  * Node methods
142  */
143 
144 /** node comparator for best lower bound */
SCIP_DECL_SORTPTRCOMP(SCIPnodeCompLowerbound)145 SCIP_DECL_SORTPTRCOMP(SCIPnodeCompLowerbound)
146 {  /*lint --e{715}*/
147    assert(elem1 != NULL);
148    assert(elem2 != NULL);
149 
150    if( ((SCIP_NODE*)elem1)->lowerbound < ((SCIP_NODE*)elem2)->lowerbound )
151       return -1;
152    else if( ((SCIP_NODE*)elem1)->lowerbound > ((SCIP_NODE*)elem2)->lowerbound )
153       return +1;
154    else
155       return 0;
156 }
157 
158 /** increases the reference counter of the LP state in the fork */
159 static
forkCaptureLPIState(SCIP_FORK * fork,int nuses)160 void forkCaptureLPIState(
161    SCIP_FORK*            fork,               /**< fork data */
162    int                   nuses               /**< number to add to the usage counter */
163    )
164 {
165    assert(fork != NULL);
166    assert(fork->nlpistateref >= 0);
167    assert(nuses > 0);
168 
169    fork->nlpistateref += nuses;
170    SCIPdebugMessage("captured LPI state of fork %p %d times -> new nlpistateref=%d\n", (void*)fork, nuses, fork->nlpistateref);
171 }
172 
173 /** decreases the reference counter of the LP state in the fork */
174 static
forkReleaseLPIState(SCIP_FORK * fork,BMS_BLKMEM * blkmem,SCIP_LP * lp)175 SCIP_RETCODE forkReleaseLPIState(
176    SCIP_FORK*            fork,               /**< fork data */
177    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
178    SCIP_LP*              lp                  /**< current LP data */
179    )
180 {
181    assert(fork != NULL);
182    assert(fork->nlpistateref > 0);
183    assert(blkmem != NULL);
184    assert(lp != NULL);
185 
186    fork->nlpistateref--;
187    if( fork->nlpistateref == 0 )
188    {
189       SCIP_CALL( SCIPlpFreeState(lp, blkmem, &(fork->lpistate)) );
190    }
191 
192    SCIPdebugMessage("released LPI state of fork %p -> new nlpistateref=%d\n", (void*)fork, fork->nlpistateref);
193 
194    return SCIP_OKAY;
195 }
196 
197 /** increases the reference counter of the LP state in the subroot */
198 static
subrootCaptureLPIState(SCIP_SUBROOT * subroot,int nuses)199 void subrootCaptureLPIState(
200    SCIP_SUBROOT*         subroot,            /**< subroot data */
201    int                   nuses               /**< number to add to the usage counter */
202    )
203 {
204    assert(subroot != NULL);
205    assert(subroot->nlpistateref >= 0);
206    assert(nuses > 0);
207 
208    subroot->nlpistateref += nuses;
209    SCIPdebugMessage("captured LPI state of subroot %p %d times -> new nlpistateref=%d\n",
210       (void*)subroot, nuses, subroot->nlpistateref);
211 }
212 
213 /** decreases the reference counter of the LP state in the subroot */
214 static
subrootReleaseLPIState(SCIP_SUBROOT * subroot,BMS_BLKMEM * blkmem,SCIP_LP * lp)215 SCIP_RETCODE subrootReleaseLPIState(
216    SCIP_SUBROOT*         subroot,            /**< subroot data */
217    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
218    SCIP_LP*              lp                  /**< current LP data */
219    )
220 {
221    assert(subroot != NULL);
222    assert(subroot->nlpistateref > 0);
223    assert(blkmem != NULL);
224    assert(lp != NULL);
225 
226    subroot->nlpistateref--;
227    if( subroot->nlpistateref == 0 )
228    {
229       SCIP_CALL( SCIPlpFreeState(lp, blkmem, &(subroot->lpistate)) );
230    }
231 
232    SCIPdebugMessage("released LPI state of subroot %p -> new nlpistateref=%d\n", (void*)subroot, subroot->nlpistateref);
233 
234    return SCIP_OKAY;
235 }
236 
237 /** increases the reference counter of the LP state in the fork or subroot node */
SCIPnodeCaptureLPIState(SCIP_NODE * node,int nuses)238 SCIP_RETCODE SCIPnodeCaptureLPIState(
239    SCIP_NODE*            node,               /**< fork/subroot node */
240    int                   nuses               /**< number to add to the usage counter */
241    )
242 {
243    assert(node != NULL);
244 
245    SCIPdebugMessage("capture %d times LPI state of node #%" SCIP_LONGINT_FORMAT " at depth %d (current: %d)\n",
246       nuses, SCIPnodeGetNumber(node), SCIPnodeGetDepth(node),
247       SCIPnodeGetType(node) == SCIP_NODETYPE_FORK ? node->data.fork->nlpistateref : node->data.subroot->nlpistateref);
248 
249    switch( SCIPnodeGetType(node) )
250    {
251    case SCIP_NODETYPE_FORK:
252       forkCaptureLPIState(node->data.fork, nuses);
253       break;
254    case SCIP_NODETYPE_SUBROOT:
255       subrootCaptureLPIState(node->data.subroot, nuses);
256       break;
257    default:
258       SCIPerrorMessage("node for capturing the LPI state is neither fork nor subroot\n");
259       SCIPABORT();
260       return SCIP_INVALIDDATA;  /*lint !e527*/
261    }  /*lint !e788*/
262    return SCIP_OKAY;
263 }
264 
265 /** decreases the reference counter of the LP state in the fork or subroot node */
SCIPnodeReleaseLPIState(SCIP_NODE * node,BMS_BLKMEM * blkmem,SCIP_LP * lp)266 SCIP_RETCODE SCIPnodeReleaseLPIState(
267    SCIP_NODE*            node,               /**< fork/subroot node */
268    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
269    SCIP_LP*              lp                  /**< current LP data */
270    )
271 {
272    assert(node != NULL);
273 
274    SCIPdebugMessage("release LPI state of node #%" SCIP_LONGINT_FORMAT " at depth %d (current: %d)\n",
275       SCIPnodeGetNumber(node), SCIPnodeGetDepth(node),
276       SCIPnodeGetType(node) == SCIP_NODETYPE_FORK ? node->data.fork->nlpistateref : node->data.subroot->nlpistateref);
277    switch( SCIPnodeGetType(node) )
278    {
279    case SCIP_NODETYPE_FORK:
280       return forkReleaseLPIState(node->data.fork, blkmem, lp);
281    case SCIP_NODETYPE_SUBROOT:
282       return subrootReleaseLPIState(node->data.subroot, blkmem, lp);
283    default:
284       SCIPerrorMessage("node for releasing the LPI state is neither fork nor subroot\n");
285       return SCIP_INVALIDDATA;
286    }  /*lint !e788*/
287 }
288 
289 /** creates probingnode data without LP information */
290 static
probingnodeCreate(SCIP_PROBINGNODE ** probingnode,BMS_BLKMEM * blkmem,SCIP_LP * lp)291 SCIP_RETCODE probingnodeCreate(
292    SCIP_PROBINGNODE**    probingnode,        /**< pointer to probingnode data */
293    BMS_BLKMEM*           blkmem,             /**< block memory */
294    SCIP_LP*              lp                  /**< current LP data */
295    )
296 {
297    assert(probingnode != NULL);
298 
299    SCIP_ALLOC( BMSallocBlockMemory(blkmem, probingnode) );
300 
301    (*probingnode)->lpistate = NULL;
302    (*probingnode)->lpinorms = NULL;
303    (*probingnode)->ninitialcols = SCIPlpGetNCols(lp);
304    (*probingnode)->ninitialrows = SCIPlpGetNRows(lp);
305    (*probingnode)->ncols = (*probingnode)->ninitialcols;
306    (*probingnode)->nrows = (*probingnode)->ninitialrows;
307    (*probingnode)->origobjvars = NULL;
308    (*probingnode)->origobjvals = NULL;
309    (*probingnode)->nchgdobjs = 0;
310 
311    SCIPdebugMessage("created probingnode information (%d cols, %d rows)\n", (*probingnode)->ncols, (*probingnode)->nrows);
312 
313    return SCIP_OKAY;
314 }
315 
316 /** updates LP information in probingnode data */
317 static
probingnodeUpdate(SCIP_PROBINGNODE * probingnode,BMS_BLKMEM * blkmem,SCIP_TREE * tree,SCIP_LP * lp)318 SCIP_RETCODE probingnodeUpdate(
319    SCIP_PROBINGNODE*     probingnode,        /**< probingnode data */
320    BMS_BLKMEM*           blkmem,             /**< block memory */
321    SCIP_TREE*            tree,               /**< branch and bound tree */
322    SCIP_LP*              lp                  /**< current LP data */
323    )
324 {
325    SCIP_Bool storenorms = FALSE;
326 
327    assert(probingnode != NULL);
328    assert(SCIPtreeIsPathComplete(tree));
329    assert(lp != NULL);
330 
331    /* free old LP state */
332    if( probingnode->lpistate != NULL )
333    {
334       SCIP_CALL( SCIPlpFreeState(lp, blkmem, &probingnode->lpistate) );
335    }
336 
337    /* free old LP norms */
338    if( probingnode->lpinorms != NULL )
339    {
340       SCIP_CALL( SCIPlpFreeNorms(lp, blkmem, &probingnode->lpinorms) );
341       probingnode->lpinorms = NULL;
342       storenorms = TRUE;
343    }
344 
345    /* get current LP state */
346    if( lp->flushed && lp->solved )
347    {
348       SCIP_CALL( SCIPlpGetState(lp, blkmem, &probingnode->lpistate) );
349 
350       /* if LP norms were stored at this node before, store the new ones */
351       if( storenorms )
352       {
353          SCIP_CALL( SCIPlpGetNorms(lp, blkmem, &probingnode->lpinorms) );
354       }
355       probingnode->lpwasprimfeas = lp->primalfeasible;
356       probingnode->lpwasprimchecked = lp->primalchecked;
357       probingnode->lpwasdualfeas = lp->dualfeasible;
358       probingnode->lpwasdualchecked = lp->dualchecked;
359    }
360    else
361       probingnode->lpistate = NULL;
362 
363    probingnode->ncols = SCIPlpGetNCols(lp);
364    probingnode->nrows = SCIPlpGetNRows(lp);
365 
366    SCIPdebugMessage("updated probingnode information (%d cols, %d rows)\n", probingnode->ncols, probingnode->nrows);
367 
368    return SCIP_OKAY;
369 }
370 
371 /** frees probingnode data */
372 static
probingnodeFree(SCIP_PROBINGNODE ** probingnode,BMS_BLKMEM * blkmem,SCIP_LP * lp)373 SCIP_RETCODE probingnodeFree(
374    SCIP_PROBINGNODE**    probingnode,        /**< probingnode data */
375    BMS_BLKMEM*           blkmem,             /**< block memory */
376    SCIP_LP*              lp                  /**< current LP data */
377    )
378 {
379    assert(probingnode != NULL);
380    assert(*probingnode != NULL);
381 
382    /* free the associated LP state */
383    if( (*probingnode)->lpistate != NULL )
384    {
385       SCIP_CALL( SCIPlpFreeState(lp, blkmem, &(*probingnode)->lpistate) );
386    }
387    /* free the associated LP norms */
388    if( (*probingnode)->lpinorms != NULL )
389    {
390       SCIP_CALL( SCIPlpFreeNorms(lp, blkmem, &(*probingnode)->lpinorms) );
391    }
392 
393    /* free objective information */
394    if( (*probingnode)->nchgdobjs > 0 )
395    {
396       assert((*probingnode)->origobjvars != NULL);
397       assert((*probingnode)->origobjvals != NULL);
398 
399       BMSfreeMemoryArray(&(*probingnode)->origobjvars);
400       BMSfreeMemoryArray(&(*probingnode)->origobjvals);
401    }
402 
403    BMSfreeBlockMemory(blkmem, probingnode);
404 
405    return SCIP_OKAY;
406 }
407 
408 /** initializes junction data */
409 static
junctionInit(SCIP_JUNCTION * junction,SCIP_TREE * tree)410 SCIP_RETCODE junctionInit(
411    SCIP_JUNCTION*        junction,           /**< pointer to junction data */
412    SCIP_TREE*            tree                /**< branch and bound tree */
413    )
414 {
415    assert(junction != NULL);
416    assert(tree != NULL);
417    assert(tree->nchildren > 0);
418    assert(SCIPtreeIsPathComplete(tree));
419    assert(tree->focusnode != NULL);
420 
421    junction->nchildren = tree->nchildren;
422 
423    /* increase the LPI state usage counter of the current LP fork */
424    if( tree->focuslpstatefork != NULL )
425    {
426       SCIP_CALL( SCIPnodeCaptureLPIState(tree->focuslpstatefork, tree->nchildren) );
427    }
428 
429    return SCIP_OKAY;
430 }
431 
432 /** creates pseudofork data */
433 static
pseudoforkCreate(SCIP_PSEUDOFORK ** pseudofork,BMS_BLKMEM * blkmem,SCIP_TREE * tree,SCIP_LP * lp)434 SCIP_RETCODE pseudoforkCreate(
435    SCIP_PSEUDOFORK**     pseudofork,         /**< pointer to pseudofork data */
436    BMS_BLKMEM*           blkmem,             /**< block memory */
437    SCIP_TREE*            tree,               /**< branch and bound tree */
438    SCIP_LP*              lp                  /**< current LP data */
439    )
440 {
441    assert(pseudofork != NULL);
442    assert(blkmem != NULL);
443    assert(tree != NULL);
444    assert(tree->nchildren > 0);
445    assert(SCIPtreeIsPathComplete(tree));
446    assert(tree->focusnode != NULL);
447 
448    SCIP_ALLOC( BMSallocBlockMemory(blkmem, pseudofork) );
449 
450    (*pseudofork)->addedcols = NULL;
451    (*pseudofork)->addedrows = NULL;
452    (*pseudofork)->naddedcols = SCIPlpGetNNewcols(lp);
453    (*pseudofork)->naddedrows = SCIPlpGetNNewrows(lp);
454    (*pseudofork)->nchildren = tree->nchildren;
455 
456    SCIPdebugMessage("creating pseudofork information with %d children (%d new cols, %d new rows)\n",
457       (*pseudofork)->nchildren, (*pseudofork)->naddedcols, (*pseudofork)->naddedrows);
458 
459    if( (*pseudofork)->naddedcols > 0 )
460    {
461       /* copy the newly created columns to the pseudofork's col array */
462       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*pseudofork)->addedcols, SCIPlpGetNewcols(lp), (*pseudofork)->naddedcols) ); /*lint !e666*/
463    }
464    if( (*pseudofork)->naddedrows > 0 )
465    {
466       int i;
467 
468       /* copy the newly created rows to the pseudofork's row array */
469       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*pseudofork)->addedrows, SCIPlpGetNewrows(lp), (*pseudofork)->naddedrows) ); /*lint !e666*/
470 
471       /* capture the added rows */
472       for( i = 0; i < (*pseudofork)->naddedrows; ++i )
473          SCIProwCapture((*pseudofork)->addedrows[i]);
474    }
475 
476    /* increase the LPI state usage counter of the current LP fork */
477    if( tree->focuslpstatefork != NULL )
478    {
479       SCIP_CALL( SCIPnodeCaptureLPIState(tree->focuslpstatefork, tree->nchildren) );
480    }
481 
482    return SCIP_OKAY;
483 }
484 
485 /** frees pseudofork data */
486 static
pseudoforkFree(SCIP_PSEUDOFORK ** pseudofork,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_LP * lp)487 SCIP_RETCODE pseudoforkFree(
488    SCIP_PSEUDOFORK**     pseudofork,         /**< pseudofork data */
489    BMS_BLKMEM*           blkmem,             /**< block memory */
490    SCIP_SET*             set,                /**< global SCIP settings */
491    SCIP_LP*              lp                  /**< current LP data */
492    )
493 {
494    int i;
495 
496    assert(pseudofork != NULL);
497    assert(*pseudofork != NULL);
498    assert((*pseudofork)->nchildren == 0);
499    assert(blkmem != NULL);
500    assert(set != NULL);
501 
502    /* release the added rows */
503    for( i = 0; i < (*pseudofork)->naddedrows; ++i )
504    {
505       SCIP_CALL( SCIProwRelease(&(*pseudofork)->addedrows[i], blkmem, set, lp) );
506    }
507 
508    BMSfreeBlockMemoryArrayNull(blkmem, &(*pseudofork)->addedcols, (*pseudofork)->naddedcols);
509    BMSfreeBlockMemoryArrayNull(blkmem, &(*pseudofork)->addedrows, (*pseudofork)->naddedrows);
510    BMSfreeBlockMemory(blkmem, pseudofork);
511 
512    return SCIP_OKAY;
513 }
514 
515 /** creates fork data */
516 static
forkCreate(SCIP_FORK ** fork,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_PROB * prob,SCIP_TREE * tree,SCIP_LP * lp)517 SCIP_RETCODE forkCreate(
518    SCIP_FORK**           fork,               /**< pointer to fork data */
519    BMS_BLKMEM*           blkmem,             /**< block memory */
520    SCIP_SET*             set,                /**< global SCIP settings */
521    SCIP_PROB*            prob,               /**< transformed problem after presolve */
522    SCIP_TREE*            tree,               /**< branch and bound tree */
523    SCIP_LP*              lp                  /**< current LP data */
524    )
525 {
526    assert(fork != NULL);
527    assert(blkmem != NULL);
528    assert(tree != NULL);
529    assert(tree->nchildren > 0);
530    assert(tree->nchildren < (1 << 30));
531    assert(SCIPtreeIsPathComplete(tree));
532    assert(tree->focusnode != NULL);
533    assert(lp != NULL);
534    assert(lp->flushed);
535    assert(lp->solved);
536    assert(SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL);
537 
538    SCIP_ALLOC( BMSallocBlockMemory(blkmem, fork) );
539 
540    SCIP_CALL( SCIPlpGetState(lp, blkmem, &((*fork)->lpistate)) );
541    (*fork)->lpwasprimfeas = lp->primalfeasible;
542    (*fork)->lpwasprimchecked = lp->primalchecked;
543    (*fork)->lpwasdualfeas = lp->dualfeasible;
544    (*fork)->lpwasdualchecked = lp->dualchecked;
545    (*fork)->lpobjval = SCIPlpGetObjval(lp, set, prob);
546    (*fork)->nlpistateref = 0;
547    (*fork)->addedcols = NULL;
548    (*fork)->addedrows = NULL;
549    (*fork)->naddedcols = SCIPlpGetNNewcols(lp);
550    (*fork)->naddedrows = SCIPlpGetNNewrows(lp);
551    (*fork)->nchildren = (unsigned int) tree->nchildren;
552 
553    SCIPsetDebugMsg(set, "creating fork information with %u children (%d new cols, %d new rows)\n", (*fork)->nchildren, (*fork)->naddedcols, (*fork)->naddedrows);
554 
555    if( (*fork)->naddedcols > 0 )
556    {
557       /* copy the newly created columns to the fork's col array */
558       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*fork)->addedcols, SCIPlpGetNewcols(lp), (*fork)->naddedcols) ); /*lint !e666*/
559    }
560    if( (*fork)->naddedrows > 0 )
561    {
562       int i;
563 
564       /* copy the newly created rows to the fork's row array */
565       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*fork)->addedrows, SCIPlpGetNewrows(lp), (*fork)->naddedrows) ); /*lint !e666*/
566 
567       /* capture the added rows */
568       for( i = 0; i < (*fork)->naddedrows; ++i )
569          SCIProwCapture((*fork)->addedrows[i]);
570    }
571 
572    /* capture the LPI state for the children */
573    forkCaptureLPIState(*fork, tree->nchildren);
574 
575    return SCIP_OKAY;
576 }
577 
578 /** frees fork data */
579 static
forkFree(SCIP_FORK ** fork,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_LP * lp)580 SCIP_RETCODE forkFree(
581    SCIP_FORK**           fork,               /**< fork data */
582    BMS_BLKMEM*           blkmem,             /**< block memory */
583    SCIP_SET*             set,                /**< global SCIP settings */
584    SCIP_LP*              lp                  /**< current LP data */
585    )
586 {
587    int i;
588 
589    assert(fork != NULL);
590    assert(*fork != NULL);
591    assert((*fork)->nchildren == 0);
592    assert((*fork)->nlpistateref == 0);
593    assert((*fork)->lpistate == NULL);
594    assert(blkmem != NULL);
595    assert(set != NULL);
596    assert(lp != NULL);
597 
598    /* release the added rows */
599    for( i = (*fork)->naddedrows - 1; i >= 0; --i )
600    {
601       SCIP_CALL( SCIProwRelease(&(*fork)->addedrows[i], blkmem, set, lp) );
602    }
603 
604    BMSfreeBlockMemoryArrayNull(blkmem, &(*fork)->addedcols, (*fork)->naddedcols);
605    BMSfreeBlockMemoryArrayNull(blkmem, &(*fork)->addedrows, (*fork)->naddedrows);
606    BMSfreeBlockMemory(blkmem, fork);
607 
608    return SCIP_OKAY;
609 }
610 
611 #ifdef WITHSUBROOTS /** @todo test whether subroots should be created */
612 /** creates subroot data */
613 static
subrootCreate(SCIP_SUBROOT ** subroot,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_PROB * prob,SCIP_TREE * tree,SCIP_LP * lp)614 SCIP_RETCODE subrootCreate(
615    SCIP_SUBROOT**        subroot,            /**< pointer to subroot data */
616    BMS_BLKMEM*           blkmem,             /**< block memory */
617    SCIP_SET*             set,                /**< global SCIP settings */
618    SCIP_PROB*            prob,               /**< transformed problem after presolve */
619    SCIP_TREE*            tree,               /**< branch and bound tree */
620    SCIP_LP*              lp                  /**< current LP data */
621    )
622 {
623    int i;
624 
625    assert(subroot != NULL);
626    assert(blkmem != NULL);
627    assert(tree != NULL);
628    assert(tree->nchildren > 0);
629    assert(SCIPtreeIsPathComplete(tree));
630    assert(tree->focusnode != NULL);
631    assert(lp != NULL);
632    assert(lp->flushed);
633    assert(lp->solved);
634    assert(SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL);
635 
636    SCIP_ALLOC( BMSallocBlockMemory(blkmem, subroot) );
637    (*subroot)->lpobjval = SCIPlpGetObjval(lp, set, prob);
638    (*subroot)->nlpistateref = 0;
639    (*subroot)->ncols = SCIPlpGetNCols(lp);
640    (*subroot)->nrows = SCIPlpGetNRows(lp);
641    (*subroot)->nchildren = (unsigned int) tree->nchildren;
642    SCIP_CALL( SCIPlpGetState(lp, blkmem, &((*subroot)->lpistate)) );
643    (*subroot)->lpwasprimfeas = lp->primalfeasible;
644    (*subroot)->lpwasprimchecked = lp->primalchecked;
645    (*subroot)->lpwasdualfeas = lp->dualfeasible;
646    (*subroot)->lpwasdualchecked = lp->dualchecked;
647 
648    if( (*subroot)->ncols != 0 )
649    {
650       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*subroot)->cols, SCIPlpGetCols(lp), (*subroot)->ncols) );
651    }
652    else
653       (*subroot)->cols = NULL;
654    if( (*subroot)->nrows != 0 )
655    {
656       SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*subroot)->rows, SCIPlpGetRows(lp), (*subroot)->nrows) );
657    }
658    else
659       (*subroot)->rows = NULL;
660 
661    /* capture the rows of the subroot */
662    for( i = 0; i < (*subroot)->nrows; ++i )
663       SCIProwCapture((*subroot)->rows[i]);
664 
665    /* capture the LPI state for the children */
666    subrootCaptureLPIState(*subroot, tree->nchildren);
667 
668    return SCIP_OKAY;
669 }
670 #endif
671 
672 /** frees subroot */
673 static
subrootFree(SCIP_SUBROOT ** subroot,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_LP * lp)674 SCIP_RETCODE subrootFree(
675    SCIP_SUBROOT**        subroot,            /**< subroot data */
676    BMS_BLKMEM*           blkmem,             /**< block memory */
677    SCIP_SET*             set,                /**< global SCIP settings */
678    SCIP_LP*              lp                  /**< current LP data */
679    )
680 {
681    int i;
682 
683    assert(subroot != NULL);
684    assert(*subroot != NULL);
685    assert((*subroot)->nchildren == 0);
686    assert((*subroot)->nlpistateref == 0);
687    assert((*subroot)->lpistate == NULL);
688    assert(blkmem != NULL);
689    assert(set != NULL);
690    assert(lp != NULL);
691 
692    /* release the rows of the subroot */
693    for( i = 0; i < (*subroot)->nrows; ++i )
694    {
695       SCIP_CALL( SCIProwRelease(&(*subroot)->rows[i], blkmem, set, lp) );
696    }
697 
698    BMSfreeBlockMemoryArrayNull(blkmem, &(*subroot)->cols, (*subroot)->ncols);
699    BMSfreeBlockMemoryArrayNull(blkmem, &(*subroot)->rows, (*subroot)->nrows);
700    BMSfreeBlockMemory(blkmem, subroot);
701 
702    return SCIP_OKAY;
703 }
704 
705 /** removes given sibling node from the siblings array */
706 static
treeRemoveSibling(SCIP_TREE * tree,SCIP_NODE * sibling)707 void treeRemoveSibling(
708    SCIP_TREE*            tree,               /**< branch and bound tree */
709    SCIP_NODE*            sibling             /**< sibling node to remove */
710    )
711 {
712    int delpos;
713 
714    assert(tree != NULL);
715    assert(sibling != NULL);
716    assert(SCIPnodeGetType(sibling) == SCIP_NODETYPE_SIBLING);
717    assert(sibling->data.sibling.arraypos >= 0 && sibling->data.sibling.arraypos < tree->nsiblings);
718    assert(tree->siblings[sibling->data.sibling.arraypos] == sibling);
719    assert(SCIPnodeGetType(tree->siblings[tree->nsiblings-1]) == SCIP_NODETYPE_SIBLING);
720 
721    delpos = sibling->data.sibling.arraypos;
722 
723    /* move last sibling in array to position of removed sibling */
724    tree->siblings[delpos] = tree->siblings[tree->nsiblings-1];
725    tree->siblingsprio[delpos] = tree->siblingsprio[tree->nsiblings-1];
726    tree->siblings[delpos]->data.sibling.arraypos = delpos;
727    sibling->data.sibling.arraypos = -1;
728    tree->nsiblings--;
729 }
730 
731 /** adds given child node to children array of focus node */
732 static
treeAddChild(SCIP_TREE * tree,SCIP_SET * set,SCIP_NODE * child,SCIP_Real nodeselprio)733 SCIP_RETCODE treeAddChild(
734    SCIP_TREE*            tree,               /**< branch and bound tree */
735    SCIP_SET*             set,                /**< global SCIP settings */
736    SCIP_NODE*            child,              /**< child node to add */
737    SCIP_Real             nodeselprio         /**< node selection priority of child node */
738    )
739 {
740    assert(tree != NULL);
741    assert(child != NULL);
742    assert(SCIPnodeGetType(child) == SCIP_NODETYPE_CHILD);
743    assert(child->data.child.arraypos == -1);
744 
745    SCIP_CALL( treeEnsureChildrenMem(tree, set, tree->nchildren+1) );
746    tree->children[tree->nchildren] = child;
747    tree->childrenprio[tree->nchildren] = nodeselprio;
748    child->data.child.arraypos = tree->nchildren;
749    tree->nchildren++;
750 
751    return SCIP_OKAY;
752 }
753 
754 /** removes given child node from the children array */
755 static
treeRemoveChild(SCIP_TREE * tree,SCIP_NODE * child)756 void treeRemoveChild(
757    SCIP_TREE*            tree,               /**< branch and bound tree */
758    SCIP_NODE*            child               /**< child node to remove */
759    )
760 {
761    int delpos;
762 
763    assert(tree != NULL);
764    assert(child != NULL);
765    assert(SCIPnodeGetType(child) == SCIP_NODETYPE_CHILD);
766    assert(child->data.child.arraypos >= 0 && child->data.child.arraypos < tree->nchildren);
767    assert(tree->children[child->data.child.arraypos] == child);
768    assert(SCIPnodeGetType(tree->children[tree->nchildren-1]) == SCIP_NODETYPE_CHILD);
769 
770    delpos = child->data.child.arraypos;
771 
772    /* move last child in array to position of removed child */
773    tree->children[delpos] = tree->children[tree->nchildren-1];
774    tree->childrenprio[delpos] = tree->childrenprio[tree->nchildren-1];
775    tree->children[delpos]->data.child.arraypos = delpos;
776    child->data.child.arraypos = -1;
777    tree->nchildren--;
778 }
779 
780 /** makes node a child of the given parent node, which must be the focus node; if the child is a probing node,
781  *  the parent node can also be a refocused node or a probing node
782  */
783 static
nodeAssignParent(SCIP_NODE * node,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_TREE * tree,SCIP_NODE * parent,SCIP_Real nodeselprio)784 SCIP_RETCODE nodeAssignParent(
785    SCIP_NODE*            node,               /**< child node */
786    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
787    SCIP_SET*             set,                /**< global SCIP settings */
788    SCIP_TREE*            tree,               /**< branch and bound tree */
789    SCIP_NODE*            parent,             /**< parent (= focus) node (or NULL, if node is root) */
790    SCIP_Real             nodeselprio         /**< node selection priority of child node */
791    )
792 {
793    assert(node != NULL);
794    assert(node->parent == NULL);
795    assert(SCIPnodeGetType(node) == SCIP_NODETYPE_CHILD || SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE);
796    assert(node->conssetchg == NULL);
797    assert(node->domchg == NULL);
798    assert(SCIPsetIsInfinity(set, -node->lowerbound)); /* node was just created */
799    assert(blkmem != NULL);
800    assert(set != NULL);
801    assert(tree != NULL);
802    assert(SCIPtreeIsPathComplete(tree));
803    assert(tree->pathlen == 0 || tree->path[tree->pathlen-1] == parent);
804    assert(parent == tree->focusnode || SCIPnodeGetType(parent) == SCIP_NODETYPE_PROBINGNODE);
805    assert(parent == NULL || SCIPnodeGetType(parent) == SCIP_NODETYPE_FOCUSNODE
806       || (SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE
807          && (SCIPnodeGetType(parent) == SCIP_NODETYPE_REFOCUSNODE
808             || SCIPnodeGetType(parent) == SCIP_NODETYPE_PROBINGNODE)));
809 
810    /* link node to parent */
811    node->parent = parent;
812    if( parent != NULL )
813    {
814       assert(parent->lowerbound <= parent->estimate);
815       node->lowerbound = parent->lowerbound;
816       node->estimate = parent->estimate;
817       node->depth = parent->depth+1; /*lint !e732*/
818       if( parent->depth >= SCIP_MAXTREEDEPTH )
819       {
820          SCIPerrorMessage("maximal depth level exceeded\n");
821          return SCIP_MAXDEPTHLEVEL;
822       }
823    }
824    SCIPsetDebugMsg(set, "assigning parent #%" SCIP_LONGINT_FORMAT " to node #%" SCIP_LONGINT_FORMAT " at depth %d\n",
825       parent != NULL ? SCIPnodeGetNumber(parent) : -1, SCIPnodeGetNumber(node), SCIPnodeGetDepth(node));
826 
827    /* register node in the childlist of the focus (the parent) node */
828    if( SCIPnodeGetType(node) == SCIP_NODETYPE_CHILD )
829    {
830       assert(parent == NULL || SCIPnodeGetType(parent) == SCIP_NODETYPE_FOCUSNODE);
831       SCIP_CALL( treeAddChild(tree, set, node, nodeselprio) );
832    }
833 
834    return SCIP_OKAY;
835 }
836 
837 /** decreases number of children of the parent, frees it if no children are left */
838 static
nodeReleaseParent(SCIP_NODE * node,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue,SCIP_TREE * tree,SCIP_LP * lp)839 SCIP_RETCODE nodeReleaseParent(
840    SCIP_NODE*            node,               /**< child node */
841    BMS_BLKMEM*           blkmem,             /**< block memory buffer */
842    SCIP_SET*             set,                /**< global SCIP settings */
843    SCIP_STAT*            stat,               /**< problem statistics */
844    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
845    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
846    SCIP_TREE*            tree,               /**< branch and bound tree */
847    SCIP_LP*              lp                  /**< current LP data */
848    )
849 {
850    SCIP_NODE* parent;
851 
852    assert(node != NULL);
853    assert(blkmem != NULL);
854    assert(tree != NULL);
855 
856    SCIPsetDebugMsg(set, "releasing parent-child relationship of node #%" SCIP_LONGINT_FORMAT " at depth %d of type %d with parent #%" SCIP_LONGINT_FORMAT " of type %d\n",
857       SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), SCIPnodeGetType(node),
858       node->parent != NULL ? SCIPnodeGetNumber(node->parent) : -1,
859       node->parent != NULL ? (int)SCIPnodeGetType(node->parent) : -1);
860    parent = node->parent;
861    if( parent != NULL )
862    {
863       SCIP_Bool freeParent;
864       SCIP_Bool singleChild;
865 
866       freeParent = FALSE;
867       singleChild = FALSE;
868       switch( SCIPnodeGetType(parent) )
869       {
870       case SCIP_NODETYPE_FOCUSNODE:
871          assert(parent->active);
872          assert(SCIPnodeGetType(node) == SCIP_NODETYPE_CHILD || SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE
873             || SCIPnodeGetType(node) == SCIP_NODETYPE_LEAF);
874          if( SCIPnodeGetType(node) == SCIP_NODETYPE_CHILD )
875             treeRemoveChild(tree, node);
876          /* don't kill the focus node at this point => freeParent = FALSE */
877          break;
878       case SCIP_NODETYPE_PROBINGNODE:
879          assert(SCIPtreeProbing(tree));
880          /* probing nodes have to be freed individually => freeParent = FALSE */
881          break;
882       case SCIP_NODETYPE_SIBLING:
883          SCIPerrorMessage("sibling cannot be a parent node\n");
884          return SCIP_INVALIDDATA;
885       case SCIP_NODETYPE_CHILD:
886          SCIPerrorMessage("child cannot be a parent node\n");
887          return SCIP_INVALIDDATA;
888       case SCIP_NODETYPE_LEAF:
889          SCIPerrorMessage("leaf cannot be a parent node\n");
890          return SCIP_INVALIDDATA;
891       case SCIP_NODETYPE_DEADEND:
892          SCIPerrorMessage("dead-end cannot be a parent node\n");
893          return SCIP_INVALIDDATA;
894       case SCIP_NODETYPE_JUNCTION:
895          assert(parent->data.junction.nchildren > 0);
896          parent->data.junction.nchildren--;
897          freeParent = (parent->data.junction.nchildren == 0); /* free parent if it has no more children */
898          singleChild = (parent->data.junction.nchildren == 1);
899          break;
900       case SCIP_NODETYPE_PSEUDOFORK:
901          assert(parent->data.pseudofork != NULL);
902          assert(parent->data.pseudofork->nchildren > 0);
903          parent->data.pseudofork->nchildren--;
904          freeParent = (parent->data.pseudofork->nchildren == 0); /* free parent if it has no more children */
905          singleChild = (parent->data.pseudofork->nchildren == 1);
906          break;
907       case SCIP_NODETYPE_FORK:
908          assert(parent->data.fork != NULL);
909          assert(parent->data.fork->nchildren > 0);
910          parent->data.fork->nchildren--;
911          freeParent = (parent->data.fork->nchildren == 0); /* free parent if it has no more children */
912          singleChild = (parent->data.fork->nchildren == 1);
913          break;
914       case SCIP_NODETYPE_SUBROOT:
915          assert(parent->data.subroot != NULL);
916          assert(parent->data.subroot->nchildren > 0);
917          parent->data.subroot->nchildren--;
918          freeParent = (parent->data.subroot->nchildren == 0); /* free parent if it has no more children */
919          singleChild = (parent->data.subroot->nchildren == 1);
920          break;
921       case SCIP_NODETYPE_REFOCUSNODE:
922          /* the only possible child a refocused node can have in its refocus state is the probing root node;
923           * we don't want to free the refocused node, because we first have to convert it back to its original
924           * type (where it possibly has children) => freeParent = FALSE
925           */
926          assert(SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE);
927          assert(!SCIPtreeProbing(tree));
928          break;
929       default:
930          SCIPerrorMessage("unknown node type %d\n", SCIPnodeGetType(parent));
931          return SCIP_INVALIDDATA;
932       }
933 
934       /* free parent, if it is not on the current active path */
935       if( freeParent && !parent->active )
936       {
937          SCIP_CALL( SCIPnodeFree(&node->parent, blkmem, set, stat, eventfilter, eventqueue, tree, lp) );
938       }
939 
940       /* update the effective root depth
941        * in reoptimization we must not increase the effective root depth
942        */
943       assert(tree->effectiverootdepth >= 0);
944       if( singleChild && SCIPnodeGetDepth(parent) == tree->effectiverootdepth && !set->reopt_enable )
945       {
946          tree->effectiverootdepth++;
947          SCIPsetDebugMsg(set, "unlinked node #%" SCIP_LONGINT_FORMAT " in depth %d -> new effective root depth: %d\n",
948             SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), tree->effectiverootdepth);
949       }
950    }
951 
952    return SCIP_OKAY;
953 }
954 
955 /** creates a node data structure */
956 static
nodeCreate(SCIP_NODE ** node,BMS_BLKMEM * blkmem,SCIP_SET * set)957 SCIP_RETCODE nodeCreate(
958    SCIP_NODE**           node,               /**< pointer to node data structure */
959    BMS_BLKMEM*           blkmem,             /**< block memory */
960    SCIP_SET*             set                 /**< global SCIP settings */
961    )
962 {
963    assert(node != NULL);
964 
965    SCIP_ALLOC( BMSallocBlockMemory(blkmem, node) );
966    (*node)->parent = NULL;
967    (*node)->conssetchg = NULL;
968    (*node)->domchg = NULL;
969    (*node)->number = 0;
970    (*node)->lowerbound = -SCIPsetInfinity(set);
971    (*node)->estimate = -SCIPsetInfinity(set);
972    (*node)->reoptid = 0;
973    (*node)->reopttype = (unsigned int) SCIP_REOPTTYPE_NONE;
974    (*node)->depth = 0;
975    (*node)->active = FALSE;
976    (*node)->cutoff = FALSE;
977    (*node)->reprop = FALSE;
978    (*node)->repropsubtreemark = 0;
979 
980    return SCIP_OKAY;
981 }
982 
983 /** creates a child node of the focus node */
SCIPnodeCreateChild(SCIP_NODE ** node,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_TREE * tree,SCIP_Real nodeselprio,SCIP_Real estimate)984 SCIP_RETCODE SCIPnodeCreateChild(
985    SCIP_NODE**           node,               /**< pointer to node data structure */
986    BMS_BLKMEM*           blkmem,             /**< block memory */
987    SCIP_SET*             set,                /**< global SCIP settings */
988    SCIP_STAT*            stat,               /**< problem statistics */
989    SCIP_TREE*            tree,               /**< branch and bound tree */
990    SCIP_Real             nodeselprio,        /**< node selection priority of new node */
991    SCIP_Real             estimate            /**< estimate for (transformed) objective value of best feasible solution in subtree */
992    )
993 {
994    assert(node != NULL);
995    assert(blkmem != NULL);
996    assert(set != NULL);
997    assert(stat != NULL);
998    assert(tree != NULL);
999    assert(SCIPtreeIsPathComplete(tree));
1000    assert(tree->pathlen == 0 || tree->path != NULL);
1001    assert((tree->pathlen == 0) == (tree->focusnode == NULL));
1002    assert(tree->focusnode == NULL || tree->focusnode == tree->path[tree->pathlen-1]);
1003    assert(tree->focusnode == NULL || SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_FOCUSNODE);
1004 
1005    stat->ncreatednodes++;
1006    stat->ncreatednodesrun++;
1007 
1008    /* create the node data structure */
1009    SCIP_CALL( nodeCreate(node, blkmem, set) );
1010    (*node)->number = stat->ncreatednodesrun;
1011 
1012    /* mark node to be a child node */
1013    (*node)->nodetype = SCIP_NODETYPE_CHILD; /*lint !e641*/
1014    (*node)->data.child.arraypos = -1;
1015 
1016    /* make focus node the parent of the new child */
1017    SCIP_CALL( nodeAssignParent(*node, blkmem, set, tree, tree->focusnode, nodeselprio) );
1018 
1019    /* update the estimate of the child */
1020    SCIPnodeSetEstimate(*node, set, estimate);
1021 
1022    tree->lastbranchparentid = tree->focusnode == NULL ? -1L : SCIPnodeGetNumber(tree->focusnode);
1023 
1024    /* output node creation to visualization file */
1025    SCIP_CALL( SCIPvisualNewChild(stat->visual, set, stat, *node) );
1026 
1027    SCIPsetDebugMsg(set, "created child node #%" SCIP_LONGINT_FORMAT " at depth %u (prio: %g)\n", SCIPnodeGetNumber(*node), (*node)->depth, nodeselprio);
1028 
1029    return SCIP_OKAY;
1030 }
1031 
1032 /** query if focus node was already branched on */
SCIPtreeWasNodeLastBranchParent(SCIP_TREE * tree,SCIP_NODE * node)1033 SCIP_Bool SCIPtreeWasNodeLastBranchParent(
1034    SCIP_TREE*            tree,               /**< branch and bound tree */
1035    SCIP_NODE*            node                /**< tree node, or NULL to check focus node */
1036    )
1037 {
1038    node = node == NULL ? tree->focusnode : node;
1039    if( node != NULL && node->number == tree->lastbranchparentid )
1040       return TRUE;
1041 
1042    return FALSE;
1043 }
1044 
1045 /** frees node */
SCIPnodeFree(SCIP_NODE ** node,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue,SCIP_TREE * tree,SCIP_LP * lp)1046 SCIP_RETCODE SCIPnodeFree(
1047    SCIP_NODE**           node,               /**< node data */
1048    BMS_BLKMEM*           blkmem,             /**< block memory buffer */
1049    SCIP_SET*             set,                /**< global SCIP settings */
1050    SCIP_STAT*            stat,               /**< problem statistics */
1051    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
1052    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
1053    SCIP_TREE*            tree,               /**< branch and bound tree */
1054    SCIP_LP*              lp                  /**< current LP data */
1055    )
1056 {
1057    SCIP_Bool isroot;
1058 
1059    assert(node != NULL);
1060    assert(*node != NULL);
1061    assert(!(*node)->active);
1062    assert(blkmem != NULL);
1063    assert(tree != NULL);
1064 
1065    SCIPsetDebugMsg(set, "free node #%" SCIP_LONGINT_FORMAT " at depth %d of type %d\n", SCIPnodeGetNumber(*node), SCIPnodeGetDepth(*node), SCIPnodeGetType(*node));
1066 
1067    /* check lower bound w.r.t. debugging solution */
1068    SCIP_CALL( SCIPdebugCheckGlobalLowerbound(blkmem, set) );
1069 
1070    if( SCIPnodeGetType(*node) != SCIP_NODETYPE_PROBINGNODE )
1071    {
1072       SCIP_EVENT event;
1073 
1074       /* trigger a node deletion event */
1075       SCIP_CALL( SCIPeventChgType(&event, SCIP_EVENTTYPE_NODEDELETE) );
1076       SCIP_CALL( SCIPeventChgNode(&event, *node) );
1077       SCIP_CALL( SCIPeventProcess(&event, set, NULL, NULL, NULL, eventfilter) );
1078    }
1079 
1080    /* inform solution debugger, that the node has been freed */
1081    SCIP_CALL( SCIPdebugRemoveNode(blkmem, set, *node) );
1082 
1083    /* check, if the node to be freed is the root node */
1084    isroot = (SCIPnodeGetDepth(*node) == 0);
1085 
1086    /* free nodetype specific data, and release no longer needed LPI states */
1087    switch( SCIPnodeGetType(*node) )
1088    {
1089    case SCIP_NODETYPE_FOCUSNODE:
1090       assert(tree->focusnode == *node);
1091       assert(!SCIPtreeProbing(tree));
1092       SCIPerrorMessage("cannot free focus node - has to be converted into a dead end first\n");
1093       return SCIP_INVALIDDATA;
1094    case SCIP_NODETYPE_PROBINGNODE:
1095       assert(SCIPtreeProbing(tree));
1096       assert(SCIPnodeGetDepth(tree->probingroot) <= SCIPnodeGetDepth(*node));
1097       assert(SCIPnodeGetDepth(*node) > 0);
1098       SCIP_CALL( probingnodeFree(&((*node)->data.probingnode), blkmem, lp) );
1099       break;
1100    case SCIP_NODETYPE_SIBLING:
1101       assert((*node)->data.sibling.arraypos >= 0);
1102       assert((*node)->data.sibling.arraypos < tree->nsiblings);
1103       assert(tree->siblings[(*node)->data.sibling.arraypos] == *node);
1104       if( tree->focuslpstatefork != NULL )
1105       {
1106          assert(SCIPnodeGetType(tree->focuslpstatefork) == SCIP_NODETYPE_FORK
1107             || SCIPnodeGetType(tree->focuslpstatefork) == SCIP_NODETYPE_SUBROOT);
1108          SCIP_CALL( SCIPnodeReleaseLPIState(tree->focuslpstatefork, blkmem, lp) );
1109       }
1110       treeRemoveSibling(tree, *node);
1111       break;
1112    case SCIP_NODETYPE_CHILD:
1113       assert((*node)->data.child.arraypos >= 0);
1114       assert((*node)->data.child.arraypos < tree->nchildren);
1115       assert(tree->children[(*node)->data.child.arraypos] == *node);
1116       /* The children capture the LPI state at the moment, where the focus node is
1117        * converted into a junction, pseudofork, fork, or subroot, and a new node is focused.
1118        * At the same time, they become siblings or leaves, such that freeing a child
1119        * of the focus node doesn't require to release the LPI state;
1120        * we don't need to call treeRemoveChild(), because this is done in nodeReleaseParent()
1121        */
1122       break;
1123    case SCIP_NODETYPE_LEAF:
1124       if( (*node)->data.leaf.lpstatefork != NULL )
1125       {
1126          SCIP_CALL( SCIPnodeReleaseLPIState((*node)->data.leaf.lpstatefork, blkmem, lp) );
1127       }
1128       break;
1129    case SCIP_NODETYPE_DEADEND:
1130    case SCIP_NODETYPE_JUNCTION:
1131       break;
1132    case SCIP_NODETYPE_PSEUDOFORK:
1133       SCIP_CALL( pseudoforkFree(&((*node)->data.pseudofork), blkmem, set, lp) );
1134       break;
1135    case SCIP_NODETYPE_FORK:
1136 
1137       /* release special root LPI state capture which is used to keep the root LPI state over the whole solving
1138        * process
1139        */
1140       if( isroot )
1141       {
1142          SCIP_CALL( SCIPnodeReleaseLPIState(*node, blkmem, lp) );
1143       }
1144       SCIP_CALL( forkFree(&((*node)->data.fork), blkmem, set, lp) );
1145       break;
1146    case SCIP_NODETYPE_SUBROOT:
1147       SCIP_CALL( subrootFree(&((*node)->data.subroot), blkmem, set, lp) );
1148       break;
1149    case SCIP_NODETYPE_REFOCUSNODE:
1150       SCIPerrorMessage("cannot free node as long it is refocused\n");
1151       return SCIP_INVALIDDATA;
1152    default:
1153       SCIPerrorMessage("unknown node type %d\n", SCIPnodeGetType(*node));
1154       return SCIP_INVALIDDATA;
1155    }
1156 
1157    /* free common data */
1158    SCIP_CALL( SCIPconssetchgFree(&(*node)->conssetchg, blkmem, set) );
1159    SCIP_CALL( SCIPdomchgFree(&(*node)->domchg, blkmem, set, eventqueue, lp) );
1160    SCIP_CALL( nodeReleaseParent(*node, blkmem, set, stat, eventfilter, eventqueue, tree, lp) );
1161 
1162    /* check, if the node is the current probing root */
1163    if( *node == tree->probingroot )
1164    {
1165       assert(SCIPnodeGetType(*node) == SCIP_NODETYPE_PROBINGNODE);
1166       tree->probingroot = NULL;
1167    }
1168 
1169    BMSfreeBlockMemory(blkmem, node);
1170 
1171    /* delete the tree's root node pointer, if the freed node was the root */
1172    if( isroot )
1173       tree->root = NULL;
1174 
1175    return SCIP_OKAY;
1176 }
1177 
1178 /** cuts off node and whole sub tree from branch and bound tree */
SCIPnodeCutoff(SCIP_NODE * node,SCIP_SET * set,SCIP_STAT * stat,SCIP_TREE * tree,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_REOPT * reopt,SCIP_LP * lp,BMS_BLKMEM * blkmem)1179 SCIP_RETCODE SCIPnodeCutoff(
1180    SCIP_NODE*            node,               /**< node that should be cut off */
1181    SCIP_SET*             set,                /**< global SCIP settings */
1182    SCIP_STAT*            stat,               /**< problem statistics */
1183    SCIP_TREE*            tree,               /**< branch and bound tree */
1184    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
1185    SCIP_PROB*            origprob,           /**< original problem */
1186    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
1187    SCIP_LP*              lp,                 /**< current LP */
1188    BMS_BLKMEM*           blkmem              /**< block memory */
1189    )
1190 {
1191    SCIP_Real oldbound;
1192 
1193    assert(node != NULL);
1194    assert(set != NULL);
1195    assert(stat != NULL);
1196    assert(tree != NULL);
1197 
1198    if( set->reopt_enable )
1199    {
1200       assert(reopt != NULL);
1201       /* check if the node should be stored for reoptimization */
1202       SCIP_CALL( SCIPreoptCheckCutoff(reopt, set, blkmem, node, SCIP_EVENTTYPE_NODEINFEASIBLE, lp, SCIPlpGetSolstat(lp),
1203             tree->root == node, tree->focusnode == node, node->lowerbound, tree->effectiverootdepth) );
1204    }
1205 
1206    oldbound = node->lowerbound;
1207    node->cutoff = TRUE;
1208    node->lowerbound = SCIPsetInfinity(set);
1209    node->estimate = SCIPsetInfinity(set);
1210    if( node->active )
1211       tree->cutoffdepth = MIN(tree->cutoffdepth, (int)node->depth);
1212 
1213    /* update primal integral */
1214    if( node->depth == 0 )
1215    {
1216       stat->rootlowerbound = SCIPsetInfinity(set);
1217       if( set->misc_calcintegral )
1218          SCIPstatUpdatePrimalDualIntegrals(stat, set, transprob, origprob, SCIPsetInfinity(set), SCIPsetInfinity(set));
1219    }
1220    else if( set->misc_calcintegral && SCIPsetIsEQ(set, oldbound, stat->lastlowerbound) )
1221    {
1222       SCIP_Real lowerbound;
1223       lowerbound = SCIPtreeGetLowerbound(tree, set);
1224 
1225       /* updating the primal integral is only necessary if dual bound has increased since last evaluation */
1226       if( lowerbound > stat->lastlowerbound )
1227          SCIPstatUpdatePrimalDualIntegrals(stat, set, transprob, origprob, SCIPsetInfinity(set), SCIPsetInfinity(set));
1228    }
1229 
1230    SCIPvisualCutoffNode(stat->visual, set, stat, node, TRUE);
1231 
1232    SCIPsetDebugMsg(set, "cutting off %s node #%" SCIP_LONGINT_FORMAT " at depth %d (cutoffdepth: %d)\n",
1233       node->active ? "active" : "inactive", SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), tree->cutoffdepth);
1234 
1235    return SCIP_OKAY;
1236 }
1237 
1238 /** marks node, that propagation should be applied again the next time, a node of its subtree is focused */
SCIPnodePropagateAgain(SCIP_NODE * node,SCIP_SET * set,SCIP_STAT * stat,SCIP_TREE * tree)1239 void SCIPnodePropagateAgain(
1240    SCIP_NODE*            node,               /**< node that should be propagated again */
1241    SCIP_SET*             set,                /**< global SCIP settings */
1242    SCIP_STAT*            stat,               /**< problem statistics */
1243    SCIP_TREE*            tree                /**< branch and bound tree */
1244    )
1245 {
1246    assert(node != NULL);
1247    assert(set != NULL);
1248    assert(stat != NULL);
1249    assert(tree != NULL);
1250 
1251    if( !node->reprop )
1252    {
1253       node->reprop = TRUE;
1254       if( node->active )
1255          tree->repropdepth = MIN(tree->repropdepth, (int)node->depth);
1256 
1257       SCIPvisualMarkedRepropagateNode(stat->visual, stat, node);
1258 
1259       SCIPsetDebugMsg(set, "marked %s node #%" SCIP_LONGINT_FORMAT " at depth %d to be propagated again (repropdepth: %d)\n",
1260          node->active ? "active" : "inactive", SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), tree->repropdepth);
1261    }
1262 }
1263 
1264 /** marks node, that it is completely propagated in the current repropagation subtree level */
SCIPnodeMarkPropagated(SCIP_NODE * node,SCIP_TREE * tree)1265 void SCIPnodeMarkPropagated(
1266    SCIP_NODE*            node,               /**< node that should be marked to be propagated */
1267    SCIP_TREE*            tree                /**< branch and bound tree */
1268    )
1269 {
1270    assert(node != NULL);
1271    assert(tree != NULL);
1272 
1273    if( node->parent != NULL )
1274       node->repropsubtreemark = node->parent->repropsubtreemark; /*lint !e732*/
1275    node->reprop = FALSE;
1276 
1277    /* if the node was the highest repropagation node in the path, update the repropdepth in the tree data */
1278    if( node->active && node->depth == tree->repropdepth )
1279    {
1280       do
1281       {
1282          assert(tree->repropdepth < tree->pathlen);
1283          assert(tree->path[tree->repropdepth]->active);
1284          assert(!tree->path[tree->repropdepth]->reprop);
1285          tree->repropdepth++;
1286       }
1287       while( tree->repropdepth < tree->pathlen && !tree->path[tree->repropdepth]->reprop );
1288       if( tree->repropdepth == tree->pathlen )
1289          tree->repropdepth = INT_MAX;
1290    }
1291 }
1292 
1293 /** moves the subtree repropagation counter to the next value */
1294 static
treeNextRepropsubtreecount(SCIP_TREE * tree)1295 void treeNextRepropsubtreecount(
1296    SCIP_TREE*            tree                /**< branch and bound tree */
1297    )
1298 {
1299    assert(tree != NULL);
1300 
1301    tree->repropsubtreecount++;
1302    tree->repropsubtreecount %= (MAXREPROPMARK+1);
1303 }
1304 
1305 /** applies propagation on the node, that was marked to be propagated again */
1306 static
nodeRepropagate(SCIP_NODE * node,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_PRIMAL * primal,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_CONFLICT * conflict,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,SCIP_Bool * cutoff)1307 SCIP_RETCODE nodeRepropagate(
1308    SCIP_NODE*            node,               /**< node to apply propagation on */
1309    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
1310    SCIP_SET*             set,                /**< global SCIP settings */
1311    SCIP_STAT*            stat,               /**< dynamic problem statistics */
1312    SCIP_PROB*            transprob,          /**< transformed problem */
1313    SCIP_PROB*            origprob,           /**< original problem */
1314    SCIP_PRIMAL*          primal,             /**< primal data */
1315    SCIP_TREE*            tree,               /**< branch and bound tree */
1316    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
1317    SCIP_LP*              lp,                 /**< current LP data */
1318    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
1319    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
1320    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
1321    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
1322    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
1323    SCIP_Bool*            cutoff              /**< pointer to store whether the node can be cut off */
1324    )
1325 {
1326    SCIP_NODETYPE oldtype;
1327    SCIP_NODE* oldfocusnode;
1328    SCIP_NODE* oldfocuslpfork;
1329    SCIP_NODE* oldfocuslpstatefork;
1330    SCIP_NODE* oldfocussubroot;
1331    SCIP_Longint oldfocuslpstateforklpcount;
1332    int oldnchildren;
1333    int oldnsiblings;
1334    SCIP_Bool oldfocusnodehaslp;
1335    SCIP_Longint oldnboundchgs;
1336    SCIP_Bool initialreprop;
1337    SCIP_Bool clockisrunning;
1338 
1339    assert(node != NULL);
1340    assert((SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_FOCUSNODE
1341       || (SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_JUNCTION
1342       || (SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_PSEUDOFORK
1343       || (SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_FORK
1344       || (SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_SUBROOT);
1345    assert(node->active);
1346    assert(node->reprop || node->repropsubtreemark != node->parent->repropsubtreemark);
1347    assert(stat != NULL);
1348    assert(tree != NULL);
1349    assert(SCIPeventqueueIsDelayed(eventqueue));
1350    assert(cutoff != NULL);
1351 
1352    SCIPsetDebugMsg(set, "propagating again node #%" SCIP_LONGINT_FORMAT " at depth %d\n", SCIPnodeGetNumber(node), SCIPnodeGetDepth(node));
1353    initialreprop = node->reprop;
1354 
1355    SCIPvisualRepropagatedNode(stat->visual, stat, node);
1356 
1357    /* process the delayed events in order to flush the problem changes */
1358    SCIP_CALL( SCIPeventqueueProcess(eventqueue, blkmem, set, primal, lp, branchcand, eventfilter) );
1359 
1360    /* stop node activation timer */
1361    clockisrunning = SCIPclockIsRunning(stat->nodeactivationtime);
1362    if( clockisrunning )
1363       SCIPclockStop(stat->nodeactivationtime, set);
1364 
1365    /* mark the node refocused and temporarily install it as focus node */
1366    oldtype = (SCIP_NODETYPE)node->nodetype;
1367    oldfocusnode = tree->focusnode;
1368    oldfocuslpfork = tree->focuslpfork;
1369    oldfocuslpstatefork = tree->focuslpstatefork;
1370    oldfocussubroot = tree->focussubroot;
1371    oldfocuslpstateforklpcount = tree->focuslpstateforklpcount;
1372    oldnchildren = tree->nchildren;
1373    oldnsiblings = tree->nsiblings;
1374    oldfocusnodehaslp = tree->focusnodehaslp;
1375    node->nodetype = SCIP_NODETYPE_REFOCUSNODE; /*lint !e641*/
1376    tree->focusnode = node;
1377    tree->focuslpfork = NULL;
1378    tree->focuslpstatefork = NULL;
1379    tree->focussubroot = NULL;
1380    tree->focuslpstateforklpcount = -1;
1381    tree->nchildren = 0;
1382    tree->nsiblings = 0;
1383    tree->focusnodehaslp = FALSE;
1384 
1385    /* propagate the domains again */
1386    oldnboundchgs = stat->nboundchgs;
1387    SCIP_CALL( SCIPpropagateDomains(blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
1388          eventqueue, conflict, cliquetable, SCIPnodeGetDepth(node), 0, SCIP_PROPTIMING_ALWAYS, cutoff) );
1389    assert(!node->reprop || *cutoff);
1390    assert(node->parent == NULL || node->repropsubtreemark == node->parent->repropsubtreemark);
1391    assert((SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_REFOCUSNODE);
1392    assert(tree->focusnode == node);
1393    assert(tree->focuslpfork == NULL);
1394    assert(tree->focuslpstatefork == NULL);
1395    assert(tree->focussubroot == NULL);
1396    assert(tree->focuslpstateforklpcount == -1);
1397    assert(tree->nchildren == 0);
1398    assert(tree->nsiblings == 0);
1399    assert(tree->focusnodehaslp == FALSE);
1400    assert(stat->nboundchgs >= oldnboundchgs);
1401    stat->nreprops++;
1402    stat->nrepropboundchgs += stat->nboundchgs - oldnboundchgs;
1403    if( *cutoff )
1404       stat->nrepropcutoffs++;
1405 
1406    SCIPsetDebugMsg(set, "repropagation %" SCIP_LONGINT_FORMAT " at depth %u changed %" SCIP_LONGINT_FORMAT " bounds (total reprop bound changes: %" SCIP_LONGINT_FORMAT "), cutoff: %u\n",
1407       stat->nreprops, node->depth, stat->nboundchgs - oldnboundchgs, stat->nrepropboundchgs, *cutoff);
1408 
1409    /* if a propagation marked with the reprop flag was successful, we want to repropagate the whole subtree */
1410    /**@todo because repropsubtree is only a bit flag, we cannot mark a whole subtree a second time for
1411     *       repropagation; use a (small) part of the node's bits to be able to store larger numbers,
1412     *       and update tree->repropsubtreelevel with this number
1413     */
1414    if( initialreprop && !(*cutoff) && stat->nboundchgs > oldnboundchgs )
1415    {
1416       treeNextRepropsubtreecount(tree);
1417       node->repropsubtreemark = tree->repropsubtreecount; /*lint !e732*/
1418       SCIPsetDebugMsg(set, "initial repropagation at depth %u changed %" SCIP_LONGINT_FORMAT " bounds -> repropagating subtree (new mark: %d)\n",
1419          node->depth, stat->nboundchgs - oldnboundchgs, tree->repropsubtreecount);
1420       assert((int)(node->repropsubtreemark) == tree->repropsubtreecount); /* bitfield must be large enough */
1421    }
1422 
1423    /* reset the node's type and reinstall the old focus node */
1424    node->nodetype = oldtype; /*lint !e641*/
1425    tree->focusnode = oldfocusnode;
1426    tree->focuslpfork = oldfocuslpfork;
1427    tree->focuslpstatefork = oldfocuslpstatefork;
1428    tree->focussubroot = oldfocussubroot;
1429    tree->focuslpstateforklpcount = oldfocuslpstateforklpcount;
1430    tree->nchildren = oldnchildren;
1431    tree->nsiblings = oldnsiblings;
1432    tree->focusnodehaslp = oldfocusnodehaslp;
1433 
1434    /* make the domain change data static again to save memory */
1435    if( (SCIP_NODETYPE)node->nodetype != SCIP_NODETYPE_FOCUSNODE )
1436    {
1437       SCIP_CALL( SCIPdomchgMakeStatic(&node->domchg, blkmem, set, eventqueue, lp) );
1438    }
1439 
1440    /* start node activation timer again */
1441    if( clockisrunning )
1442       SCIPclockStart(stat->nodeactivationtime, set);
1443 
1444    /* delay events in path switching */
1445    SCIP_CALL( SCIPeventqueueDelay(eventqueue) );
1446 
1447    /* mark the node to be cut off if a cutoff was detected */
1448    if( *cutoff )
1449    {
1450       SCIP_CALL( SCIPnodeCutoff(node, set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
1451    }
1452 
1453    return SCIP_OKAY;
1454 }
1455 
1456 /** informs node, that it is now on the active path and applies any domain and constraint set changes */
1457 static
nodeActivate(SCIP_NODE * node,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_PRIMAL * primal,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_CONFLICT * conflict,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,SCIP_Bool * cutoff)1458 SCIP_RETCODE nodeActivate(
1459    SCIP_NODE*            node,               /**< node to activate */
1460    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
1461    SCIP_SET*             set,                /**< global SCIP settings */
1462    SCIP_STAT*            stat,               /**< problem statistics */
1463    SCIP_PROB*            transprob,          /**< transformed problem */
1464    SCIP_PROB*            origprob,           /**< original problem */
1465    SCIP_PRIMAL*          primal,             /**< primal data */
1466    SCIP_TREE*            tree,               /**< branch and bound tree */
1467    SCIP_REOPT*           reopt,              /**< reotimization data structure */
1468    SCIP_LP*              lp,                 /**< current LP data */
1469    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
1470    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
1471    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
1472    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
1473    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
1474    SCIP_Bool*            cutoff              /**< pointer to store whether the node can be cut off */
1475    )
1476 {
1477    assert(node != NULL);
1478    assert(!node->active);
1479    assert(stat != NULL);
1480    assert(tree != NULL);
1481    assert(!SCIPtreeProbing(tree));
1482    assert(cutoff != NULL);
1483 
1484    SCIPsetDebugMsg(set, "activate node #%" SCIP_LONGINT_FORMAT " at depth %d of type %d (reprop subtree mark: %u)\n",
1485       SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), SCIPnodeGetType(node), node->repropsubtreemark);
1486 
1487    /* apply domain and constraint set changes */
1488    SCIP_CALL( SCIPconssetchgApply(node->conssetchg, blkmem, set, stat, (int) node->depth,
1489          (SCIPnodeGetType(node) == SCIP_NODETYPE_FOCUSNODE)) );
1490    SCIP_CALL( SCIPdomchgApply(node->domchg, blkmem, set, stat, lp, branchcand, eventqueue, (int) node->depth, cutoff) );
1491 
1492    /* mark node active */
1493    node->active = TRUE;
1494    stat->nactivatednodes++;
1495 
1496    /* check if the domain change produced a cutoff */
1497    if( *cutoff )
1498    {
1499       /* try to repropagate the node to see, if the propagation also leads to a conflict and a conflict constraint
1500        * could be generated; if propagation conflict analysis is turned off, repropagating the node makes no
1501        * sense, since it is already cut off
1502        */
1503       node->reprop = set->conf_enable && set->conf_useprop;
1504 
1505       /* mark the node to be cut off */
1506       SCIP_CALL( SCIPnodeCutoff(node, set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
1507    }
1508 
1509    /* propagate node again, if the reprop flag is set; in the new focus node, no repropagation is necessary, because
1510     * the focus node is propagated anyways
1511     */
1512    if( SCIPnodeGetType(node) != SCIP_NODETYPE_FOCUSNODE
1513       && (node->reprop || (node->parent != NULL && node->repropsubtreemark != node->parent->repropsubtreemark)) )
1514    {
1515       SCIP_Bool propcutoff;
1516 
1517       SCIP_CALL( nodeRepropagate(node, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, conflict,
1518             eventfilter, eventqueue, cliquetable, &propcutoff) );
1519       *cutoff = *cutoff || propcutoff;
1520    }
1521 
1522    return SCIP_OKAY;
1523 }
1524 
1525 /** informs node, that it is no longer on the active path and undoes any domain and constraint set changes */
1526 static
nodeDeactivate(SCIP_NODE * node,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_TREE * tree,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue)1527 SCIP_RETCODE nodeDeactivate(
1528    SCIP_NODE*            node,               /**< node to deactivate */
1529    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
1530    SCIP_SET*             set,                /**< global SCIP settings */
1531    SCIP_STAT*            stat,               /**< problem statistics */
1532    SCIP_TREE*            tree,               /**< branch and bound tree */
1533    SCIP_LP*              lp,                 /**< current LP data */
1534    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
1535    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
1536    SCIP_EVENTQUEUE*      eventqueue          /**< event queue */
1537    )
1538 {
1539    SCIP_Bool freeNode;
1540 
1541    assert(node != NULL);
1542    assert(node->active);
1543    assert(tree != NULL);
1544    assert(SCIPnodeGetType(node) != SCIP_NODETYPE_FOCUSNODE);
1545 
1546    SCIPsetDebugMsg(set, "deactivate node #%" SCIP_LONGINT_FORMAT " at depth %d of type %d (reprop subtree mark: %u)\n",
1547       SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), SCIPnodeGetType(node), node->repropsubtreemark);
1548 
1549    /* undo domain and constraint set changes */
1550    SCIP_CALL( SCIPdomchgUndo(node->domchg, blkmem, set, stat, lp, branchcand, eventqueue) );
1551    SCIP_CALL( SCIPconssetchgUndo(node->conssetchg, blkmem, set, stat) );
1552 
1553    /* mark node inactive */
1554    node->active = FALSE;
1555 
1556    /* count number of deactivated nodes (ignoring probing switches) */
1557    if( !SCIPtreeProbing(tree) )
1558       stat->ndeactivatednodes++;
1559 
1560    /* free node if it is a dead-end node, i.e., has no children */
1561    switch( SCIPnodeGetType(node) )
1562    {
1563    case SCIP_NODETYPE_FOCUSNODE:
1564    case SCIP_NODETYPE_PROBINGNODE:
1565    case SCIP_NODETYPE_SIBLING:
1566    case SCIP_NODETYPE_CHILD:
1567    case SCIP_NODETYPE_LEAF:
1568    case SCIP_NODETYPE_DEADEND:
1569    case SCIP_NODETYPE_REFOCUSNODE:
1570       freeNode = FALSE;
1571       break;
1572    case SCIP_NODETYPE_JUNCTION:
1573       freeNode = (node->data.junction.nchildren == 0);
1574       break;
1575    case SCIP_NODETYPE_PSEUDOFORK:
1576       freeNode = (node->data.pseudofork->nchildren == 0);
1577       break;
1578    case SCIP_NODETYPE_FORK:
1579       freeNode = (node->data.fork->nchildren == 0);
1580       break;
1581    case SCIP_NODETYPE_SUBROOT:
1582       freeNode = (node->data.subroot->nchildren == 0);
1583       break;
1584    default:
1585       SCIPerrorMessage("unknown node type %d\n", SCIPnodeGetType(node));
1586       return SCIP_INVALIDDATA;
1587    }
1588    if( freeNode )
1589    {
1590       SCIP_CALL( SCIPnodeFree(&node, blkmem, set, stat, eventfilter, eventqueue, tree, lp) );
1591    }
1592 
1593    return SCIP_OKAY;
1594 }
1595 
1596 /** adds constraint locally to the node and captures it; activates constraint, if node is active;
1597  *  if a local constraint is added to the root node, it is automatically upgraded into a global constraint
1598  */
SCIPnodeAddCons(SCIP_NODE * node,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_TREE * tree,SCIP_CONS * cons)1599 SCIP_RETCODE SCIPnodeAddCons(
1600    SCIP_NODE*            node,               /**< node to add constraint to */
1601    BMS_BLKMEM*           blkmem,             /**< block memory */
1602    SCIP_SET*             set,                /**< global SCIP settings */
1603    SCIP_STAT*            stat,               /**< problem statistics */
1604    SCIP_TREE*            tree,               /**< branch and bound tree */
1605    SCIP_CONS*            cons                /**< constraint to add */
1606    )
1607 {
1608    assert(node != NULL);
1609    assert(cons != NULL);
1610    assert(cons->validdepth <= SCIPnodeGetDepth(node));
1611    assert(tree != NULL);
1612    assert(tree->effectiverootdepth >= 0);
1613    assert(tree->root != NULL);
1614    assert(SCIPconsIsGlobal(cons) || SCIPnodeGetDepth(node) > tree->effectiverootdepth);
1615 
1616 #ifndef NDEBUG
1617    /* check if we add this constraint to the same scip, where we create the constraint */
1618    if( cons->scip != set->scip )
1619    {
1620       SCIPerrorMessage("try to add a constraint of another scip instance\n");
1621       return SCIP_INVALIDDATA;
1622    }
1623 #endif
1624 
1625    /* add constraint addition to the node's constraint set change data, and activate constraint if node is active */
1626    SCIP_CALL( SCIPconssetchgAddAddedCons(&node->conssetchg, blkmem, set, stat, cons, (int) node->depth,
1627          (SCIPnodeGetType(node) == SCIP_NODETYPE_FOCUSNODE), node->active) );
1628    assert(node->conssetchg != NULL);
1629    assert(node->conssetchg->addedconss != NULL);
1630    assert(!node->active || SCIPconsIsActive(cons));
1631 
1632    /* if the constraint is added to an active node which is not a probing node, increment the corresponding counter */
1633    if( node->active && SCIPnodeGetType(node) != SCIP_NODETYPE_PROBINGNODE )
1634       stat->nactiveconssadded++;
1635 
1636    return SCIP_OKAY;
1637 }
1638 
1639 /** locally deletes constraint at the given node by disabling its separation, enforcing, and propagation capabilities
1640  *  at the node; captures constraint; disables constraint, if node is active
1641  */
SCIPnodeDelCons(SCIP_NODE * node,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_TREE * tree,SCIP_CONS * cons)1642 SCIP_RETCODE SCIPnodeDelCons(
1643    SCIP_NODE*            node,               /**< node to add constraint to */
1644    BMS_BLKMEM*           blkmem,             /**< block memory */
1645    SCIP_SET*             set,                /**< global SCIP settings */
1646    SCIP_STAT*            stat,               /**< problem statistics */
1647    SCIP_TREE*            tree,               /**< branch and bound tree */
1648    SCIP_CONS*            cons                /**< constraint to locally delete */
1649    )
1650 {
1651    assert(node != NULL);
1652    assert(tree != NULL);
1653    assert(cons != NULL);
1654 
1655    SCIPsetDebugMsg(set, "disabling constraint <%s> at node at depth %u\n", cons->name, node->depth);
1656 
1657    /* add constraint disabling to the node's constraint set change data */
1658    SCIP_CALL( SCIPconssetchgAddDisabledCons(&node->conssetchg, blkmem, set, cons) );
1659    assert(node->conssetchg != NULL);
1660    assert(node->conssetchg->disabledconss != NULL);
1661 
1662    /* disable constraint, if node is active */
1663    if( node->active && cons->enabled && !cons->updatedisable )
1664    {
1665       SCIP_CALL( SCIPconsDisable(cons, set, stat) );
1666    }
1667 
1668    return SCIP_OKAY;
1669 }
1670 
1671 /** returns all constraints added to a given node */
SCIPnodeGetAddedConss(SCIP_NODE * node,SCIP_CONS ** addedconss,int * naddedconss,int addedconsssize)1672 void SCIPnodeGetAddedConss(
1673    SCIP_NODE*            node,               /**< node */
1674    SCIP_CONS**           addedconss,         /**< array to store the constraints */
1675    int*                  naddedconss,        /**< number of added constraints */
1676    int                   addedconsssize      /**< size of the constraint array */
1677    )
1678 {
1679    int cons;
1680 
1681    assert(node != NULL );
1682    assert(node->conssetchg != NULL);
1683    assert(node->conssetchg->addedconss != NULL);
1684    assert(node->conssetchg->naddedconss >= 1);
1685 
1686    *naddedconss = node->conssetchg->naddedconss;
1687 
1688    /* check the size and return if the array is not large enough */
1689    if( addedconsssize < *naddedconss )
1690       return;
1691 
1692    /* fill the array */
1693    for( cons = 0; cons < *naddedconss; cons++ )
1694    {
1695       addedconss[cons] = node->conssetchg->addedconss[cons];
1696    }
1697 
1698    return;
1699 }
1700 
1701 /** returns the number of added constraints to the given node */
SCIPnodeGetNAddedConss(SCIP_NODE * node)1702 int SCIPnodeGetNAddedConss(
1703    SCIP_NODE*            node                /**< node */
1704    )
1705 {
1706    assert(node != NULL);
1707 
1708    if( node->conssetchg == NULL )
1709       return 0;
1710    else
1711       return node->conssetchg->naddedconss;
1712 }
1713 
1714 /** adds the given bound change to the list of pending bound changes */
1715 static
treeAddPendingBdchg(SCIP_TREE * tree,SCIP_SET * set,SCIP_NODE * node,SCIP_VAR * var,SCIP_Real newbound,SCIP_BOUNDTYPE boundtype,SCIP_CONS * infercons,SCIP_PROP * inferprop,int inferinfo,SCIP_Bool probingchange)1716 SCIP_RETCODE treeAddPendingBdchg(
1717    SCIP_TREE*            tree,               /**< branch and bound tree */
1718    SCIP_SET*             set,                /**< global SCIP settings */
1719    SCIP_NODE*            node,               /**< node to add bound change to */
1720    SCIP_VAR*             var,                /**< variable to change the bounds for */
1721    SCIP_Real             newbound,           /**< new value for bound */
1722    SCIP_BOUNDTYPE        boundtype,          /**< type of bound: lower or upper bound */
1723    SCIP_CONS*            infercons,          /**< constraint that deduced the bound change, or NULL */
1724    SCIP_PROP*            inferprop,          /**< propagator that deduced the bound change, or NULL */
1725    int                   inferinfo,          /**< user information for inference to help resolving the conflict */
1726    SCIP_Bool             probingchange       /**< is the bound change a temporary setting due to probing? */
1727    )
1728 {
1729    assert(tree != NULL);
1730 
1731    /* make sure that enough memory is allocated for the pendingbdchgs array */
1732    SCIP_CALL( treeEnsurePendingbdchgsMem(tree, set, tree->npendingbdchgs+1) );
1733 
1734    /* capture the variable */
1735    SCIPvarCapture(var);
1736 
1737    /* add the bound change to the pending list */
1738    tree->pendingbdchgs[tree->npendingbdchgs].node = node;
1739    tree->pendingbdchgs[tree->npendingbdchgs].var = var;
1740    tree->pendingbdchgs[tree->npendingbdchgs].newbound = newbound;
1741    tree->pendingbdchgs[tree->npendingbdchgs].boundtype = boundtype;
1742    tree->pendingbdchgs[tree->npendingbdchgs].infercons = infercons;
1743    tree->pendingbdchgs[tree->npendingbdchgs].inferprop = inferprop;
1744    tree->pendingbdchgs[tree->npendingbdchgs].inferinfo = inferinfo;
1745    tree->pendingbdchgs[tree->npendingbdchgs].probingchange = probingchange;
1746    tree->npendingbdchgs++;
1747 
1748    /* check global pending boundchanges against debug solution */
1749    if( node->depth == 0 )
1750    {
1751 #ifndef NDEBUG
1752       SCIP_Real bound = newbound;
1753 
1754       /* get bound adjusted for integrality(, this should already be done) */
1755       SCIPvarAdjustBd(var, set, boundtype, &bound);
1756 
1757       if( boundtype == SCIP_BOUNDTYPE_LOWER )
1758       {
1759 	 /* check that the bound is feasible */
1760 	 if( bound > SCIPvarGetUbGlobal(var) )
1761 	 {
1762 	    /* due to numerics we only want to be feasible in feasibility tolerance */
1763 	    assert(SCIPsetIsFeasLE(set, bound, SCIPvarGetUbGlobal(var)));
1764 	    bound = SCIPvarGetUbGlobal(var);
1765 	 }
1766       }
1767       else
1768       {
1769 	 assert(boundtype == SCIP_BOUNDTYPE_UPPER);
1770 
1771 	 /* check that the bound is feasible */
1772 	 if( bound < SCIPvarGetLbGlobal(var) )
1773 	 {
1774 	    /* due to numerics we only want to be feasible in feasibility tolerance */
1775 	    assert(SCIPsetIsFeasGE(set, bound, SCIPvarGetLbGlobal(var)));
1776 	    bound = SCIPvarGetLbGlobal(var);
1777 	 }
1778       }
1779       /* check that the given bound was already adjusted for integrality */
1780       assert(SCIPsetIsEQ(set, newbound, bound));
1781 #endif
1782       if( boundtype == SCIP_BOUNDTYPE_LOWER )
1783       {
1784 	 /* check bound on debugging solution */
1785 	 SCIP_CALL( SCIPdebugCheckLbGlobal(set->scip, var, newbound) ); /*lint !e506 !e774*/
1786       }
1787       else
1788       {
1789 	 assert(boundtype == SCIP_BOUNDTYPE_UPPER);
1790 
1791 	 /* check bound on debugging solution */
1792 	 SCIP_CALL( SCIPdebugCheckUbGlobal(set->scip, var, newbound) ); /*lint !e506 !e774*/
1793       }
1794    }
1795 
1796    return SCIP_OKAY;
1797 }
1798 
1799 /** adds bound change with inference information to focus node, child of focus node, or probing node;
1800  *  if possible, adjusts bound to integral value;
1801  *  at most one of infercons and inferprop may be non-NULL
1802  */
SCIPnodeAddBoundinfer(SCIP_NODE * node,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,SCIP_VAR * var,SCIP_Real newbound,SCIP_BOUNDTYPE boundtype,SCIP_CONS * infercons,SCIP_PROP * inferprop,int inferinfo,SCIP_Bool probingchange)1803 SCIP_RETCODE SCIPnodeAddBoundinfer(
1804    SCIP_NODE*            node,               /**< node to add bound change to */
1805    BMS_BLKMEM*           blkmem,             /**< block memory */
1806    SCIP_SET*             set,                /**< global SCIP settings */
1807    SCIP_STAT*            stat,               /**< problem statistics */
1808    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
1809    SCIP_PROB*            origprob,           /**< original problem */
1810    SCIP_TREE*            tree,               /**< branch and bound tree */
1811    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
1812    SCIP_LP*              lp,                 /**< current LP data */
1813    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
1814    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
1815    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
1816    SCIP_VAR*             var,                /**< variable to change the bounds for */
1817    SCIP_Real             newbound,           /**< new value for bound */
1818    SCIP_BOUNDTYPE        boundtype,          /**< type of bound: lower or upper bound */
1819    SCIP_CONS*            infercons,          /**< constraint that deduced the bound change, or NULL */
1820    SCIP_PROP*            inferprop,          /**< propagator that deduced the bound change, or NULL */
1821    int                   inferinfo,          /**< user information for inference to help resolving the conflict */
1822    SCIP_Bool             probingchange       /**< is the bound change a temporary setting due to probing? */
1823    )
1824 {
1825    SCIP_VAR* infervar;
1826    SCIP_BOUNDTYPE inferboundtype;
1827    SCIP_Real oldlb;
1828    SCIP_Real oldub;
1829    SCIP_Real oldbound;
1830    SCIP_Bool useglobal;
1831 
1832    useglobal = (int) node->depth <= tree->effectiverootdepth;
1833    if( useglobal )
1834    {
1835       oldlb = SCIPvarGetLbGlobal(var);
1836       oldub = SCIPvarGetUbGlobal(var);
1837    }
1838    else
1839    {
1840       oldlb = SCIPvarGetLbLocal(var);
1841       oldub = SCIPvarGetUbLocal(var);
1842    }
1843 
1844    assert(node != NULL);
1845    assert((SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_FOCUSNODE
1846       || (SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_PROBINGNODE
1847       || (SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_CHILD
1848       || (SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_REFOCUSNODE
1849       || node->depth == 0);
1850    assert(set != NULL);
1851    assert(tree != NULL);
1852    assert(tree->effectiverootdepth >= 0);
1853    assert(tree->root != NULL);
1854    assert(var != NULL);
1855    assert(node->active || (infercons == NULL && inferprop == NULL));
1856    assert((SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_PROBINGNODE || !probingchange);
1857    assert((boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsGT(set, newbound, oldlb))
1858          || (boundtype == SCIP_BOUNDTYPE_LOWER && newbound > oldlb && newbound * oldlb <= 0.0)
1859          || (boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsLT(set, newbound, oldub))
1860          || (boundtype == SCIP_BOUNDTYPE_UPPER && newbound < oldub && newbound * oldub <= 0.0));
1861 
1862    SCIPsetDebugMsg(set, "adding boundchange at node %llu at depth %u to variable <%s>: old bounds=[%g,%g], new %s bound: %g (infer%s=<%s>, inferinfo=%d)\n",
1863       node->number, node->depth, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
1864       boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper", newbound, infercons != NULL ? "cons" : "prop",
1865       infercons != NULL ? SCIPconsGetName(infercons) : (inferprop != NULL ? SCIPpropGetName(inferprop) : "-"), inferinfo);
1866 
1867    /* remember variable as inference variable, and get corresponding active variable, bound and bound type */
1868    infervar = var;
1869    inferboundtype = boundtype;
1870 
1871    SCIP_CALL( SCIPvarGetProbvarBound(&var, &newbound, &boundtype) );
1872 
1873    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
1874    {
1875       SCIPerrorMessage("cannot change bounds of multi-aggregated variable <%s>\n", SCIPvarGetName(var));
1876       SCIPABORT();
1877       return SCIP_INVALIDDATA; /*lint !e527*/
1878    }
1879    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
1880 
1881    /* the variable may have changed, make sure we have the correct bounds */
1882    if( useglobal )
1883    {
1884       oldlb = SCIPvarGetLbGlobal(var);
1885       oldub = SCIPvarGetUbGlobal(var);
1886    }
1887    else
1888    {
1889       oldlb = SCIPvarGetLbLocal(var);
1890       oldub = SCIPvarGetUbLocal(var);
1891    }
1892    assert(SCIPsetIsLE(set, oldlb, oldub));
1893 
1894    if( boundtype == SCIP_BOUNDTYPE_LOWER )
1895    {
1896       /* adjust lower bound w.r.t. to integrality */
1897       SCIPvarAdjustLb(var, set, &newbound);
1898       assert(SCIPsetIsFeasLE(set, newbound, oldub));
1899       oldbound = oldlb;
1900       newbound = MIN(newbound, oldub);
1901 
1902       if ( set->stage == SCIP_STAGE_SOLVING && SCIPsetIsInfinity(set, newbound) )
1903       {
1904          SCIPerrorMessage("cannot change lower bound of variable <%s> to infinity.\n", SCIPvarGetName(var));
1905          SCIPABORT();
1906          return SCIP_INVALIDDATA; /*lint !e527*/
1907       }
1908    }
1909    else
1910    {
1911       assert(boundtype == SCIP_BOUNDTYPE_UPPER);
1912 
1913       /* adjust the new upper bound */
1914       SCIPvarAdjustUb(var, set, &newbound);
1915       assert(SCIPsetIsFeasGE(set, newbound, oldlb));
1916       oldbound = oldub;
1917       newbound = MAX(newbound, oldlb);
1918 
1919       if ( set->stage == SCIP_STAGE_SOLVING && SCIPsetIsInfinity(set, -newbound) )
1920       {
1921          SCIPerrorMessage("cannot change upper bound of variable <%s> to minus infinity.\n", SCIPvarGetName(var));
1922          SCIPABORT();
1923          return SCIP_INVALIDDATA; /*lint !e527*/
1924       }
1925    }
1926 
1927    /* after switching to the active variable, the bounds might become redundant
1928     * if this happens, ignore the bound change
1929     */
1930    if( (boundtype == SCIP_BOUNDTYPE_LOWER && !SCIPsetIsGT(set, newbound, oldlb))
1931        || (boundtype == SCIP_BOUNDTYPE_UPPER && !SCIPsetIsLT(set, newbound, oldub)) )
1932       return SCIP_OKAY;
1933 
1934    SCIPsetDebugMsg(set, " -> transformed to active variable <%s>: old bounds=[%g,%g], new %s bound: %g, obj: %g\n",
1935       SCIPvarGetName(var), oldlb, oldub, boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper", newbound,
1936       SCIPvarGetObj(var));
1937 
1938    /* if the bound change takes place at an active node but is conflicting with the current local bounds,
1939     * we cannot apply it immediately because this would introduce inconsistencies to the bound change data structures
1940     * in the tree and to the bound change information data in the variable;
1941     * instead we have to remember the bound change as a pending bound change and mark the affected nodes on the active
1942     * path to be infeasible
1943     */
1944    if( node->active )
1945    {
1946       int conflictingdepth;
1947 
1948       conflictingdepth = SCIPvarGetConflictingBdchgDepth(var, set, boundtype, newbound);
1949 
1950       if( conflictingdepth >= 0 )
1951       {
1952          /* 0 would mean the bound change conflicts with a global bound */
1953          assert(conflictingdepth > 0);
1954          assert(conflictingdepth < tree->pathlen);
1955 
1956          SCIPsetDebugMsg(set, " -> bound change <%s> %s %g violates current local bounds [%g,%g] since depth %d: remember for later application\n",
1957             SCIPvarGetName(var), boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", newbound,
1958             SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), conflictingdepth);
1959 
1960          /* remember the pending bound change */
1961          SCIP_CALL( treeAddPendingBdchg(tree, set, node, var, newbound, boundtype, infercons, inferprop, inferinfo,
1962                probingchange) );
1963 
1964          /* mark the node with the conflicting bound change to be cut off */
1965          SCIP_CALL( SCIPnodeCutoff(tree->path[conflictingdepth], set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
1966 
1967          return SCIP_OKAY;
1968       }
1969    }
1970 
1971    SCIPstatIncrement(stat, set, nboundchgs);
1972 
1973    /* if we are in probing mode we have to additionally count the bound changes for the probing statistic */
1974    if( tree->probingroot != NULL )
1975       SCIPstatIncrement(stat, set, nprobboundchgs);
1976 
1977    /* if the node is the root node: change local and global bound immediately */
1978    if( SCIPnodeGetDepth(node) <= tree->effectiverootdepth )
1979    {
1980       assert(node->active || tree->focusnode == NULL );
1981       assert(SCIPnodeGetType(node) != SCIP_NODETYPE_PROBINGNODE);
1982       assert(!probingchange);
1983 
1984       SCIPsetDebugMsg(set, " -> bound change in root node: perform global bound change\n");
1985       SCIP_CALL( SCIPvarChgBdGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound, boundtype) );
1986 
1987       if( set->stage == SCIP_STAGE_SOLVING )
1988       {
1989          /* the root should be repropagated due to the bound change */
1990          SCIPnodePropagateAgain(tree->root, set, stat, tree);
1991          SCIPsetDebugMsg(set, "marked root node to be repropagated due to global bound change <%s>:[%g,%g] -> [%g,%g] found in depth %u\n",
1992             SCIPvarGetName(var), oldlb, oldub, boundtype == SCIP_BOUNDTYPE_LOWER ? newbound : oldlb,
1993             boundtype == SCIP_BOUNDTYPE_LOWER ? oldub : newbound, node->depth);
1994       }
1995 
1996       return SCIP_OKAY;
1997    }
1998 
1999    /* if the node is a child, or the bound is a temporary probing bound
2000     *  - the bound change is a branching decision
2001     *  - the child's lower bound can be updated due to the changed pseudo solution
2002     * otherwise:
2003     *  - the bound change is an inference
2004     */
2005    if( SCIPnodeGetType(node) == SCIP_NODETYPE_CHILD || probingchange )
2006    {
2007       SCIP_Real newpseudoobjval;
2008       SCIP_Real lpsolval;
2009 
2010       assert(!node->active || SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE);
2011 
2012       /* get the solution value of variable in last solved LP on the active path:
2013        *  - if the LP was solved at the current node, the LP values of the columns are valid
2014        *  - if the last solved LP was the one in the current lpstatefork, the LP value in the columns are still valid
2015        *  - otherwise, the LP values are invalid
2016        */
2017       if( SCIPtreeHasCurrentNodeLP(tree)
2018          || (tree->focuslpstateforklpcount == stat->lpcount && SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN) )
2019       {
2020          lpsolval = SCIPvarGetLPSol(var);
2021       }
2022       else
2023          lpsolval = SCIP_INVALID;
2024 
2025       /* remember the bound change as branching decision (infervar/infercons/inferprop are not important: use NULL) */
2026       SCIP_CALL( SCIPdomchgAddBoundchg(&node->domchg, blkmem, set, var, newbound, boundtype, SCIP_BOUNDCHGTYPE_BRANCHING,
2027             lpsolval, NULL, NULL, NULL, 0, inferboundtype) );
2028 
2029       /* update the child's lower bound */
2030       if( set->misc_exactsolve )
2031          newpseudoobjval = SCIPlpGetModifiedProvedPseudoObjval(lp, set, var, oldbound, newbound, boundtype);
2032       else
2033          newpseudoobjval = SCIPlpGetModifiedPseudoObjval(lp, set, transprob, var, oldbound, newbound, boundtype);
2034       SCIPnodeUpdateLowerbound(node, stat, set, tree, transprob, origprob, newpseudoobjval);
2035    }
2036    else
2037    {
2038       /* check the infered bound change on the debugging solution */
2039       SCIP_CALL( SCIPdebugCheckInference(blkmem, set, node, var, newbound, boundtype) ); /*lint !e506 !e774*/
2040 
2041       /* remember the bound change as inference (lpsolval is not important: use 0.0) */
2042       SCIP_CALL( SCIPdomchgAddBoundchg(&node->domchg, blkmem, set, var, newbound, boundtype,
2043             infercons != NULL ? SCIP_BOUNDCHGTYPE_CONSINFER : SCIP_BOUNDCHGTYPE_PROPINFER,
2044             0.0, infervar, infercons, inferprop, inferinfo, inferboundtype) );
2045    }
2046 
2047    assert(node->domchg != NULL);
2048    assert(node->domchg->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/
2049    assert(node->domchg->domchgdyn.boundchgs != NULL);
2050    assert(node->domchg->domchgdyn.nboundchgs > 0);
2051    assert(node->domchg->domchgdyn.boundchgs[node->domchg->domchgdyn.nboundchgs-1].var == var);
2052    assert(node->domchg->domchgdyn.boundchgs[node->domchg->domchgdyn.nboundchgs-1].newbound == newbound); /*lint !e777*/
2053 
2054    /* if node is active, apply the bound change immediately */
2055    if( node->active )
2056    {
2057       SCIP_Bool cutoff;
2058 
2059       /**@todo if the node is active, it currently must either be the effective root (see above) or the current node;
2060        *       if a bound change to an intermediate active node should be added, we must make sure, the bound change
2061        *       information array of the variable stays sorted (new info must be sorted in instead of putting it to
2062        *       the end of the array), and we should identify now redundant bound changes that are applied at a
2063        *       later node on the active path
2064        */
2065       assert(SCIPtreeGetCurrentNode(tree) == node);
2066       SCIP_CALL( SCIPboundchgApply(&node->domchg->domchgdyn.boundchgs[node->domchg->domchgdyn.nboundchgs-1],
2067             blkmem, set, stat, lp, branchcand, eventqueue, (int) node->depth, node->domchg->domchgdyn.nboundchgs-1, &cutoff) );
2068       assert(node->domchg->domchgdyn.boundchgs[node->domchg->domchgdyn.nboundchgs-1].var == var);
2069       assert(!cutoff);
2070    }
2071 
2072    return SCIP_OKAY;
2073 }
2074 
2075 /** adds bound change to focus node, or child of focus node, or probing node;
2076  *  if possible, adjusts bound to integral value
2077  */
SCIPnodeAddBoundchg(SCIP_NODE * node,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,SCIP_VAR * var,SCIP_Real newbound,SCIP_BOUNDTYPE boundtype,SCIP_Bool probingchange)2078 SCIP_RETCODE SCIPnodeAddBoundchg(
2079    SCIP_NODE*            node,               /**< node to add bound change to */
2080    BMS_BLKMEM*           blkmem,             /**< block memory */
2081    SCIP_SET*             set,                /**< global SCIP settings */
2082    SCIP_STAT*            stat,               /**< problem statistics */
2083    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
2084    SCIP_PROB*            origprob,           /**< original problem */
2085    SCIP_TREE*            tree,               /**< branch and bound tree */
2086    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
2087    SCIP_LP*              lp,                 /**< current LP data */
2088    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
2089    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2090    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
2091    SCIP_VAR*             var,                /**< variable to change the bounds for */
2092    SCIP_Real             newbound,           /**< new value for bound */
2093    SCIP_BOUNDTYPE        boundtype,          /**< type of bound: lower or upper bound */
2094    SCIP_Bool             probingchange       /**< is the bound change a temporary setting due to probing? */
2095    )
2096 {
2097    SCIP_CALL( SCIPnodeAddBoundinfer(node, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
2098          cliquetable, var, newbound, boundtype, NULL, NULL, 0, probingchange) );
2099 
2100    return SCIP_OKAY;
2101 }
2102 
2103 /** adds hole with inference information to focus node, child of focus node, or probing node;
2104  *  if possible, adjusts bound to integral value;
2105  *  at most one of infercons and inferprop may be non-NULL
2106  */
SCIPnodeAddHoleinfer(SCIP_NODE * node,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_TREE * tree,SCIP_EVENTQUEUE * eventqueue,SCIP_VAR * var,SCIP_Real left,SCIP_Real right,SCIP_CONS * infercons,SCIP_PROP * inferprop,int inferinfo,SCIP_Bool probingchange,SCIP_Bool * added)2107 SCIP_RETCODE SCIPnodeAddHoleinfer(
2108    SCIP_NODE*            node,               /**< node to add bound change to */
2109    BMS_BLKMEM*           blkmem,             /**< block memory */
2110    SCIP_SET*             set,                /**< global SCIP settings */
2111    SCIP_STAT*            stat,               /**< problem statistics */
2112    SCIP_TREE*            tree,               /**< branch and bound tree */
2113    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2114    SCIP_VAR*             var,                /**< variable to change the bounds for */
2115    SCIP_Real             left,               /**< left bound of open interval defining the hole (left,right) */
2116    SCIP_Real             right,              /**< right bound of open interval defining the hole (left,right) */
2117    SCIP_CONS*            infercons,          /**< constraint that deduced the bound change, or NULL */
2118    SCIP_PROP*            inferprop,          /**< propagator that deduced the bound change, or NULL */
2119    int                   inferinfo,          /**< user information for inference to help resolving the conflict */
2120    SCIP_Bool             probingchange,      /**< is the bound change a temporary setting due to probing? */
2121    SCIP_Bool*            added               /**< pointer to store whether the hole was added, or NULL */
2122    )
2123 {
2124 #if 0
2125    SCIP_VAR* infervar;
2126 #endif
2127 
2128    assert(node != NULL);
2129    assert((SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_FOCUSNODE
2130       || (SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_PROBINGNODE
2131       || (SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_CHILD
2132       || (SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_REFOCUSNODE
2133       || node->depth == 0);
2134    assert(blkmem != NULL);
2135    assert(set != NULL);
2136    assert(tree != NULL);
2137    assert(tree->effectiverootdepth >= 0);
2138    assert(tree->root != NULL);
2139    assert(var != NULL);
2140    assert(node->active || (infercons == NULL && inferprop == NULL));
2141    assert((SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_PROBINGNODE || !probingchange);
2142 
2143    /* the interval should not be empty */
2144    assert(SCIPsetIsLT(set, left, right));
2145 
2146 #ifndef NDEBUG
2147    {
2148       SCIP_Real adjustedleft;
2149       SCIP_Real adjustedright;
2150 
2151       adjustedleft = left;
2152       adjustedright = right;
2153 
2154       SCIPvarAdjustUb(var, set, &adjustedleft);
2155       SCIPvarAdjustLb(var, set, &adjustedright);
2156 
2157       assert(SCIPsetIsEQ(set, left, adjustedleft));
2158       assert(SCIPsetIsEQ(set, right, adjustedright));
2159    }
2160 #endif
2161 
2162    /* the hole should lay within the lower and upper bounds */
2163    assert(SCIPsetIsGE(set, left, SCIPvarGetLbLocal(var)));
2164    assert(SCIPsetIsLE(set, right, SCIPvarGetUbLocal(var)));
2165 
2166    SCIPsetDebugMsg(set, "adding hole (%g,%g) at node at depth %u to variable <%s>: bounds=[%g,%g], (infer%s=<%s>, inferinfo=%d)\n",
2167       left, right, node->depth, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), infercons != NULL ? "cons" : "prop",
2168       infercons != NULL ? SCIPconsGetName(infercons) : (inferprop != NULL ? SCIPpropGetName(inferprop) : "-"), inferinfo);
2169 
2170 #if 0
2171    /* remember variable as inference variable, and get corresponding active variable, bound and bound type */
2172    infervar = var;
2173 #endif
2174    SCIP_CALL( SCIPvarGetProbvarHole(&var, &left, &right) );
2175 
2176    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
2177    {
2178       SCIPerrorMessage("cannot change bounds of multi-aggregated variable <%s>\n", SCIPvarGetName(var));
2179       SCIPABORT();
2180       return SCIP_INVALIDDATA; /*lint !e527*/
2181    }
2182    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
2183 
2184    SCIPsetDebugMsg(set, " -> transformed to active variable <%s>: hole (%g,%g), obj: %g\n", SCIPvarGetName(var), left, right, SCIPvarGetObj(var));
2185 
2186    stat->nholechgs++;
2187 
2188    /* if we are in probing mode we have to additionally count the bound changes for the probing statistic */
2189    if( tree->probingroot != NULL )
2190       stat->nprobholechgs++;
2191 
2192    /* if the node is the root node: change local and global bound immediately */
2193    if( SCIPnodeGetDepth(node) <= tree->effectiverootdepth )
2194    {
2195       assert(node->active || tree->focusnode == NULL );
2196       assert(SCIPnodeGetType(node) != SCIP_NODETYPE_PROBINGNODE);
2197       assert(!probingchange);
2198 
2199       SCIPsetDebugMsg(set, " -> hole added in root node: perform global domain change\n");
2200       SCIP_CALL( SCIPvarAddHoleGlobal(var, blkmem, set, stat, eventqueue, left, right, added) );
2201 
2202       if( set->stage == SCIP_STAGE_SOLVING && (*added) )
2203       {
2204          /* the root should be repropagated due to the bound change */
2205          SCIPnodePropagateAgain(tree->root, set, stat, tree);
2206          SCIPsetDebugMsg(set, "marked root node to be repropagated due to global added hole <%s>: (%g,%g) found in depth %u\n",
2207             SCIPvarGetName(var), left, right, node->depth);
2208       }
2209 
2210       return SCIP_OKAY;
2211    }
2212 
2213    /**@todo add adding of local domain holes */
2214 
2215    (*added) = FALSE;
2216    SCIPerrorMessage("WARNING: currently domain holes can only be handled globally!\n");
2217 
2218    stat->nholechgs--;
2219 
2220    /* if we are in probing mode we have to additionally count the bound changes for the probing statistic */
2221    if( tree->probingroot != NULL )
2222       stat->nprobholechgs--;
2223 
2224    return SCIP_OKAY;
2225 }
2226 
2227 /** adds hole change to focus node, or child of focus node */
SCIPnodeAddHolechg(SCIP_NODE * node,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_TREE * tree,SCIP_EVENTQUEUE * eventqueue,SCIP_VAR * var,SCIP_Real left,SCIP_Real right,SCIP_Bool probingchange,SCIP_Bool * added)2228 SCIP_RETCODE SCIPnodeAddHolechg(
2229    SCIP_NODE*            node,               /**< node to add bound change to */
2230    BMS_BLKMEM*           blkmem,             /**< block memory */
2231    SCIP_SET*             set,                /**< global SCIP settings */
2232    SCIP_STAT*            stat,               /**< problem statistics */
2233    SCIP_TREE*            tree,               /**< branch and bound tree */
2234    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2235    SCIP_VAR*             var,                /**< variable to change the bounds for */
2236    SCIP_Real             left,               /**< left bound of open interval defining the hole (left,right) */
2237    SCIP_Real             right,              /**< right bound of open interval defining the hole (left,right) */
2238    SCIP_Bool             probingchange,      /**< is the bound change a temporary setting due to probing? */
2239    SCIP_Bool*            added               /**< pointer to store whether the hole was added, or NULL */
2240    )
2241 {
2242    assert(node != NULL);
2243    assert((SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_FOCUSNODE
2244       || (SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_PROBINGNODE
2245       || (SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_CHILD);
2246    assert(blkmem != NULL);
2247 
2248    SCIPsetDebugMsg(set, "adding hole (%g,%g) at node at depth %u of variable <%s>\n",
2249       left, right, node->depth, SCIPvarGetName(var));
2250 
2251    SCIP_CALL( SCIPnodeAddHoleinfer(node, blkmem, set, stat, tree, eventqueue, var, left, right,
2252          NULL, NULL, 0, probingchange, added) );
2253 
2254    /**@todo apply hole change on active nodes and issue event */
2255 
2256    return SCIP_OKAY;
2257 }
2258 
2259 /** applies the pending bound changes */
2260 static
treeApplyPendingBdchgs(SCIP_TREE * tree,SCIP_REOPT * reopt,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable)2261 SCIP_RETCODE treeApplyPendingBdchgs(
2262    SCIP_TREE*            tree,               /**< branch and bound tree */
2263    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
2264    BMS_BLKMEM*           blkmem,             /**< block memory */
2265    SCIP_SET*             set,                /**< global SCIP settings */
2266    SCIP_STAT*            stat,               /**< problem statistics */
2267    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
2268    SCIP_PROB*            origprob,           /**< original problem */
2269    SCIP_LP*              lp,                 /**< current LP data */
2270    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
2271    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2272    SCIP_CLIQUETABLE*     cliquetable         /**< clique table data structure */
2273    )
2274 {
2275    SCIP_VAR* var;
2276    int npendingbdchgs;
2277    int conflictdepth;
2278    int i;
2279 
2280    assert(tree != NULL);
2281 
2282    npendingbdchgs = tree->npendingbdchgs;
2283    for( i = 0; i < npendingbdchgs; ++i )
2284    {
2285       var = tree->pendingbdchgs[i].var;
2286       assert(SCIPnodeGetDepth(tree->pendingbdchgs[i].node) < tree->cutoffdepth);
2287 
2288       conflictdepth = SCIPvarGetConflictingBdchgDepth(var, set, tree->pendingbdchgs[i].boundtype,
2289          tree->pendingbdchgs[i].newbound);
2290 
2291       /* It can happen, that a pending bound change conflicts with the global bounds, because when it was collected, it
2292        * just conflicted with the local bounds, but a conflicting global bound change was applied afterwards. In this
2293        * case, we can cut off the node where the pending bound change should be applied.
2294        */
2295       if( conflictdepth == 0 )
2296       {
2297          SCIP_CALL( SCIPnodeCutoff(tree->pendingbdchgs[i].node, set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
2298 
2299          if( ((int) tree->pendingbdchgs[i].node->depth) <= tree->effectiverootdepth )
2300             break; /* break here to clear all pending bound changes */
2301          else
2302             continue;
2303       }
2304 
2305       assert(conflictdepth == -1);
2306 
2307       SCIPsetDebugMsg(set, "applying pending bound change <%s>[%g,%g] %s %g\n", SCIPvarGetName(var),
2308          SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
2309          tree->pendingbdchgs[i].boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
2310          tree->pendingbdchgs[i].newbound);
2311 
2312       /* ignore bounds that are now redundant (for example, multiple entries in the pendingbdchgs for the same
2313        * variable)
2314        */
2315       if( tree->pendingbdchgs[i].boundtype == SCIP_BOUNDTYPE_LOWER )
2316       {
2317          SCIP_Real lb;
2318 
2319          lb = SCIPvarGetLbLocal(var);
2320          if( !SCIPsetIsGT(set, tree->pendingbdchgs[i].newbound, lb) )
2321             continue;
2322       }
2323       else
2324       {
2325          SCIP_Real ub;
2326 
2327          assert(tree->pendingbdchgs[i].boundtype == SCIP_BOUNDTYPE_UPPER);
2328          ub = SCIPvarGetUbLocal(var);
2329          if( !SCIPsetIsLT(set, tree->pendingbdchgs[i].newbound, ub) )
2330             continue;
2331       }
2332 
2333       SCIP_CALL( SCIPnodeAddBoundinfer(tree->pendingbdchgs[i].node, blkmem, set, stat, transprob, origprob, tree, reopt,
2334             lp, branchcand, eventqueue, cliquetable, var, tree->pendingbdchgs[i].newbound, tree->pendingbdchgs[i].boundtype,
2335             tree->pendingbdchgs[i].infercons, tree->pendingbdchgs[i].inferprop, tree->pendingbdchgs[i].inferinfo,
2336             tree->pendingbdchgs[i].probingchange) );
2337       assert(tree->npendingbdchgs == npendingbdchgs); /* this time, the bound change can be applied! */
2338    }
2339 
2340    /* clear pending bound changes */
2341    for( i = 0; i < tree->npendingbdchgs; ++i )
2342    {
2343       var = tree->pendingbdchgs[i].var;
2344       assert(var != NULL);
2345 
2346       /* release the variable */
2347       SCIP_CALL( SCIPvarRelease(&var, blkmem, set, eventqueue, lp) );
2348    }
2349 
2350    tree->npendingbdchgs = 0;
2351 
2352    return SCIP_OKAY;
2353 }
2354 
2355 /** if given value is larger than the node's lower bound, sets the node's lower bound to the new value */
SCIPnodeUpdateLowerbound(SCIP_NODE * node,SCIP_STAT * stat,SCIP_SET * set,SCIP_TREE * tree,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_Real newbound)2356 void SCIPnodeUpdateLowerbound(
2357    SCIP_NODE*            node,               /**< node to update lower bound for */
2358    SCIP_STAT*            stat,               /**< problem statistics */
2359    SCIP_SET*             set,                /**< global SCIP settings */
2360    SCIP_TREE*            tree,               /**< branch and bound tree */
2361    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
2362    SCIP_PROB*            origprob,           /**< original problem */
2363    SCIP_Real             newbound            /**< new lower bound for the node (if it's larger than the old one) */
2364    )
2365 {
2366    assert(node != NULL);
2367    assert(stat != NULL);
2368 
2369    if( newbound > node->lowerbound )
2370    {
2371       SCIP_Real oldbound;
2372 
2373       oldbound = node->lowerbound;
2374       node->lowerbound = newbound;
2375       node->estimate = MAX(node->estimate, newbound);
2376 
2377       if( node->depth == 0 )
2378       {
2379          stat->rootlowerbound = newbound;
2380          if( set->misc_calcintegral )
2381             SCIPstatUpdatePrimalDualIntegrals(stat, set, transprob, origprob, SCIPsetInfinity(set), newbound);
2382          SCIPvisualLowerbound(stat->visual, set, stat, newbound);
2383       }
2384       else if ( SCIPnodeGetType(node) != SCIP_NODETYPE_PROBINGNODE )
2385       {
2386          SCIP_Real lowerbound;
2387 
2388          lowerbound = SCIPtreeGetLowerbound(tree, set);
2389          assert(newbound >= lowerbound);
2390          SCIPvisualLowerbound(stat->visual, set, stat, lowerbound);
2391 
2392          /* updating the primal integral is only necessary if dual bound has increased since last evaluation */
2393          if( set->misc_calcintegral && SCIPsetIsEQ(set, oldbound, stat->lastlowerbound) && lowerbound > stat->lastlowerbound )
2394             SCIPstatUpdatePrimalDualIntegrals(stat, set, transprob, origprob, SCIPsetInfinity(set), lowerbound);
2395       }
2396    }
2397 }
2398 
2399 /** updates lower bound of node using lower bound of LP */
SCIPnodeUpdateLowerboundLP(SCIP_NODE * node,SCIP_SET * set,SCIP_STAT * stat,SCIP_TREE * tree,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_LP * lp)2400 SCIP_RETCODE SCIPnodeUpdateLowerboundLP(
2401    SCIP_NODE*            node,               /**< node to set lower bound for */
2402    SCIP_SET*             set,                /**< global SCIP settings */
2403    SCIP_STAT*            stat,               /**< problem statistics */
2404    SCIP_TREE*            tree,               /**< branch and bound tree */
2405    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
2406    SCIP_PROB*            origprob,           /**< original problem */
2407    SCIP_LP*              lp                  /**< LP data */
2408    )
2409 {
2410    SCIP_Real lpobjval;
2411 
2412    assert(set != NULL);
2413    assert(lp->flushed);
2414 
2415    /* in case of iteration or time limit, the LP value may not be a valid dual bound */
2416    /* @todo check for dual feasibility of LP solution and use sub-optimal solution if they are dual feasible */
2417    if( lp->lpsolstat == SCIP_LPSOLSTAT_ITERLIMIT || lp->lpsolstat == SCIP_LPSOLSTAT_TIMELIMIT )
2418       return SCIP_OKAY;
2419 
2420    if( set->misc_exactsolve )
2421    {
2422       SCIP_CALL( SCIPlpGetProvedLowerbound(lp, set, &lpobjval) );
2423    }
2424    else
2425       lpobjval = SCIPlpGetObjval(lp, set, transprob);
2426 
2427    SCIPnodeUpdateLowerbound(node, stat, set, tree, transprob, origprob, lpobjval);
2428 
2429    return SCIP_OKAY;
2430 }
2431 
2432 
2433 /** change the node selection priority of the given child */
SCIPchildChgNodeselPrio(SCIP_TREE * tree,SCIP_NODE * child,SCIP_Real priority)2434 void SCIPchildChgNodeselPrio(
2435    SCIP_TREE*            tree,               /**< branch and bound tree */
2436    SCIP_NODE*            child,              /**< child to update the node selection priority */
2437    SCIP_Real             priority            /**< node selection priority value */
2438    )
2439 {
2440    int pos;
2441 
2442    assert( SCIPnodeGetType(child) == SCIP_NODETYPE_CHILD );
2443 
2444    pos = child->data.child.arraypos;
2445    assert( pos >= 0 );
2446 
2447    tree->childrenprio[pos] = priority;
2448 }
2449 
2450 
2451 /** sets the node's estimated bound to the new value */
SCIPnodeSetEstimate(SCIP_NODE * node,SCIP_SET * set,SCIP_Real newestimate)2452 void SCIPnodeSetEstimate(
2453    SCIP_NODE*            node,               /**< node to update lower bound for */
2454    SCIP_SET*             set,                /**< global SCIP settings */
2455    SCIP_Real             newestimate         /**< new estimated bound for the node */
2456    )
2457 {
2458    assert(node != NULL);
2459    assert(set != NULL);
2460    assert(SCIPsetIsRelGE(set, newestimate, node->lowerbound));
2461 
2462    /* due to numerical reasons we need this check, see https://git.zib.de/integer/scip/issues/2866 */
2463    if( node->lowerbound <= newestimate )
2464       node->estimate = newestimate;
2465 }
2466 
2467 /** propagates implications of binary fixings at the given node triggered by the implication graph and the clique table */
SCIPnodePropagateImplics(SCIP_NODE * node,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,SCIP_Bool * cutoff)2468 SCIP_RETCODE SCIPnodePropagateImplics(
2469    SCIP_NODE*            node,               /**< node to propagate implications on */
2470    BMS_BLKMEM*           blkmem,             /**< block memory */
2471    SCIP_SET*             set,                /**< global SCIP settings */
2472    SCIP_STAT*            stat,               /**< problem statistics */
2473    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
2474    SCIP_PROB*            origprob,           /**< original problem */
2475    SCIP_TREE*            tree,               /**< branch and bound tree */
2476    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
2477    SCIP_LP*              lp,                 /**< current LP data */
2478    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
2479    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
2480    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
2481    SCIP_Bool*            cutoff              /**< pointer to store whether the node can be cut off */
2482    )
2483 {
2484    int nboundchgs;
2485    int i;
2486 
2487    assert(node != NULL);
2488    assert(SCIPnodeIsActive(node));
2489    assert(SCIPnodeGetType(node) == SCIP_NODETYPE_FOCUSNODE
2490       || SCIPnodeGetType(node) == SCIP_NODETYPE_REFOCUSNODE
2491       || SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE);
2492    assert(cutoff != NULL);
2493 
2494    SCIPsetDebugMsg(set, "implication graph propagation of node #%" SCIP_LONGINT_FORMAT " in depth %d\n",
2495       SCIPnodeGetNumber(node), SCIPnodeGetDepth(node));
2496 
2497    *cutoff = FALSE;
2498 
2499    /* propagate all fixings of binary variables performed at this node */
2500    nboundchgs = SCIPdomchgGetNBoundchgs(node->domchg);
2501    for( i = 0; i < nboundchgs && !(*cutoff); ++i )
2502    {
2503       SCIP_BOUNDCHG* boundchg;
2504       SCIP_VAR* var;
2505 
2506       boundchg = SCIPdomchgGetBoundchg(node->domchg, i);
2507 
2508       /* ignore redundant bound changes */
2509       if( SCIPboundchgIsRedundant(boundchg) )
2510          continue;
2511 
2512       var = SCIPboundchgGetVar(boundchg);
2513       if( SCIPvarIsBinary(var) )
2514       {
2515          SCIP_Bool varfixing;
2516          int nimpls;
2517          SCIP_VAR** implvars;
2518          SCIP_BOUNDTYPE* impltypes;
2519          SCIP_Real* implbounds;
2520          SCIP_CLIQUE** cliques;
2521          int ncliques;
2522          int j;
2523 
2524          varfixing = (SCIPboundchgGetBoundtype(boundchg) == SCIP_BOUNDTYPE_LOWER);
2525          nimpls = SCIPvarGetNImpls(var, varfixing);
2526          implvars = SCIPvarGetImplVars(var, varfixing);
2527          impltypes = SCIPvarGetImplTypes(var, varfixing);
2528          implbounds = SCIPvarGetImplBounds(var, varfixing);
2529 
2530          /* apply implications */
2531          for( j = 0; j < nimpls; ++j )
2532          {
2533             SCIP_Real lb;
2534             SCIP_Real ub;
2535 
2536             /* @note should this be checked here (because SCIPnodeAddBoundinfer fails for multi-aggregated variables)
2537              *       or should SCIPnodeAddBoundinfer() just return for multi-aggregated variables?
2538              */
2539             if( SCIPvarGetStatus(implvars[j]) == SCIP_VARSTATUS_MULTAGGR ||
2540                   SCIPvarGetStatus(SCIPvarGetProbvar(implvars[j])) == SCIP_VARSTATUS_MULTAGGR )
2541                continue;
2542 
2543             /* check for infeasibility */
2544             lb = SCIPvarGetLbLocal(implvars[j]);
2545             ub = SCIPvarGetUbLocal(implvars[j]);
2546             if( impltypes[j] == SCIP_BOUNDTYPE_LOWER )
2547             {
2548                if( SCIPsetIsFeasGT(set, implbounds[j], ub) )
2549                {
2550                   *cutoff = TRUE;
2551                   return SCIP_OKAY;
2552                }
2553                if( SCIPsetIsFeasLE(set, implbounds[j], lb) )
2554                   continue;
2555             }
2556             else
2557             {
2558                if( SCIPsetIsFeasLT(set, implbounds[j], lb) )
2559                {
2560                   *cutoff = TRUE;
2561                   return SCIP_OKAY;
2562                }
2563                if( SCIPsetIsFeasGE(set, implbounds[j], ub) )
2564                   continue;
2565             }
2566 
2567             /* @note the implication might affect a fixed variable (after resolving (multi-)aggregations);
2568              *       normally, the implication should have been deleted in that case, but this is only possible
2569              *       if the implied variable has the reverse implication stored as a variable bound;
2570              *       due to numerics, the variable bound may not be present and so the implication is not deleted
2571              */
2572             if( SCIPvarGetStatus(SCIPvarGetProbvar(implvars[j])) == SCIP_VARSTATUS_FIXED )
2573                continue;
2574 
2575             /* apply the implication */
2576             SCIP_CALL( SCIPnodeAddBoundinfer(node, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
2577                   eventqueue, cliquetable, implvars[j], implbounds[j], impltypes[j], NULL, NULL, 0, FALSE) );
2578          }
2579 
2580          /* apply cliques */
2581          ncliques = SCIPvarGetNCliques(var, varfixing);
2582          cliques = SCIPvarGetCliques(var, varfixing);
2583          for( j = 0; j < ncliques; ++j )
2584          {
2585             SCIP_VAR** vars;
2586             SCIP_Bool* values;
2587             int nvars;
2588             int k;
2589 
2590             nvars = SCIPcliqueGetNVars(cliques[j]);
2591             vars = SCIPcliqueGetVars(cliques[j]);
2592             values = SCIPcliqueGetValues(cliques[j]);
2593             for( k = 0; k < nvars; ++k )
2594             {
2595                SCIP_Real lb;
2596                SCIP_Real ub;
2597 
2598                assert(SCIPvarIsBinary(vars[k]));
2599 
2600                if( SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_MULTAGGR ||
2601                      SCIPvarGetStatus(SCIPvarGetProbvar(vars[k])) == SCIP_VARSTATUS_MULTAGGR )
2602                   continue;
2603 
2604                if( vars[k] == var && values[k] == varfixing )
2605                   continue;
2606 
2607                /* check for infeasibility */
2608                lb = SCIPvarGetLbLocal(vars[k]);
2609                ub = SCIPvarGetUbLocal(vars[k]);
2610                if( values[k] == FALSE )
2611                {
2612                   if( ub < 0.5 )
2613                   {
2614                      *cutoff = TRUE;
2615                      return SCIP_OKAY;
2616                   }
2617                   if( lb > 0.5 )
2618                      continue;
2619                }
2620                else
2621                {
2622                   if( lb > 0.5 )
2623                   {
2624                      *cutoff = TRUE;
2625                      return SCIP_OKAY;
2626                   }
2627                   if( ub < 0.5 )
2628                      continue;
2629                }
2630 
2631                if( SCIPvarGetStatus(SCIPvarGetProbvar(vars[k])) == SCIP_VARSTATUS_FIXED )
2632                   continue;
2633 
2634                /* apply the clique implication */
2635                SCIP_CALL( SCIPnodeAddBoundinfer(node, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
2636                      eventqueue, cliquetable, vars[k], (SCIP_Real)(!values[k]), values[k] ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER,
2637                      NULL, NULL, 0, FALSE) );
2638             }
2639          }
2640       }
2641    }
2642 
2643    return SCIP_OKAY;
2644 }
2645 
2646 
2647 
2648 
2649 /*
2650  * Path Switching
2651  */
2652 
2653 /** updates the LP sizes of the active path starting at the given depth */
2654 static
treeUpdatePathLPSize(SCIP_TREE * tree,int startdepth)2655 SCIP_RETCODE treeUpdatePathLPSize(
2656    SCIP_TREE*            tree,               /**< branch and bound tree */
2657    int                   startdepth          /**< depth to start counting */
2658    )
2659 {
2660    SCIP_NODE* node;
2661    int ncols;
2662    int nrows;
2663    int i;
2664 
2665    assert(tree != NULL);
2666    assert(startdepth >= 0);
2667    assert(startdepth <= tree->pathlen);
2668 
2669    if( startdepth == 0 )
2670    {
2671       ncols = 0;
2672       nrows = 0;
2673    }
2674    else
2675    {
2676       ncols = tree->pathnlpcols[startdepth-1];
2677       nrows = tree->pathnlprows[startdepth-1];
2678    }
2679 
2680    for( i = startdepth; i < tree->pathlen; ++i )
2681    {
2682       node = tree->path[i];
2683       assert(node != NULL);
2684       assert(node->active);
2685       assert((int)(node->depth) == i);
2686 
2687       switch( SCIPnodeGetType(node) )
2688       {
2689       case SCIP_NODETYPE_FOCUSNODE:
2690          assert(i == tree->pathlen-1 || SCIPtreeProbing(tree));
2691          break;
2692       case SCIP_NODETYPE_PROBINGNODE:
2693          assert(SCIPtreeProbing(tree));
2694          assert(i >= 1);
2695          assert(SCIPnodeGetType(tree->path[i-1]) == SCIP_NODETYPE_FOCUSNODE
2696             || (ncols == node->data.probingnode->ninitialcols && nrows == node->data.probingnode->ninitialrows));
2697          assert(ncols <= node->data.probingnode->ncols || !tree->focuslpconstructed);
2698          assert(nrows <= node->data.probingnode->nrows || !tree->focuslpconstructed);
2699          if( i < tree->pathlen-1 )
2700          {
2701             ncols = node->data.probingnode->ncols;
2702             nrows = node->data.probingnode->nrows;
2703          }
2704          else
2705          {
2706             /* for the current probing node, the initial LP size is stored in the path */
2707             ncols = node->data.probingnode->ninitialcols;
2708             nrows = node->data.probingnode->ninitialrows;
2709          }
2710          break;
2711       case SCIP_NODETYPE_SIBLING:
2712          SCIPerrorMessage("sibling cannot be in the active path\n");
2713          SCIPABORT();
2714          return SCIP_INVALIDDATA;  /*lint !e527*/
2715       case SCIP_NODETYPE_CHILD:
2716          SCIPerrorMessage("child cannot be in the active path\n");
2717          SCIPABORT();
2718          return SCIP_INVALIDDATA;  /*lint !e527*/
2719       case SCIP_NODETYPE_LEAF:
2720          SCIPerrorMessage("leaf cannot be in the active path\n");
2721          SCIPABORT();
2722          return SCIP_INVALIDDATA;  /*lint !e527*/
2723       case SCIP_NODETYPE_DEADEND:
2724          SCIPerrorMessage("dead-end cannot be in the active path\n");
2725          SCIPABORT();
2726          return SCIP_INVALIDDATA;  /*lint !e527*/
2727       case SCIP_NODETYPE_JUNCTION:
2728          break;
2729       case SCIP_NODETYPE_PSEUDOFORK:
2730          assert(node->data.pseudofork != NULL);
2731          ncols += node->data.pseudofork->naddedcols;
2732          nrows += node->data.pseudofork->naddedrows;
2733          break;
2734       case SCIP_NODETYPE_FORK:
2735          assert(node->data.fork != NULL);
2736          ncols += node->data.fork->naddedcols;
2737          nrows += node->data.fork->naddedrows;
2738          break;
2739       case SCIP_NODETYPE_SUBROOT:
2740          assert(node->data.subroot != NULL);
2741          ncols = node->data.subroot->ncols;
2742          nrows = node->data.subroot->nrows;
2743          break;
2744       case SCIP_NODETYPE_REFOCUSNODE:
2745          SCIPerrorMessage("node cannot be of type REFOCUSNODE at this point\n");
2746          SCIPABORT();
2747          return SCIP_INVALIDDATA;  /*lint !e527*/
2748       default:
2749          SCIPerrorMessage("unknown node type %d\n", SCIPnodeGetType(node));
2750          SCIPABORT();
2751          return SCIP_INVALIDDATA;  /*lint !e527*/
2752       }
2753       tree->pathnlpcols[i] = ncols;
2754       tree->pathnlprows[i] = nrows;
2755    }
2756    return SCIP_OKAY;
2757 }
2758 
2759 /** finds the common fork node, the new LP state defining fork, and the new focus subroot, if the path is switched to
2760  *  the given node
2761  */
2762 static
treeFindSwitchForks(SCIP_TREE * tree,SCIP_NODE * node,SCIP_NODE ** commonfork,SCIP_NODE ** newlpfork,SCIP_NODE ** newlpstatefork,SCIP_NODE ** newsubroot,SCIP_Bool * cutoff)2763 void treeFindSwitchForks(
2764    SCIP_TREE*            tree,               /**< branch and bound tree */
2765    SCIP_NODE*            node,               /**< new focus node, or NULL */
2766    SCIP_NODE**           commonfork,         /**< pointer to store common fork node of old and new focus node */
2767    SCIP_NODE**           newlpfork,          /**< pointer to store the new LP defining fork node */
2768    SCIP_NODE**           newlpstatefork,     /**< pointer to store the new LP state defining fork node */
2769    SCIP_NODE**           newsubroot,         /**< pointer to store the new subroot node */
2770    SCIP_Bool*            cutoff              /**< pointer to store whether the given node can be cut off and no path switching
2771                                               *   should be performed */
2772    )
2773 {
2774    SCIP_NODE* fork;
2775    SCIP_NODE* lpfork;
2776    SCIP_NODE* lpstatefork;
2777    SCIP_NODE* subroot;
2778 
2779    assert(tree != NULL);
2780    assert(tree->root != NULL);
2781    assert((tree->focusnode == NULL) == !tree->root->active);
2782    assert(tree->focuslpfork == NULL || tree->focusnode != NULL);
2783    assert(tree->focuslpfork == NULL || tree->focuslpfork->depth < tree->focusnode->depth);
2784    assert(tree->focuslpstatefork == NULL || tree->focuslpfork != NULL);
2785    assert(tree->focuslpstatefork == NULL || tree->focuslpstatefork->depth <= tree->focuslpfork->depth);
2786    assert(tree->focussubroot == NULL || tree->focuslpstatefork != NULL);
2787    assert(tree->focussubroot == NULL || tree->focussubroot->depth <= tree->focuslpstatefork->depth);
2788    assert(tree->cutoffdepth >= 0);
2789    assert(tree->cutoffdepth == INT_MAX || tree->cutoffdepth < tree->pathlen);
2790    assert(tree->cutoffdepth == INT_MAX || tree->path[tree->cutoffdepth]->cutoff);
2791    assert(tree->repropdepth >= 0);
2792    assert(tree->repropdepth == INT_MAX || tree->repropdepth < tree->pathlen);
2793    assert(tree->repropdepth == INT_MAX || tree->path[tree->repropdepth]->reprop);
2794    assert(commonfork != NULL);
2795    assert(newlpfork != NULL);
2796    assert(newlpstatefork != NULL);
2797    assert(newsubroot != NULL);
2798    assert(cutoff != NULL);
2799 
2800    *commonfork = NULL;
2801    *newlpfork = NULL;
2802    *newlpstatefork = NULL;
2803    *newsubroot = NULL;
2804    *cutoff = FALSE;
2805 
2806    /* if the new focus node is NULL, there is no common fork node, and the new LP fork, LP state fork, and subroot
2807     * are NULL
2808     */
2809    if( node == NULL )
2810    {
2811       tree->cutoffdepth = INT_MAX;
2812       tree->repropdepth = INT_MAX;
2813       return;
2814    }
2815 
2816    /* check if the new node is marked to be cut off */
2817    if( node->cutoff )
2818    {
2819       *cutoff = TRUE;
2820       return;
2821    }
2822 
2823    /* if the old focus node is NULL, there is no common fork node, and we have to search the new LP fork, LP state fork
2824     * and subroot
2825     */
2826    if( tree->focusnode == NULL )
2827    {
2828       assert(!tree->root->active);
2829       assert(tree->pathlen == 0);
2830       assert(tree->cutoffdepth == INT_MAX);
2831       assert(tree->repropdepth == INT_MAX);
2832 
2833       lpfork = node;
2834       while( SCIPnodeGetType(lpfork) != SCIP_NODETYPE_PSEUDOFORK
2835          && SCIPnodeGetType(lpfork) != SCIP_NODETYPE_FORK && SCIPnodeGetType(lpfork) != SCIP_NODETYPE_SUBROOT )
2836       {
2837          lpfork = lpfork->parent;
2838          if( lpfork == NULL )
2839             return;
2840          if( lpfork->cutoff )
2841          {
2842             *cutoff = TRUE;
2843             return;
2844          }
2845       }
2846       *newlpfork = lpfork;
2847 
2848       lpstatefork = lpfork;
2849       while( SCIPnodeGetType(lpstatefork) != SCIP_NODETYPE_FORK && SCIPnodeGetType(lpstatefork) != SCIP_NODETYPE_SUBROOT )
2850       {
2851          lpstatefork = lpstatefork->parent;
2852          if( lpstatefork == NULL )
2853             return;
2854          if( lpstatefork->cutoff )
2855          {
2856             *cutoff = TRUE;
2857             return;
2858          }
2859       }
2860       *newlpstatefork = lpstatefork;
2861 
2862       subroot = lpstatefork;
2863       while( SCIPnodeGetType(subroot) != SCIP_NODETYPE_SUBROOT )
2864       {
2865          subroot = subroot->parent;
2866          if( subroot == NULL )
2867             return;
2868          if( subroot->cutoff )
2869          {
2870             *cutoff = TRUE;
2871             return;
2872          }
2873       }
2874       *newsubroot = subroot;
2875 
2876       fork = subroot;
2877       while( fork->parent != NULL )
2878       {
2879          fork = fork->parent;
2880          if( fork->cutoff )
2881          {
2882             *cutoff = TRUE;
2883             return;
2884          }
2885       }
2886       return;
2887    }
2888 
2889    /* find the common fork node, the new LP defining fork, the new LP state defining fork, and the new focus subroot */
2890    fork = node;
2891    lpfork = NULL;
2892    lpstatefork = NULL;
2893    subroot = NULL;
2894    assert(fork != NULL);
2895 
2896    while( !fork->active )
2897    {
2898       fork = fork->parent;
2899       assert(fork != NULL); /* because the root is active, there must be a common fork node */
2900 
2901       if( fork->cutoff )
2902       {
2903          *cutoff = TRUE;
2904          return;
2905       }
2906       if( lpfork == NULL
2907          && (SCIPnodeGetType(fork) == SCIP_NODETYPE_PSEUDOFORK
2908             || SCIPnodeGetType(fork) == SCIP_NODETYPE_FORK || SCIPnodeGetType(fork) == SCIP_NODETYPE_SUBROOT) )
2909          lpfork = fork;
2910       if( lpstatefork == NULL
2911          && (SCIPnodeGetType(fork) == SCIP_NODETYPE_FORK || SCIPnodeGetType(fork) == SCIP_NODETYPE_SUBROOT) )
2912          lpstatefork = fork;
2913       if( subroot == NULL && SCIPnodeGetType(fork) == SCIP_NODETYPE_SUBROOT )
2914          subroot = fork;
2915    }
2916    assert(lpfork == NULL || !lpfork->active || lpfork == fork);
2917    assert(lpstatefork == NULL || !lpstatefork->active || lpstatefork == fork);
2918    assert(subroot == NULL || !subroot->active || subroot == fork);
2919    SCIPdebugMessage("find switch forks: forkdepth=%u\n", fork->depth);
2920 
2921    /* if the common fork node is below the current cutoff depth, the cutoff node is an ancestor of the common fork
2922     * and thus an ancestor of the new focus node, s.t. the new node can also be cut off
2923     */
2924    assert((int)fork->depth != tree->cutoffdepth);
2925    if( (int)fork->depth > tree->cutoffdepth )
2926    {
2927 #ifndef NDEBUG
2928       while( !fork->cutoff )
2929       {
2930          fork = fork->parent;
2931          assert(fork != NULL);
2932       }
2933       assert((int)fork->depth >= tree->cutoffdepth);
2934 #endif
2935       *cutoff = TRUE;
2936       return;
2937    }
2938    tree->cutoffdepth = INT_MAX;
2939 
2940    /* if not already found, continue searching the LP defining fork; it cannot be deeper than the common fork */
2941    if( lpfork == NULL )
2942    {
2943       if( tree->focuslpfork != NULL && (int)(tree->focuslpfork->depth) > fork->depth )
2944       {
2945          /* focuslpfork is not on the same active path as the new node: we have to continue searching */
2946          lpfork = fork;
2947          while( lpfork != NULL
2948             && SCIPnodeGetType(lpfork) != SCIP_NODETYPE_PSEUDOFORK
2949             && SCIPnodeGetType(lpfork) != SCIP_NODETYPE_FORK
2950             && SCIPnodeGetType(lpfork) != SCIP_NODETYPE_SUBROOT )
2951          {
2952             assert(lpfork->active);
2953             lpfork = lpfork->parent;
2954          }
2955       }
2956       else
2957       {
2958          /* focuslpfork is on the same active path as the new node: old and new node have the same lpfork */
2959          lpfork = tree->focuslpfork;
2960       }
2961       assert(lpfork == NULL || (int)(lpfork->depth) <= fork->depth);
2962       assert(lpfork == NULL || lpfork->active);
2963    }
2964    assert(lpfork == NULL
2965       || SCIPnodeGetType(lpfork) == SCIP_NODETYPE_PSEUDOFORK
2966       || SCIPnodeGetType(lpfork) == SCIP_NODETYPE_FORK
2967       || SCIPnodeGetType(lpfork) == SCIP_NODETYPE_SUBROOT);
2968    SCIPdebugMessage("find switch forks: lpforkdepth=%d\n", lpfork == NULL ? -1 : (int)(lpfork->depth));
2969 
2970    /* if not already found, continue searching the LP state defining fork; it cannot be deeper than the
2971     * LP defining fork and the common fork
2972     */
2973    if( lpstatefork == NULL )
2974    {
2975       if( tree->focuslpstatefork != NULL && (int)(tree->focuslpstatefork->depth) > fork->depth )
2976       {
2977          /* focuslpstatefork is not on the same active path as the new node: we have to continue searching */
2978          if( lpfork != NULL && lpfork->depth < fork->depth )
2979             lpstatefork = lpfork;
2980          else
2981             lpstatefork = fork;
2982          while( lpstatefork != NULL
2983             && SCIPnodeGetType(lpstatefork) != SCIP_NODETYPE_FORK
2984             && SCIPnodeGetType(lpstatefork) != SCIP_NODETYPE_SUBROOT )
2985          {
2986             assert(lpstatefork->active);
2987             lpstatefork = lpstatefork->parent;
2988          }
2989       }
2990       else
2991       {
2992          /* focuslpstatefork is on the same active path as the new node: old and new node have the same lpstatefork */
2993          lpstatefork = tree->focuslpstatefork;
2994       }
2995       assert(lpstatefork == NULL || (int)(lpstatefork->depth) <= fork->depth);
2996       assert(lpstatefork == NULL || lpstatefork->active);
2997    }
2998    assert(lpstatefork == NULL
2999       || SCIPnodeGetType(lpstatefork) == SCIP_NODETYPE_FORK
3000       || SCIPnodeGetType(lpstatefork) == SCIP_NODETYPE_SUBROOT);
3001    assert(lpstatefork == NULL || (lpfork != NULL && lpstatefork->depth <= lpfork->depth));
3002    SCIPdebugMessage("find switch forks: lpstateforkdepth=%d\n", lpstatefork == NULL ? -1 : (int)(lpstatefork->depth));
3003 
3004    /* if not already found, continue searching the subroot; it cannot be deeper than the LP defining fork, the
3005     * LP state fork and the common fork
3006     */
3007    if( subroot == NULL )
3008    {
3009       if( tree->focussubroot != NULL && (int)(tree->focussubroot->depth) > fork->depth )
3010       {
3011          /* focussubroot is not on the same active path as the new node: we have to continue searching */
3012          if( lpstatefork != NULL && lpstatefork->depth < fork->depth )
3013             subroot = lpstatefork;
3014          else if( lpfork != NULL && lpfork->depth < fork->depth )
3015             subroot = lpfork;
3016          else
3017             subroot = fork;
3018          while( subroot != NULL && SCIPnodeGetType(subroot) != SCIP_NODETYPE_SUBROOT )
3019          {
3020             assert(subroot->active);
3021             subroot = subroot->parent;
3022          }
3023       }
3024       else
3025          subroot = tree->focussubroot;
3026       assert(subroot == NULL || subroot->depth <= fork->depth);
3027       assert(subroot == NULL || subroot->active);
3028    }
3029    assert(subroot == NULL || SCIPnodeGetType(subroot) == SCIP_NODETYPE_SUBROOT);
3030    assert(subroot == NULL || (lpstatefork != NULL && subroot->depth <= lpstatefork->depth));
3031    SCIPdebugMessage("find switch forks: subrootdepth=%d\n", subroot == NULL ? -1 : (int)(subroot->depth));
3032 
3033    /* if a node prior to the common fork should be repropagated, we select the node to be repropagated as common
3034     * fork in order to undo all bound changes up to this node, repropagate the node, and redo the bound changes
3035     * afterwards
3036     */
3037    if( (int)fork->depth > tree->repropdepth )
3038    {
3039       fork = tree->path[tree->repropdepth];
3040       assert(fork->active);
3041       assert(fork->reprop);
3042    }
3043 
3044    *commonfork = fork;
3045    *newlpfork = lpfork;
3046    *newlpstatefork = lpstatefork;
3047    *newsubroot = subroot;
3048 
3049 #ifndef NDEBUG
3050    while( fork != NULL )
3051    {
3052       assert(fork->active);
3053       assert(!fork->cutoff);
3054       assert(fork->parent == NULL || !fork->parent->reprop);
3055       fork = fork->parent;
3056    }
3057 #endif
3058    tree->repropdepth = INT_MAX;
3059 }
3060 
3061 /** switches the active path to the new focus node, applies domain and constraint set changes */
3062 static
treeSwitchPath(SCIP_TREE * tree,SCIP_REOPT * reopt,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_PRIMAL * primal,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_CONFLICT * conflict,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,SCIP_NODE * fork,SCIP_NODE * focusnode,SCIP_Bool * cutoff)3063 SCIP_RETCODE treeSwitchPath(
3064    SCIP_TREE*            tree,               /**< branch and bound tree */
3065    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
3066    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3067    SCIP_SET*             set,                /**< global SCIP settings */
3068    SCIP_STAT*            stat,               /**< problem statistics */
3069    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
3070    SCIP_PROB*            origprob,           /**< original problem */
3071    SCIP_PRIMAL*          primal,             /**< primal data */
3072    SCIP_LP*              lp,                 /**< current LP data */
3073    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
3074    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
3075    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
3076    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3077    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
3078    SCIP_NODE*            fork,               /**< common fork node of old and new focus node, or NULL */
3079    SCIP_NODE*            focusnode,          /**< new focus node, or NULL */
3080    SCIP_Bool*            cutoff              /**< pointer to store whether the new focus node can be cut off */
3081    )
3082 {
3083    int focusnodedepth;  /* depth of the new focus node, or -1 if focusnode == NULL */
3084    int forkdepth;       /* depth of the common subroot/fork/pseudofork/junction node, or -1 if no common fork exists */
3085    int i;
3086 
3087    assert(tree != NULL);
3088    assert(fork == NULL || (fork->active && !fork->cutoff));
3089    assert(fork == NULL || focusnode != NULL);
3090    assert(focusnode == NULL || (!focusnode->active && !focusnode->cutoff));
3091    assert(focusnode == NULL || SCIPnodeGetType(focusnode) == SCIP_NODETYPE_FOCUSNODE);
3092    assert(cutoff != NULL);
3093 
3094    *cutoff = FALSE;
3095 
3096    SCIPsetDebugMsg(set, "switch path: old pathlen=%d\n", tree->pathlen);
3097 
3098    /* get the nodes' depths */
3099    focusnodedepth = (focusnode != NULL ? (int)focusnode->depth : -1);
3100    forkdepth = (fork != NULL ? (int)fork->depth : -1);
3101    assert(forkdepth <= focusnodedepth);
3102    assert(forkdepth < tree->pathlen);
3103 
3104    /* delay events in path switching */
3105    SCIP_CALL( SCIPeventqueueDelay(eventqueue) );
3106 
3107    /* undo the domain and constraint set changes of the old active path by deactivating the path's nodes */
3108    for( i = tree->pathlen-1; i > forkdepth; --i )
3109    {
3110       SCIP_CALL( nodeDeactivate(tree->path[i], blkmem, set, stat, tree, lp, branchcand, eventfilter, eventqueue) );
3111    }
3112    tree->pathlen = forkdepth+1;
3113 
3114    /* apply the pending bound changes */
3115    SCIP_CALL( treeApplyPendingBdchgs(tree, reopt, blkmem, set, stat, transprob, origprob, lp, branchcand, eventqueue, cliquetable) );
3116 
3117    /* create the new active path */
3118    SCIP_CALL( treeEnsurePathMem(tree, set, focusnodedepth+1) );
3119 
3120    while( focusnode != fork )
3121    {
3122       assert(focusnode != NULL);
3123       assert(!focusnode->active);
3124       assert(!focusnode->cutoff);
3125       /* coverity[var_deref_op] */
3126       tree->path[focusnode->depth] = focusnode;
3127       focusnode = focusnode->parent;
3128    }
3129 
3130    /* fork might be cut off when applying the pending bound changes */
3131    if( fork != NULL && fork->cutoff )
3132       *cutoff = TRUE;
3133    else if( fork != NULL && fork->reprop )
3134    {
3135      /* propagate common fork again, if the reprop flag is set */
3136       assert(tree->path[forkdepth] == fork);
3137       assert(fork->active);
3138       assert(!fork->cutoff);
3139 
3140       SCIP_CALL( nodeRepropagate(fork, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, conflict,
3141             eventfilter, eventqueue, cliquetable, cutoff) );
3142    }
3143    assert(fork != NULL || !(*cutoff));
3144 
3145    /* Apply domain and constraint set changes of the new path by activating the path's nodes;
3146     * on the way, domain propagation might be applied again to the path's nodes, which can result in the cutoff of
3147     * the node (and its subtree).
3148     * We only activate all nodes down to the parent of the new focus node, because the events in this process are
3149     * delayed, which means that multiple changes of a bound of a variable are merged (and might even be cancelled out,
3150     * if the bound is first relaxed when deactivating a node on the old path and then tightened to the same value
3151     * when activating a node on the new path).
3152     * This is valid for all nodes down to the parent of the new focus node, since they have already been propagated.
3153     * Bound change events on the new focus node, however, must not be cancelled out, since they need to be propagated
3154     * and thus, the event must be thrown and catched by the constraint handlers to mark constraints for propagation.
3155     */
3156    for( i = forkdepth+1; i < focusnodedepth && !(*cutoff); ++i )
3157    {
3158       assert(!tree->path[i]->cutoff);
3159       assert(tree->pathlen == i);
3160 
3161       /* activate the node, and apply domain propagation if the reprop flag is set */
3162       tree->pathlen++;
3163       SCIP_CALL( nodeActivate(tree->path[i], blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
3164             conflict, eventfilter, eventqueue, cliquetable, cutoff) );
3165    }
3166 
3167    /* process the delayed events */
3168    SCIP_CALL( SCIPeventqueueProcess(eventqueue, blkmem, set, primal, lp, branchcand, eventfilter) );
3169 
3170    /* activate the new focus node; there is no need to delay these events */
3171    if( !(*cutoff) && (i == focusnodedepth) )
3172    {
3173       assert(!tree->path[focusnodedepth]->cutoff);
3174       assert(tree->pathlen == focusnodedepth);
3175 
3176       /* activate the node, and apply domain propagation if the reprop flag is set */
3177       tree->pathlen++;
3178       SCIP_CALL( nodeActivate(tree->path[focusnodedepth], blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
3179             conflict, eventfilter, eventqueue, cliquetable, cutoff) );
3180    }
3181 
3182    /* mark last node of path to be cut off, if a cutoff was found */
3183    if( *cutoff )
3184    {
3185       assert(tree->pathlen > 0);
3186       assert(tree->path[tree->pathlen-1]->active);
3187       SCIP_CALL( SCIPnodeCutoff(tree->path[tree->pathlen-1], set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
3188    }
3189 
3190    /* count the new LP sizes of the path */
3191    SCIP_CALL( treeUpdatePathLPSize(tree, forkdepth+1) );
3192 
3193    SCIPsetDebugMsg(set, "switch path: new pathlen=%d\n", tree->pathlen);
3194 
3195    return SCIP_OKAY;
3196 }
3197 
3198 /** loads the subroot's LP data */
3199 static
subrootConstructLP(SCIP_NODE * subroot,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter,SCIP_LP * lp)3200 SCIP_RETCODE subrootConstructLP(
3201    SCIP_NODE*            subroot,            /**< subroot node to construct LP for */
3202    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3203    SCIP_SET*             set,                /**< global SCIP settings */
3204    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3205    SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
3206    SCIP_LP*              lp                  /**< current LP data */
3207    )
3208 {
3209    SCIP_COL** cols;
3210    SCIP_ROW** rows;
3211    int ncols;
3212    int nrows;
3213    int c;
3214    int r;
3215 
3216    assert(subroot != NULL);
3217    assert(SCIPnodeGetType(subroot) == SCIP_NODETYPE_SUBROOT);
3218    assert(subroot->data.subroot != NULL);
3219    assert(blkmem != NULL);
3220    assert(set != NULL);
3221    assert(lp != NULL);
3222 
3223    cols = subroot->data.subroot->cols;
3224    rows = subroot->data.subroot->rows;
3225    ncols = subroot->data.subroot->ncols;
3226    nrows = subroot->data.subroot->nrows;
3227 
3228    assert(ncols == 0 || cols != NULL);
3229    assert(nrows == 0 || rows != NULL);
3230 
3231    for( c = 0; c < ncols; ++c )
3232    {
3233       SCIP_CALL( SCIPlpAddCol(lp, set, cols[c], (int) subroot->depth) );
3234    }
3235    for( r = 0; r < nrows; ++r )
3236    {
3237       SCIP_CALL( SCIPlpAddRow(lp, blkmem, set, eventqueue, eventfilter, rows[r], (int) subroot->depth) );
3238    }
3239 
3240    return SCIP_OKAY;
3241 }
3242 
3243 /** loads the fork's additional LP data */
3244 static
forkAddLP(SCIP_NODE * fork,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter,SCIP_LP * lp)3245 SCIP_RETCODE forkAddLP(
3246    SCIP_NODE*            fork,               /**< fork node to construct additional LP for */
3247    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3248    SCIP_SET*             set,                /**< global SCIP settings */
3249    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3250    SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
3251    SCIP_LP*              lp                  /**< current LP data */
3252    )
3253 {
3254    SCIP_COL** cols;
3255    SCIP_ROW** rows;
3256    int ncols;
3257    int nrows;
3258    int c;
3259    int r;
3260 
3261    assert(fork != NULL);
3262    assert(SCIPnodeGetType(fork) == SCIP_NODETYPE_FORK);
3263    assert(fork->data.fork != NULL);
3264    assert(blkmem != NULL);
3265    assert(set != NULL);
3266    assert(lp != NULL);
3267 
3268    cols = fork->data.fork->addedcols;
3269    rows = fork->data.fork->addedrows;
3270    ncols = fork->data.fork->naddedcols;
3271    nrows = fork->data.fork->naddedrows;
3272 
3273    assert(ncols == 0 || cols != NULL);
3274    assert(nrows == 0 || rows != NULL);
3275 
3276    for( c = 0; c < ncols; ++c )
3277    {
3278       SCIP_CALL( SCIPlpAddCol(lp, set, cols[c], (int) fork->depth) );
3279    }
3280    for( r = 0; r < nrows; ++r )
3281    {
3282       SCIP_CALL( SCIPlpAddRow(lp, blkmem, set, eventqueue, eventfilter, rows[r], (int) fork->depth) );
3283    }
3284 
3285    return SCIP_OKAY;
3286 }
3287 
3288 /** loads the pseudofork's additional LP data */
3289 static
pseudoforkAddLP(SCIP_NODE * pseudofork,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter,SCIP_LP * lp)3290 SCIP_RETCODE pseudoforkAddLP(
3291    SCIP_NODE*            pseudofork,         /**< pseudofork node to construct additional LP for */
3292    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3293    SCIP_SET*             set,                /**< global SCIP settings */
3294    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3295    SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
3296    SCIP_LP*              lp                  /**< current LP data */
3297    )
3298 {
3299    SCIP_COL** cols;
3300    SCIP_ROW** rows;
3301    int ncols;
3302    int nrows;
3303    int c;
3304    int r;
3305 
3306    assert(pseudofork != NULL);
3307    assert(SCIPnodeGetType(pseudofork) == SCIP_NODETYPE_PSEUDOFORK);
3308    assert(pseudofork->data.pseudofork != NULL);
3309    assert(blkmem != NULL);
3310    assert(set != NULL);
3311    assert(lp != NULL);
3312 
3313    cols = pseudofork->data.pseudofork->addedcols;
3314    rows = pseudofork->data.pseudofork->addedrows;
3315    ncols = pseudofork->data.pseudofork->naddedcols;
3316    nrows = pseudofork->data.pseudofork->naddedrows;
3317 
3318    assert(ncols == 0 || cols != NULL);
3319    assert(nrows == 0 || rows != NULL);
3320 
3321    for( c = 0; c < ncols; ++c )
3322    {
3323       SCIP_CALL( SCIPlpAddCol(lp, set, cols[c], (int) pseudofork->depth) );
3324    }
3325    for( r = 0; r < nrows; ++r )
3326    {
3327       SCIP_CALL( SCIPlpAddRow(lp, blkmem, set, eventqueue, eventfilter, rows[r], (int) pseudofork->depth) );
3328    }
3329 
3330    return SCIP_OKAY;
3331 }
3332 
3333 #ifndef NDEBUG
3334 /** checks validity of active path */
3335 static
treeCheckPath(SCIP_TREE * tree)3336 void treeCheckPath(
3337    SCIP_TREE*            tree                /**< branch and bound tree */
3338    )
3339 {
3340    SCIP_NODE* node;
3341    int ncols;
3342    int nrows;
3343    int d;
3344 
3345    assert(tree != NULL);
3346    assert(tree->path != NULL);
3347 
3348    ncols = 0;
3349    nrows = 0;
3350    for( d = 0; d < tree->pathlen; ++d )
3351    {
3352       node = tree->path[d];
3353       assert(node != NULL);
3354       assert((int)(node->depth) == d);
3355       switch( SCIPnodeGetType(node) )
3356       {
3357       case SCIP_NODETYPE_PROBINGNODE:
3358          assert(SCIPtreeProbing(tree));
3359          assert(d >= 1);
3360          assert(SCIPnodeGetType(tree->path[d-1]) == SCIP_NODETYPE_FOCUSNODE
3361             || (ncols == node->data.probingnode->ninitialcols && nrows == node->data.probingnode->ninitialrows));
3362          assert(ncols <= node->data.probingnode->ncols || !tree->focuslpconstructed);
3363          assert(nrows <= node->data.probingnode->nrows || !tree->focuslpconstructed);
3364          if( d < tree->pathlen-1 )
3365          {
3366             ncols = node->data.probingnode->ncols;
3367             nrows = node->data.probingnode->nrows;
3368          }
3369          else
3370          {
3371             /* for the current probing node, the initial LP size is stored in the path */
3372             ncols = node->data.probingnode->ninitialcols;
3373             nrows = node->data.probingnode->ninitialrows;
3374          }
3375          break;
3376       case SCIP_NODETYPE_JUNCTION:
3377          break;
3378       case SCIP_NODETYPE_PSEUDOFORK:
3379          ncols += node->data.pseudofork->naddedcols;
3380          nrows += node->data.pseudofork->naddedrows;
3381          break;
3382       case SCIP_NODETYPE_FORK:
3383          ncols += node->data.fork->naddedcols;
3384          nrows += node->data.fork->naddedrows;
3385          break;
3386       case SCIP_NODETYPE_SUBROOT:
3387          ncols = node->data.subroot->ncols;
3388          nrows = node->data.subroot->nrows;
3389          break;
3390       case SCIP_NODETYPE_FOCUSNODE:
3391       case SCIP_NODETYPE_REFOCUSNODE:
3392          assert(d == tree->pathlen-1 || SCIPtreeProbing(tree));
3393          break;
3394       default:
3395          SCIPerrorMessage("node at depth %d on active path has to be of type JUNCTION, PSEUDOFORK, FORK, SUBROOT, FOCUSNODE, REFOCUSNODE, or PROBINGNODE, but is %d\n",
3396             d, SCIPnodeGetType(node));
3397          SCIPABORT();
3398       }  /*lint !e788*/
3399       assert(tree->pathnlpcols[d] == ncols);
3400       assert(tree->pathnlprows[d] == nrows);
3401    }
3402 }
3403 #else
3404 #define treeCheckPath(tree) /**/
3405 #endif
3406 
3407 /** constructs the LP relaxation of the focus node */
SCIPtreeLoadLP(SCIP_TREE * tree,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter,SCIP_LP * lp,SCIP_Bool * initroot)3408 SCIP_RETCODE SCIPtreeLoadLP(
3409    SCIP_TREE*            tree,               /**< branch and bound tree */
3410    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3411    SCIP_SET*             set,                /**< global SCIP settings */
3412    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3413    SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
3414    SCIP_LP*              lp,                 /**< current LP data */
3415    SCIP_Bool*            initroot            /**< pointer to store whether the root LP relaxation has to be initialized */
3416    )
3417 {
3418    SCIP_NODE* lpfork;
3419    int lpforkdepth;
3420    int d;
3421 
3422    assert(tree != NULL);
3423    assert(!tree->focuslpconstructed);
3424    assert(tree->path != NULL);
3425    assert(tree->pathlen > 0);
3426    assert(tree->focusnode != NULL);
3427    assert(SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_FOCUSNODE);
3428    assert(SCIPnodeGetDepth(tree->focusnode) == tree->pathlen-1);
3429    assert(!SCIPtreeProbing(tree));
3430    assert(tree->focusnode == tree->path[tree->pathlen-1]);
3431    assert(blkmem != NULL);
3432    assert(set != NULL);
3433    assert(lp != NULL);
3434    assert(initroot != NULL);
3435 
3436    SCIPsetDebugMsg(set, "load LP for current fork node #%" SCIP_LONGINT_FORMAT " at depth %d\n",
3437       tree->focuslpfork == NULL ? -1 : SCIPnodeGetNumber(tree->focuslpfork),
3438       tree->focuslpfork == NULL ? -1 : SCIPnodeGetDepth(tree->focuslpfork));
3439    SCIPsetDebugMsg(set, "-> old LP has %d cols and %d rows\n", SCIPlpGetNCols(lp), SCIPlpGetNRows(lp));
3440    SCIPsetDebugMsg(set, "-> correct LP has %d cols and %d rows\n",
3441       tree->correctlpdepth >= 0 ? tree->pathnlpcols[tree->correctlpdepth] : 0,
3442       tree->correctlpdepth >= 0 ? tree->pathnlprows[tree->correctlpdepth] : 0);
3443    SCIPsetDebugMsg(set, "-> old correctlpdepth: %d\n", tree->correctlpdepth);
3444 
3445    treeCheckPath(tree);
3446 
3447    lpfork = tree->focuslpfork;
3448 
3449    /* find out the lpfork's depth (or -1, if lpfork is NULL) */
3450    if( lpfork == NULL )
3451    {
3452       assert(tree->correctlpdepth == -1 || tree->pathnlpcols[tree->correctlpdepth] == 0);
3453       assert(tree->correctlpdepth == -1 || tree->pathnlprows[tree->correctlpdepth] == 0);
3454       assert(tree->focuslpstatefork == NULL);
3455       assert(tree->focussubroot == NULL);
3456       lpforkdepth = -1;
3457    }
3458    else
3459    {
3460       assert(SCIPnodeGetType(lpfork) == SCIP_NODETYPE_PSEUDOFORK
3461          || SCIPnodeGetType(lpfork) == SCIP_NODETYPE_FORK || SCIPnodeGetType(lpfork) == SCIP_NODETYPE_SUBROOT);
3462       assert(lpfork->active);
3463       assert(tree->path[lpfork->depth] == lpfork);
3464       lpforkdepth = (int) lpfork->depth;
3465    }
3466    assert(lpforkdepth < tree->pathlen-1); /* lpfork must not be the last (the focus) node of the active path */
3467 
3468    /* find out, if we are in the same subtree */
3469    if( tree->correctlpdepth >= 0 )
3470    {
3471       /* same subtree: shrink LP to the deepest node with correct LP */
3472       assert(lpforkdepth == -1 || tree->pathnlpcols[tree->correctlpdepth] <= tree->pathnlpcols[lpforkdepth]);
3473       assert(lpforkdepth == -1 || tree->pathnlprows[tree->correctlpdepth] <= tree->pathnlprows[lpforkdepth]);
3474       assert(lpforkdepth >= 0 || tree->pathnlpcols[tree->correctlpdepth] == 0);
3475       assert(lpforkdepth >= 0 || tree->pathnlprows[tree->correctlpdepth] == 0);
3476       SCIP_CALL( SCIPlpShrinkCols(lp, set, tree->pathnlpcols[tree->correctlpdepth]) );
3477       SCIP_CALL( SCIPlpShrinkRows(lp, blkmem, set, eventqueue, eventfilter, tree->pathnlprows[tree->correctlpdepth]) );
3478    }
3479    else
3480    {
3481       /* other subtree: fill LP with the subroot LP data */
3482       SCIP_CALL( SCIPlpClear(lp, blkmem, set, eventqueue, eventfilter) );
3483       if( tree->focussubroot != NULL )
3484       {
3485          SCIP_CALL( subrootConstructLP(tree->focussubroot, blkmem, set, eventqueue, eventfilter, lp) );
3486          tree->correctlpdepth = (int) tree->focussubroot->depth;
3487       }
3488    }
3489 
3490    assert(lpforkdepth < tree->pathlen);
3491 
3492    /* add the missing columns and rows */
3493    for( d = tree->correctlpdepth+1; d <= lpforkdepth; ++d )
3494    {
3495       SCIP_NODE* pathnode;
3496 
3497       pathnode = tree->path[d];
3498       assert(pathnode != NULL);
3499       assert((int)(pathnode->depth) == d);
3500       assert(SCIPnodeGetType(pathnode) == SCIP_NODETYPE_JUNCTION
3501          || SCIPnodeGetType(pathnode) == SCIP_NODETYPE_PSEUDOFORK
3502          || SCIPnodeGetType(pathnode) == SCIP_NODETYPE_FORK);
3503       if( SCIPnodeGetType(pathnode) == SCIP_NODETYPE_FORK )
3504       {
3505          SCIP_CALL( forkAddLP(pathnode, blkmem, set, eventqueue, eventfilter, lp) );
3506       }
3507       else if( SCIPnodeGetType(pathnode) == SCIP_NODETYPE_PSEUDOFORK )
3508       {
3509          SCIP_CALL( pseudoforkAddLP(pathnode, blkmem, set, eventqueue, eventfilter, lp) );
3510       }
3511    }
3512    tree->correctlpdepth = MAX(tree->correctlpdepth, lpforkdepth);
3513    assert(lpforkdepth == -1 || tree->pathnlpcols[tree->correctlpdepth] == tree->pathnlpcols[lpforkdepth]);
3514    assert(lpforkdepth == -1 || tree->pathnlprows[tree->correctlpdepth] == tree->pathnlprows[lpforkdepth]);
3515    assert(lpforkdepth == -1 || SCIPlpGetNCols(lp) == tree->pathnlpcols[lpforkdepth]);
3516    assert(lpforkdepth == -1 || SCIPlpGetNRows(lp) == tree->pathnlprows[lpforkdepth]);
3517    assert(lpforkdepth >= 0 || SCIPlpGetNCols(lp) == 0);
3518    assert(lpforkdepth >= 0 || SCIPlpGetNRows(lp) == 0);
3519 
3520    /* mark the LP's size, such that we know which rows and columns were added in the new node */
3521    SCIPlpMarkSize(lp);
3522 
3523    SCIPsetDebugMsg(set, "-> new correctlpdepth: %d\n", tree->correctlpdepth);
3524    SCIPsetDebugMsg(set, "-> new LP has %d cols and %d rows\n", SCIPlpGetNCols(lp), SCIPlpGetNRows(lp));
3525 
3526    /* if the correct LP depth is still -1, the root LP relaxation has to be initialized */
3527    *initroot = (tree->correctlpdepth == -1);
3528 
3529    /* mark the LP of the focus node constructed */
3530    tree->focuslpconstructed = TRUE;
3531 
3532    return SCIP_OKAY;
3533 }
3534 
3535 /** loads LP state for fork/subroot of the focus node */
SCIPtreeLoadLPState(SCIP_TREE * tree,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp)3536 SCIP_RETCODE SCIPtreeLoadLPState(
3537    SCIP_TREE*            tree,               /**< branch and bound tree */
3538    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3539    SCIP_SET*             set,                /**< global SCIP settings */
3540    SCIP_STAT*            stat,               /**< dynamic problem statistics */
3541    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3542    SCIP_LP*              lp                  /**< current LP data */
3543    )
3544 {
3545    SCIP_NODE* lpstatefork;
3546    SCIP_Bool updatefeas;
3547    SCIP_Bool checkbdchgs;
3548    int lpstateforkdepth;
3549    int d;
3550 
3551    assert(tree != NULL);
3552    assert(tree->focuslpconstructed);
3553    assert(tree->path != NULL);
3554    assert(tree->pathlen > 0);
3555    assert(tree->focusnode != NULL);
3556    assert(tree->correctlpdepth < tree->pathlen);
3557    assert(SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_FOCUSNODE);
3558    assert(SCIPnodeGetDepth(tree->focusnode) == tree->pathlen-1);
3559    assert(!SCIPtreeProbing(tree));
3560    assert(tree->focusnode == tree->path[tree->pathlen-1]);
3561    assert(blkmem != NULL);
3562    assert(set != NULL);
3563    assert(lp != NULL);
3564 
3565    SCIPsetDebugMsg(set, "load LP state for current fork node #%" SCIP_LONGINT_FORMAT " at depth %d\n",
3566       tree->focuslpstatefork == NULL ? -1 : SCIPnodeGetNumber(tree->focuslpstatefork),
3567       tree->focuslpstatefork == NULL ? -1 : SCIPnodeGetDepth(tree->focuslpstatefork));
3568 
3569    lpstatefork = tree->focuslpstatefork;
3570 
3571    /* if there is no LP state defining fork, nothing can be done */
3572    if( lpstatefork == NULL )
3573       return SCIP_OKAY;
3574 
3575    /* get the lpstatefork's depth */
3576    assert(SCIPnodeGetType(lpstatefork) == SCIP_NODETYPE_FORK || SCIPnodeGetType(lpstatefork) == SCIP_NODETYPE_SUBROOT);
3577    assert(lpstatefork->active);
3578    assert(tree->path[lpstatefork->depth] == lpstatefork);
3579    lpstateforkdepth = (int) lpstatefork->depth;
3580    assert(lpstateforkdepth < tree->pathlen-1); /* lpstatefork must not be the last (the focus) node of the active path */
3581    assert(lpstateforkdepth <= tree->correctlpdepth); /* LP must have been constructed at least up to the fork depth */
3582    assert(tree->pathnlpcols[tree->correctlpdepth] >= tree->pathnlpcols[lpstateforkdepth]); /* LP can only grow */
3583    assert(tree->pathnlprows[tree->correctlpdepth] >= tree->pathnlprows[lpstateforkdepth]); /* LP can only grow */
3584 
3585    /* load LP state */
3586    if( tree->focuslpstateforklpcount != stat->lpcount )
3587    {
3588       if( SCIPnodeGetType(lpstatefork) == SCIP_NODETYPE_FORK )
3589       {
3590          assert(lpstatefork->data.fork != NULL);
3591          SCIP_CALL( SCIPlpSetState(lp, blkmem, set, eventqueue, lpstatefork->data.fork->lpistate,
3592                lpstatefork->data.fork->lpwasprimfeas, lpstatefork->data.fork->lpwasprimchecked,
3593                lpstatefork->data.fork->lpwasdualfeas, lpstatefork->data.fork->lpwasdualchecked) );
3594       }
3595       else
3596       {
3597          assert(SCIPnodeGetType(lpstatefork) == SCIP_NODETYPE_SUBROOT);
3598          assert(lpstatefork->data.subroot != NULL);
3599          SCIP_CALL( SCIPlpSetState(lp, blkmem, set, eventqueue, lpstatefork->data.subroot->lpistate,
3600                lpstatefork->data.subroot->lpwasprimfeas, lpstatefork->data.subroot->lpwasprimchecked,
3601                lpstatefork->data.subroot->lpwasdualfeas, lpstatefork->data.subroot->lpwasdualchecked) );
3602       }
3603       updatefeas = !lp->solved || !lp->solisbasic;
3604       checkbdchgs = TRUE;
3605    }
3606    else
3607    {
3608       updatefeas = TRUE;
3609 
3610       /* we do not need to check the bounds, since primalfeasible is updated anyway when flushing the LP */
3611       checkbdchgs = FALSE;
3612    }
3613 
3614    if( updatefeas )
3615    {
3616       /* check whether the size of the LP increased (destroying primal/dual feasibility) */
3617       lp->primalfeasible = lp->primalfeasible
3618          && (tree->pathnlprows[tree->correctlpdepth] == tree->pathnlprows[lpstateforkdepth]);
3619       lp->primalchecked = lp->primalchecked
3620          && (tree->pathnlprows[tree->correctlpdepth] == tree->pathnlprows[lpstateforkdepth]);
3621       lp->dualfeasible = lp->dualfeasible
3622          && (tree->pathnlpcols[tree->correctlpdepth] == tree->pathnlpcols[lpstateforkdepth]);
3623       lp->dualchecked = lp->dualchecked
3624          && (tree->pathnlpcols[tree->correctlpdepth] == tree->pathnlpcols[lpstateforkdepth]);
3625 
3626       /* check the path from LP fork to focus node for domain changes (destroying primal feasibility of LP basis) */
3627       if( checkbdchgs )
3628       {
3629          for( d = lpstateforkdepth; d < (int)(tree->focusnode->depth) && lp->primalfeasible; ++d )
3630          {
3631             assert(d < tree->pathlen);
3632             lp->primalfeasible = (tree->path[d]->domchg == NULL || tree->path[d]->domchg->domchgbound.nboundchgs == 0);
3633             lp->primalchecked = lp->primalfeasible;
3634          }
3635       }
3636    }
3637 
3638    SCIPsetDebugMsg(set, "-> primalfeasible=%u, dualfeasible=%u\n", lp->primalfeasible, lp->dualfeasible);
3639 
3640    return SCIP_OKAY;
3641 }
3642 
3643 
3644 
3645 
3646 /*
3647  * Node Conversion
3648  */
3649 
3650 /** converts node into LEAF and moves it into the array of the node queue
3651  *  if node's lower bound is greater or equal than the given upper bound, the node is deleted;
3652  *  otherwise, it is moved to the node queue; anyways, the given pointer is NULL after the call
3653  */
3654 static
nodeToLeaf(SCIP_NODE ** node,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_NODE * lpstatefork,SCIP_Real cutoffbound)3655 SCIP_RETCODE nodeToLeaf(
3656    SCIP_NODE**           node,               /**< pointer to child or sibling node to convert */
3657    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3658    SCIP_SET*             set,                /**< global SCIP settings */
3659    SCIP_STAT*            stat,               /**< dynamic problem statistics */
3660    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
3661    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3662    SCIP_TREE*            tree,               /**< branch and bound tree */
3663    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
3664    SCIP_LP*              lp,                 /**< current LP data */
3665    SCIP_NODE*            lpstatefork,        /**< LP state defining fork of the node */
3666    SCIP_Real             cutoffbound         /**< cutoff bound: all nodes with lowerbound >= cutoffbound are cut off */
3667    )
3668 {
3669    assert(SCIPnodeGetType(*node) == SCIP_NODETYPE_SIBLING || SCIPnodeGetType(*node) == SCIP_NODETYPE_CHILD
3670       || SCIPnodeGetType(*node) == SCIP_NODETYPE_FOCUSNODE);
3671    assert(stat != NULL);
3672    assert(lpstatefork == NULL || lpstatefork->depth < (*node)->depth);
3673    assert(lpstatefork == NULL || lpstatefork->active || SCIPsetIsGE(set, (*node)->lowerbound, cutoffbound));
3674    assert(lpstatefork == NULL
3675       || SCIPnodeGetType(lpstatefork) == SCIP_NODETYPE_FORK
3676       || SCIPnodeGetType(lpstatefork) == SCIP_NODETYPE_SUBROOT);
3677 
3678    /* convert node into leaf */
3679    SCIPsetDebugMsg(set, "convert node #%" SCIP_LONGINT_FORMAT " at depth %d to leaf with lpstatefork #%" SCIP_LONGINT_FORMAT " at depth %d\n",
3680       SCIPnodeGetNumber(*node), SCIPnodeGetDepth(*node),
3681       lpstatefork == NULL ? -1 : SCIPnodeGetNumber(lpstatefork),
3682       lpstatefork == NULL ? -1 : SCIPnodeGetDepth(lpstatefork));
3683    (*node)->nodetype = SCIP_NODETYPE_LEAF; /*lint !e641*/
3684    (*node)->data.leaf.lpstatefork = lpstatefork;
3685 
3686 #ifndef NDEBUG
3687    /* check, if the LP state fork is the first node with LP state information on the path back to the root */
3688    if( !SCIPsetIsInfinity(set, -cutoffbound) ) /* if the node was cut off in SCIPnodeFocus(), the lpstatefork is invalid */
3689    {
3690       SCIP_NODE* pathnode;
3691       pathnode = (*node)->parent;
3692       while( pathnode != NULL && pathnode != lpstatefork )
3693       {
3694          assert(SCIPnodeGetType(pathnode) == SCIP_NODETYPE_JUNCTION
3695             || SCIPnodeGetType(pathnode) == SCIP_NODETYPE_PSEUDOFORK);
3696          pathnode = pathnode->parent;
3697       }
3698       assert(pathnode == lpstatefork);
3699    }
3700 #endif
3701 
3702    /* if node is good enough to keep, put it on the node queue */
3703    if( SCIPsetIsLT(set, (*node)->lowerbound, cutoffbound) )
3704    {
3705       /* insert leaf in node queue */
3706       SCIP_CALL( SCIPnodepqInsert(tree->leaves, set, *node) );
3707 
3708       /* make the domain change data static to save memory */
3709       SCIP_CALL( SCIPdomchgMakeStatic(&(*node)->domchg, blkmem, set, eventqueue, lp) );
3710 
3711       /* node is now member of the node queue: delete the pointer to forbid further access */
3712       *node = NULL;
3713    }
3714    else
3715    {
3716       if( set->reopt_enable )
3717       {
3718          assert(reopt != NULL);
3719          /* check if the node should be stored for reoptimization */
3720          SCIP_CALL( SCIPreoptCheckCutoff(reopt, set, blkmem, *node, SCIP_EVENTTYPE_NODEINFEASIBLE, lp, SCIPlpGetSolstat(lp),
3721                tree->root == *node, tree->focusnode == *node, (*node)->lowerbound, tree->effectiverootdepth) );
3722       }
3723 
3724       /* delete node due to bound cut off */
3725       SCIPvisualCutoffNode(stat->visual, set, stat, *node, FALSE);
3726       SCIP_CALL( SCIPnodeFree(node, blkmem, set, stat, eventfilter, eventqueue, tree, lp) );
3727    }
3728    assert(*node == NULL);
3729 
3730    return SCIP_OKAY;
3731 }
3732 
3733 /** removes variables from the problem, that are marked to be deletable, and were created at the focusnode;
3734  *  only removes variables that were created at the focusnode, unless inlp is TRUE (e.g., when the node is cut off, anyway)
3735  */
3736 static
focusnodeCleanupVars(BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_CLIQUETABLE * cliquetable,SCIP_Bool inlp)3737 SCIP_RETCODE focusnodeCleanupVars(
3738    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3739    SCIP_SET*             set,                /**< global SCIP settings */
3740    SCIP_STAT*            stat,               /**< dynamic problem statistics */
3741    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3742    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
3743    SCIP_PROB*            origprob,           /**< original problem */
3744    SCIP_TREE*            tree,               /**< branch and bound tree */
3745    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
3746    SCIP_LP*              lp,                 /**< current LP data */
3747    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
3748    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
3749    SCIP_Bool             inlp                /**< should variables in the LP be deleted, too?*/
3750    )
3751 {
3752    SCIP_VAR* var;
3753    int i;
3754    int ndelvars;
3755    SCIP_Bool needdel;
3756    SCIP_Bool deleted;
3757 
3758    assert(blkmem != NULL);
3759    assert(set != NULL);
3760    assert(stat != NULL);
3761    assert(tree != NULL);
3762    assert(!SCIPtreeProbing(tree));
3763    assert(tree->focusnode != NULL);
3764    assert(SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_FOCUSNODE);
3765    assert(lp != NULL);
3766 
3767    /* check the settings, whether variables should be deleted */
3768    needdel = (tree->focusnode == tree->root ? set->price_delvarsroot : set->price_delvars);
3769 
3770    if( !needdel )
3771       return SCIP_OKAY;
3772 
3773    ndelvars = 0;
3774 
3775    /* also delete variables currently in the LP, thus remove all new variables from the LP, first */
3776    if( inlp )
3777    {
3778       /* remove all additions to the LP at this node */
3779       SCIP_CALL( SCIPlpShrinkCols(lp, set, SCIPlpGetNCols(lp) - SCIPlpGetNNewcols(lp)) );
3780 
3781       SCIP_CALL( SCIPlpFlush(lp, blkmem, set, eventqueue) );
3782    }
3783 
3784    /* mark variables as deleted */
3785    for( i = 0; i < transprob->nvars; i++ )
3786    {
3787       var = transprob->vars[i];
3788       assert(var != NULL);
3789 
3790       /* check whether variable is deletable */
3791       if( SCIPvarIsDeletable(var) )
3792       {
3793          if( !SCIPvarIsInLP(var) )
3794          {
3795             /* fix the variable to 0, first */
3796             assert(!SCIPsetIsFeasPositive(set, SCIPvarGetLbGlobal(var)));
3797             assert(!SCIPsetIsFeasNegative(set, SCIPvarGetUbGlobal(var)));
3798 
3799             if( !SCIPsetIsFeasZero(set, SCIPvarGetLbGlobal(var)) )
3800             {
3801                SCIP_CALL( SCIPnodeAddBoundchg(tree->root, blkmem, set, stat, transprob, origprob,
3802                      tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 0.0, SCIP_BOUNDTYPE_LOWER, FALSE) );
3803             }
3804             if( !SCIPsetIsFeasZero(set, SCIPvarGetUbGlobal(var)) )
3805             {
3806                SCIP_CALL( SCIPnodeAddBoundchg(tree->root, blkmem, set, stat, transprob, origprob,
3807                      tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 0.0, SCIP_BOUNDTYPE_UPPER, FALSE) );
3808             }
3809 
3810             SCIP_CALL( SCIPprobDelVar(transprob, blkmem, set, eventqueue, var, &deleted) );
3811 
3812             if( deleted )
3813                ndelvars++;
3814          }
3815          else
3816          {
3817             /* mark variable to be non-deletable, because it will be contained in the basis information
3818              * at this node and must not be deleted from now on
3819              */
3820             SCIPvarMarkNotDeletable(var);
3821          }
3822       }
3823    }
3824 
3825    SCIPsetDebugMsg(set, "delvars at node %" SCIP_LONGINT_FORMAT ", deleted %d vars\n", stat->nnodes, ndelvars);
3826 
3827    if( ndelvars > 0 )
3828    {
3829       /* perform the variable deletions from the problem */
3830       SCIP_CALL( SCIPprobPerformVarDeletions(transprob, blkmem, set, stat, eventqueue, cliquetable, lp, branchcand) );
3831    }
3832 
3833    return SCIP_OKAY;
3834 }
3835 
3836 /** converts the focus node into a dead-end node */
3837 static
focusnodeToDeadend(BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_CLIQUETABLE * cliquetable)3838 SCIP_RETCODE focusnodeToDeadend(
3839    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3840    SCIP_SET*             set,                /**< global SCIP settings */
3841    SCIP_STAT*            stat,               /**< dynamic problem statistics */
3842    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3843    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
3844    SCIP_PROB*            origprob,           /**< original problem */
3845    SCIP_TREE*            tree,               /**< branch and bound tree */
3846    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
3847    SCIP_LP*              lp,                 /**< current LP data */
3848    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
3849    SCIP_CLIQUETABLE*     cliquetable         /**< clique table data structure */
3850    )
3851 {
3852    assert(blkmem != NULL);
3853    assert(tree != NULL);
3854    assert(!SCIPtreeProbing(tree));
3855    assert(tree->focusnode != NULL);
3856    assert(SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_FOCUSNODE);
3857    assert(tree->nchildren == 0);
3858 
3859    SCIPsetDebugMsg(set, "focusnode #%" SCIP_LONGINT_FORMAT " to dead-end at depth %d\n",
3860       SCIPnodeGetNumber(tree->focusnode), SCIPnodeGetDepth(tree->focusnode));
3861 
3862    /* remove variables from the problem that are marked as deletable and were created at this node */
3863    SCIP_CALL( focusnodeCleanupVars(blkmem, set, stat, eventqueue, transprob, origprob, tree, reopt, lp, branchcand, cliquetable, TRUE) );
3864 
3865    tree->focusnode->nodetype = SCIP_NODETYPE_DEADEND; /*lint !e641*/
3866 
3867    /* release LPI state */
3868    if( tree->focuslpstatefork != NULL )
3869    {
3870       SCIP_CALL( SCIPnodeReleaseLPIState(tree->focuslpstatefork, blkmem, lp) );
3871    }
3872 
3873    return SCIP_OKAY;
3874 }
3875 
3876 /** converts the focus node into a leaf node (if it was postponed) */
3877 static
focusnodeToLeaf(BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_NODE * lpstatefork,SCIP_Real cutoffbound)3878 SCIP_RETCODE focusnodeToLeaf(
3879    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3880    SCIP_SET*             set,                /**< global SCIP settings */
3881    SCIP_STAT*            stat,               /**< dynamic problem statistics */
3882    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
3883    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3884    SCIP_TREE*            tree,               /**< branch and bound tree */
3885    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
3886    SCIP_LP*              lp,                 /**< current LP data */
3887    SCIP_NODE*            lpstatefork,        /**< LP state defining fork of the node */
3888    SCIP_Real             cutoffbound         /**< cutoff bound: all nodes with lowerbound >= cutoffbound are cut off */
3889 
3890    )
3891 {
3892    assert(tree != NULL);
3893    assert(!SCIPtreeProbing(tree));
3894    assert(tree->focusnode != NULL);
3895    assert(tree->focusnode->active);
3896    assert(SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_FOCUSNODE);
3897 
3898    SCIPsetDebugMsg(set, "focusnode #%" SCIP_LONGINT_FORMAT " to leaf at depth %d\n",
3899       SCIPnodeGetNumber(tree->focusnode), SCIPnodeGetDepth(tree->focusnode));
3900 
3901    SCIP_CALL( nodeToLeaf(&tree->focusnode, blkmem, set, stat, eventfilter, eventqueue, tree, reopt, lp, lpstatefork, cutoffbound));
3902 
3903    return SCIP_OKAY;
3904 }
3905 
3906 /** converts the focus node into a junction node */
3907 static
focusnodeToJunction(BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_TREE * tree,SCIP_LP * lp)3908 SCIP_RETCODE focusnodeToJunction(
3909    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3910    SCIP_SET*             set,                /**< global SCIP settings */
3911    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3912    SCIP_TREE*            tree,               /**< branch and bound tree */
3913    SCIP_LP*              lp                  /**< current LP data */
3914    )
3915 {
3916    assert(tree != NULL);
3917    assert(!SCIPtreeProbing(tree));
3918    assert(tree->focusnode != NULL);
3919    assert(tree->focusnode->active); /* otherwise, no children could be created at the focus node */
3920    assert(SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_FOCUSNODE);
3921    assert(SCIPlpGetNNewcols(lp) == 0);
3922 
3923    SCIPsetDebugMsg(set, "focusnode #%" SCIP_LONGINT_FORMAT " to junction at depth %d\n",
3924       SCIPnodeGetNumber(tree->focusnode), SCIPnodeGetDepth(tree->focusnode));
3925 
3926    /* convert node into junction */
3927    tree->focusnode->nodetype = SCIP_NODETYPE_JUNCTION; /*lint !e641*/
3928 
3929    SCIP_CALL( junctionInit(&tree->focusnode->data.junction, tree) );
3930 
3931    /* release LPI state */
3932    if( tree->focuslpstatefork != NULL )
3933    {
3934       SCIP_CALL( SCIPnodeReleaseLPIState(tree->focuslpstatefork, blkmem, lp) );
3935    }
3936 
3937    /* make the domain change data static to save memory */
3938    SCIP_CALL( SCIPdomchgMakeStatic(&tree->focusnode->domchg, blkmem, set, eventqueue, lp) );
3939 
3940    return SCIP_OKAY;
3941 }
3942 
3943 /** converts the focus node into a pseudofork node */
3944 static
focusnodeToPseudofork(BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_CLIQUETABLE * cliquetable)3945 SCIP_RETCODE focusnodeToPseudofork(
3946    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3947    SCIP_SET*             set,                /**< global SCIP settings */
3948    SCIP_STAT*            stat,               /**< dynamic problem statistics */
3949    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
3950    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
3951    SCIP_PROB*            origprob,           /**< original problem */
3952    SCIP_TREE*            tree,               /**< branch and bound tree */
3953    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
3954    SCIP_LP*              lp,                 /**< current LP data */
3955    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
3956    SCIP_CLIQUETABLE*     cliquetable         /**< clique table data structure */
3957    )
3958 {
3959    SCIP_PSEUDOFORK* pseudofork;
3960 
3961    assert(blkmem != NULL);
3962    assert(tree != NULL);
3963    assert(!SCIPtreeProbing(tree));
3964    assert(tree->focusnode != NULL);
3965    assert(tree->focusnode->active); /* otherwise, no children could be created at the focus node */
3966    assert(SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_FOCUSNODE);
3967    assert(tree->nchildren > 0);
3968    assert(lp != NULL);
3969 
3970    SCIPsetDebugMsg(set, "focusnode #%" SCIP_LONGINT_FORMAT " to pseudofork at depth %d\n",
3971       SCIPnodeGetNumber(tree->focusnode), SCIPnodeGetDepth(tree->focusnode));
3972 
3973    /* remove variables from the problem that are marked as deletable and were created at this node */
3974    SCIP_CALL( focusnodeCleanupVars(blkmem, set, stat, eventqueue, transprob, origprob, tree, reopt, lp, branchcand, cliquetable, FALSE) );
3975 
3976    /* create pseudofork data */
3977    SCIP_CALL( pseudoforkCreate(&pseudofork, blkmem, tree, lp) );
3978 
3979    tree->focusnode->nodetype = SCIP_NODETYPE_PSEUDOFORK; /*lint !e641*/
3980    tree->focusnode->data.pseudofork = pseudofork;
3981 
3982    /* release LPI state */
3983    if( tree->focuslpstatefork != NULL )
3984    {
3985       SCIP_CALL( SCIPnodeReleaseLPIState(tree->focuslpstatefork, blkmem, lp) );
3986    }
3987 
3988    /* make the domain change data static to save memory */
3989    SCIP_CALL( SCIPdomchgMakeStatic(&tree->focusnode->domchg, blkmem, set, eventqueue, lp) );
3990 
3991    return SCIP_OKAY;
3992 }
3993 
3994 /** converts the focus node into a fork node */
3995 static
focusnodeToFork(BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_CLIQUETABLE * cliquetable)3996 SCIP_RETCODE focusnodeToFork(
3997    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
3998    SCIP_SET*             set,                /**< global SCIP settings */
3999    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
4000    SCIP_STAT*            stat,               /**< dynamic problem statistics */
4001    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
4002    SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
4003    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
4004    SCIP_PROB*            origprob,           /**< original problem */
4005    SCIP_TREE*            tree,               /**< branch and bound tree */
4006    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
4007    SCIP_LP*              lp,                 /**< current LP data */
4008    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
4009    SCIP_CLIQUETABLE*     cliquetable         /**< clique table data structure */
4010    )
4011 {
4012    SCIP_FORK* fork;
4013    SCIP_Bool lperror;
4014 
4015    assert(blkmem != NULL);
4016    assert(tree != NULL);
4017    assert(!SCIPtreeProbing(tree));
4018    assert(tree->focusnode != NULL);
4019    assert(tree->focusnode->active); /* otherwise, no children could be created at the focus node */
4020    assert(SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_FOCUSNODE);
4021    assert(tree->nchildren > 0);
4022    assert(lp != NULL);
4023    assert(lp->flushed);
4024    assert(lp->solved || lp->resolvelperror);
4025 
4026    SCIPsetDebugMsg(set, "focusnode #%" SCIP_LONGINT_FORMAT " to fork at depth %d\n",
4027       SCIPnodeGetNumber(tree->focusnode), SCIPnodeGetDepth(tree->focusnode));
4028 
4029    /* usually, the LP should be solved to optimality; otherwise, numerical troubles occured,
4030     * and we have to forget about the LP and transform the node into a junction (see below)
4031     */
4032    lperror = FALSE;
4033    if( !lp->resolvelperror && SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL )
4034    {
4035       /* clean up newly created part of LP to keep only necessary columns and rows */
4036       SCIP_CALL( SCIPlpCleanupNew(lp, blkmem, set, stat, eventqueue, eventfilter, (tree->focusnode->depth == 0)) );
4037 
4038       /* resolve LP after cleaning up */
4039       if( !lp->solved || !lp->flushed )
4040       {
4041          SCIPsetDebugMsg(set, "resolving LP after cleanup\n");
4042          SCIP_CALL( SCIPlpSolveAndEval(lp, set, messagehdlr, blkmem, stat, eventqueue, eventfilter, transprob, -1LL, FALSE, FALSE, TRUE, &lperror) );
4043       }
4044    }
4045    assert(lp->flushed);
4046    assert(lp->solved || lperror || lp->resolvelperror);
4047 
4048    /* There are two reasons, that the (reduced) LP is not solved to optimality:
4049     *  - The primal heuristics (called after the current node's LP was solved) found a new
4050     *    solution, that is better than the current node's lower bound.
4051     *    (But in this case, all children should be cut off and the node should be converted
4052     *    into a dead-end instead of a fork.)
4053     *  - Something numerically weird happened after cleaning up or after resolving a diving or probing LP.
4054     * The only thing we can do, is to completely forget about the LP and treat the node as
4055     * if it was only a pseudo-solution node. Therefore we have to remove all additional
4056     * columns and rows from the LP and convert the node into a junction.
4057     * However, the node's lower bound is kept, thus automatically throwing away nodes that
4058     * were cut off due to a primal solution.
4059     */
4060    if( lperror || lp->resolvelperror || SCIPlpGetSolstat(lp) != SCIP_LPSOLSTAT_OPTIMAL )
4061    {
4062       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
4063          "(node %" SCIP_LONGINT_FORMAT ") numerical troubles: LP %" SCIP_LONGINT_FORMAT " not optimal -- convert node into junction instead of fork\n",
4064          stat->nnodes, stat->nlps);
4065 
4066       /* remove all additions to the LP at this node */
4067       SCIP_CALL( SCIPlpShrinkCols(lp, set, SCIPlpGetNCols(lp) - SCIPlpGetNNewcols(lp)) );
4068       SCIP_CALL( SCIPlpShrinkRows(lp, blkmem, set, eventqueue, eventfilter, SCIPlpGetNRows(lp) - SCIPlpGetNNewrows(lp)) );
4069 
4070       /* convert node into a junction */
4071       SCIP_CALL( focusnodeToJunction(blkmem, set, eventqueue, tree, lp) );
4072 
4073       return SCIP_OKAY;
4074    }
4075    assert(lp->flushed);
4076    assert(lp->solved);
4077    assert(SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL);
4078 
4079    /* remove variables from the problem that are marked as deletable, were created at this node and are not contained in the LP */
4080    SCIP_CALL( focusnodeCleanupVars(blkmem, set, stat, eventqueue, transprob, origprob, tree, reopt, lp, branchcand, cliquetable, FALSE) );
4081 
4082    assert(lp->flushed);
4083    assert(lp->solved);
4084 
4085    /* create fork data */
4086    SCIP_CALL( forkCreate(&fork, blkmem, set, transprob, tree, lp) );
4087 
4088    tree->focusnode->nodetype = SCIP_NODETYPE_FORK; /*lint !e641*/
4089    tree->focusnode->data.fork = fork;
4090 
4091    /* capture the LPI state of the root node to ensure that the LPI state of the root stays for the whole solving
4092     * process
4093     */
4094    if( tree->focusnode == tree->root )
4095       forkCaptureLPIState(fork, 1);
4096 
4097    /* release LPI state */
4098    if( tree->focuslpstatefork != NULL )
4099    {
4100       SCIP_CALL( SCIPnodeReleaseLPIState(tree->focuslpstatefork, blkmem, lp) );
4101    }
4102 
4103    /* make the domain change data static to save memory */
4104    SCIP_CALL( SCIPdomchgMakeStatic(&tree->focusnode->domchg, blkmem, set, eventqueue, lp) );
4105 
4106    return SCIP_OKAY;
4107 }
4108 
4109 #ifdef WITHSUBROOTS  /** @todo test whether subroots should be created */
4110 /** converts the focus node into a subroot node */
4111 static
focusnodeToSubroot(BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_TREE * tree,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_CLIQUETABLE * cliquetable)4112 SCIP_RETCODE focusnodeToSubroot(
4113    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4114    SCIP_SET*             set,                /**< global SCIP settings */
4115    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
4116    SCIP_STAT*            stat,               /**< dynamic problem statistics */
4117    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
4118    SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
4119    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
4120    SCIP_PROB*            origprob,           /**< original problem */
4121    SCIP_TREE*            tree,               /**< branch and bound tree */
4122    SCIP_LP*              lp,                 /**< current LP data */
4123    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
4124    SCIP_CLIQUETABLE*     cliquetable         /**< clique table data structure */
4125    )
4126 {
4127    SCIP_SUBROOT* subroot;
4128    SCIP_Bool lperror;
4129 
4130    assert(blkmem != NULL);
4131    assert(tree != NULL);
4132    assert(!SCIPtreeProbing(tree));
4133    assert(tree->focusnode != NULL);
4134    assert(SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_FOCUSNODE);
4135    assert(tree->focusnode->active); /* otherwise, no children could be created at the focus node */
4136    assert(tree->nchildren > 0);
4137    assert(lp != NULL);
4138    assert(lp->flushed);
4139    assert(lp->solved);
4140 
4141    SCIPsetDebugMsg(set, "focusnode #%" SCIP_LONGINT_FORMAT " to subroot at depth %d\n",
4142       SCIPnodeGetNumber(tree->focusnode), SCIPnodeGetDepth(tree->focusnode));
4143 
4144    /* usually, the LP should be solved to optimality; otherwise, numerical troubles occured,
4145     * and we have to forget about the LP and transform the node into a junction (see below)
4146     */
4147    lperror = FALSE;
4148    if( SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL )
4149    {
4150       /* clean up whole LP to keep only necessary columns and rows */
4151 #ifdef SCIP_DISABLED_CODE
4152       if( tree->focusnode->depth == 0 )
4153       {
4154          SCIP_CALL( SCIPlpCleanupAll(lp, blkmem, set, stat, eventqueue, eventfilter, (tree->focusnode->depth == 0)) );
4155       }
4156       else
4157 #endif
4158       {
4159          SCIP_CALL( SCIPlpRemoveAllObsoletes(lp, blkmem, set, stat, eventqueue, eventfilter) );
4160       }
4161 
4162       /* resolve LP after cleaning up */
4163       if( !lp->solved || !lp->flushed )
4164       {
4165          SCIPsetDebugMsg(set, "resolving LP after cleanup\n");
4166          SCIP_CALL( SCIPlpSolveAndEval(lp, set, messagehdlr, blkmem, stat, eventqueue, eventfilter, transprob, -1LL, FALSE, FALSE, TRUE, &lperror) );
4167       }
4168    }
4169    assert(lp->flushed);
4170    assert(lp->solved || lperror);
4171 
4172    /* There are two reasons, that the (reduced) LP is not solved to optimality:
4173     *  - The primal heuristics (called after the current node's LP was solved) found a new
4174     *    solution, that is better than the current node's lower bound.
4175     *    (But in this case, all children should be cut off and the node should be converted
4176     *    into a dead-end instead of a subroot.)
4177     *  - Something numerically weird happened after cleaning up.
4178     * The only thing we can do, is to completely forget about the LP and treat the node as
4179     * if it was only a pseudo-solution node. Therefore we have to remove all additional
4180     * columns and rows from the LP and convert the node into a junction.
4181     * However, the node's lower bound is kept, thus automatically throwing away nodes that
4182     * were cut off due to a primal solution.
4183     */
4184    if( lperror || SCIPlpGetSolstat(lp) != SCIP_LPSOLSTAT_OPTIMAL )
4185    {
4186       SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
4187          "(node %" SCIP_LONGINT_FORMAT ") numerical troubles: LP %" SCIP_LONGINT_FORMAT " not optimal -- convert node into junction instead of subroot\n",
4188          stat->nnodes, stat->nlps);
4189 
4190       /* remove all additions to the LP at this node */
4191       SCIP_CALL( SCIPlpShrinkCols(lp, set, SCIPlpGetNCols(lp) - SCIPlpGetNNewcols(lp)) );
4192       SCIP_CALL( SCIPlpShrinkRows(lp, blkmem, set, eventqueue, eventfilter, SCIPlpGetNRows(lp) - SCIPlpGetNNewrows(lp)) );
4193 
4194       /* convert node into a junction */
4195       SCIP_CALL( focusnodeToJunction(blkmem, set, eventqueue, tree, lp) );
4196 
4197       return SCIP_OKAY;
4198    }
4199    assert(lp->flushed);
4200    assert(lp->solved);
4201    assert(SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL);
4202 
4203    /* remove variables from the problem that are marked as deletable, were created at this node and are not contained in the LP */
4204    SCIP_CALL( focusnodeCleanupVars(blkmem, set, stat, eventqueue, transprob, origprob, tree, lp, branchcand, cliquetable, FALSE) );
4205 
4206    assert(lp->flushed);
4207    assert(lp->solved);
4208 
4209    /* create subroot data */
4210    SCIP_CALL( subrootCreate(&subroot, blkmem, set, transprob, tree, lp) );
4211 
4212    tree->focusnode->nodetype = SCIP_NODETYPE_SUBROOT; /*lint !e641*/
4213    tree->focusnode->data.subroot = subroot;
4214 
4215    /* update the LP column and row counter for the converted node */
4216    SCIP_CALL( treeUpdatePathLPSize(tree, tree->focusnode->depth) );
4217 
4218    /* release LPI state */
4219    if( tree->focuslpstatefork != NULL )
4220    {
4221       SCIP_CALL( SCIPnodeReleaseLPIState(tree->focuslpstatefork, blkmem, lp) );
4222    }
4223 
4224    /* make the domain change data static to save memory */
4225    SCIP_CALL( SCIPdomchgMakeStatic(&tree->focusnode->domchg, blkmem, set, eventqueue, lp) );
4226 
4227    return SCIP_OKAY;
4228 }
4229 #endif
4230 
4231 /** puts all nodes in the array on the node queue and makes them LEAFs */
4232 static
treeNodesToQueue(SCIP_TREE * tree,SCIP_REOPT * reopt,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_NODE ** nodes,int * nnodes,SCIP_NODE * lpstatefork,SCIP_Real cutoffbound)4233 SCIP_RETCODE treeNodesToQueue(
4234    SCIP_TREE*            tree,               /**< branch and bound tree */
4235    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
4236    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4237    SCIP_SET*             set,                /**< global SCIP settings */
4238    SCIP_STAT*            stat,               /**< dynamic problem statistics */
4239    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
4240    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
4241    SCIP_LP*              lp,                 /**< current LP data */
4242    SCIP_NODE**           nodes,              /**< array of nodes to put on the queue */
4243    int*                  nnodes,             /**< pointer to number of nodes in the array */
4244    SCIP_NODE*            lpstatefork,        /**< LP state defining fork of the nodes */
4245    SCIP_Real             cutoffbound         /**< cutoff bound: all nodes with lowerbound >= cutoffbound are cut off */
4246    )
4247 {
4248    int i;
4249 
4250    assert(tree != NULL);
4251    assert(set != NULL);
4252    assert(nnodes != NULL);
4253    assert(*nnodes == 0 || nodes != NULL);
4254 
4255    for( i = *nnodes; --i >= 0; )
4256    {
4257       /* convert node to LEAF and put it into leaves queue, or delete it if it's lower bound exceeds the cutoff bound */
4258       SCIP_CALL( nodeToLeaf(&nodes[i], blkmem, set, stat, eventfilter, eventqueue, tree, reopt, lp, lpstatefork, cutoffbound) );
4259       assert(nodes[i] == NULL);
4260       --(*nnodes);
4261    }
4262 
4263    return SCIP_OKAY;
4264 }
4265 
4266 /** converts children into siblings, clears children array */
4267 static
treeChildrenToSiblings(SCIP_TREE * tree)4268 void treeChildrenToSiblings(
4269    SCIP_TREE*            tree                /**< branch and bound tree */
4270    )
4271 {
4272    SCIP_NODE** tmpnodes;
4273    SCIP_Real* tmpprios;
4274    int tmpnodessize;
4275    int i;
4276 
4277    assert(tree != NULL);
4278    assert(tree->nsiblings == 0);
4279 
4280    tmpnodes = tree->siblings;
4281    tmpprios = tree->siblingsprio;
4282    tmpnodessize = tree->siblingssize;
4283 
4284    tree->siblings = tree->children;
4285    tree->siblingsprio = tree->childrenprio;
4286    tree->nsiblings = tree->nchildren;
4287    tree->siblingssize = tree->childrensize;
4288 
4289    tree->children = tmpnodes;
4290    tree->childrenprio = tmpprios;
4291    tree->nchildren = 0;
4292    tree->childrensize = tmpnodessize;
4293 
4294    for( i = 0; i < tree->nsiblings; ++i )
4295    {
4296       assert(SCIPnodeGetType(tree->siblings[i]) == SCIP_NODETYPE_CHILD);
4297       tree->siblings[i]->nodetype = SCIP_NODETYPE_SIBLING; /*lint !e641*/
4298 
4299       /* because CHILD and SIBLING structs contain the same data in the same order, we do not have to copy it */
4300       assert(&(tree->siblings[i]->data.sibling.arraypos) == &(tree->siblings[i]->data.child.arraypos));
4301    }
4302 }
4303 
4304 /** installs a child, a sibling, or a leaf node as the new focus node */
SCIPnodeFocus(SCIP_NODE ** node,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_PRIMAL * primal,SCIP_TREE * tree,SCIP_REOPT * reopt,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_CONFLICT * conflict,SCIP_CONFLICTSTORE * conflictstore,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable,SCIP_Bool * cutoff,SCIP_Bool postponed,SCIP_Bool exitsolve)4305 SCIP_RETCODE SCIPnodeFocus(
4306    SCIP_NODE**           node,               /**< pointer to node to focus (or NULL to remove focus); the node
4307                                               *   is freed, if it was cut off due to a cut off subtree */
4308    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4309    SCIP_SET*             set,                /**< global SCIP settings */
4310    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
4311    SCIP_STAT*            stat,               /**< problem statistics */
4312    SCIP_PROB*            transprob,          /**< transformed problem */
4313    SCIP_PROB*            origprob,           /**< original problem */
4314    SCIP_PRIMAL*          primal,             /**< primal data */
4315    SCIP_TREE*            tree,               /**< branch and bound tree */
4316    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
4317    SCIP_LP*              lp,                 /**< current LP data */
4318    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
4319    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
4320    SCIP_CONFLICTSTORE*   conflictstore,      /**< conflict store */
4321    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
4322    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
4323    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
4324    SCIP_Bool*            cutoff,             /**< pointer to store whether the given node can be cut off */
4325    SCIP_Bool             postponed,          /**< was the current focus node postponed? */
4326    SCIP_Bool             exitsolve           /**< are we in exitsolve stage, so we only need to loose the children */
4327    )
4328 {  /*lint --e{715}*/
4329    SCIP_NODE* oldfocusnode;
4330    SCIP_NODE* fork;
4331    SCIP_NODE* lpfork;
4332    SCIP_NODE* lpstatefork;
4333    SCIP_NODE* subroot;
4334    SCIP_NODE* childrenlpstatefork;
4335    int oldcutoffdepth;
4336 
4337    assert(node != NULL);
4338    assert(*node == NULL
4339       || SCIPnodeGetType(*node) == SCIP_NODETYPE_SIBLING
4340       || SCIPnodeGetType(*node) == SCIP_NODETYPE_CHILD
4341       || SCIPnodeGetType(*node) == SCIP_NODETYPE_LEAF);
4342    assert(*node == NULL || !(*node)->active);
4343    assert(stat != NULL);
4344    assert(tree != NULL);
4345    assert(!SCIPtreeProbing(tree));
4346    assert(lp != NULL);
4347    assert(conflictstore != NULL);
4348    assert(cutoff != NULL);
4349 
4350    /* check global lower bound w.r.t. debugging solution */
4351    SCIP_CALL( SCIPdebugCheckGlobalLowerbound(blkmem, set) );
4352 
4353    /* check local lower bound w.r.t. debugging solution */
4354    SCIP_CALL( SCIPdebugCheckLocalLowerbound(blkmem, set, *node) );
4355 
4356    SCIPsetDebugMsg(set, "focusing node #%" SCIP_LONGINT_FORMAT " of type %d in depth %d\n",
4357       *node != NULL ? SCIPnodeGetNumber(*node) : -1, *node != NULL ? (int)SCIPnodeGetType(*node) : 0,
4358       *node != NULL ? SCIPnodeGetDepth(*node) : -1);
4359 
4360    /* remember old cutoff depth in order to know, whether the children and siblings can be deleted */
4361    oldcutoffdepth = tree->cutoffdepth;
4362 
4363    /* find the common fork node, the new LP defining fork, and the new focus subroot,
4364     * thereby checking, if the new node can be cut off
4365     */
4366    treeFindSwitchForks(tree, *node, &fork, &lpfork, &lpstatefork, &subroot, cutoff);
4367    SCIPsetDebugMsg(set, "focus node: focusnodedepth=%d, forkdepth=%d, lpforkdepth=%d, lpstateforkdepth=%d, subrootdepth=%d, cutoff=%u\n",
4368       *node != NULL ? (*node)->depth : -1, fork != NULL ? fork->depth : -1, /*lint !e705 */
4369       lpfork != NULL ? lpfork->depth : -1, lpstatefork != NULL ? lpstatefork->depth : -1, /*lint !e705 */
4370       subroot != NULL ? subroot->depth : -1, *cutoff); /*lint !e705 */
4371 
4372    /* free the new node, if it is located in a cut off subtree */
4373    if( *cutoff )
4374    {
4375       assert(*node != NULL);
4376       assert(tree->cutoffdepth == oldcutoffdepth);
4377       if( SCIPnodeGetType(*node) == SCIP_NODETYPE_LEAF )
4378       {
4379          SCIP_CALL( SCIPnodepqRemove(tree->leaves, set, *node) );
4380       }
4381       SCIPvisualCutoffNode(stat->visual, set, stat, *node, FALSE);
4382 
4383       if( set->reopt_enable )
4384       {
4385          assert(reopt != NULL);
4386          /* check if the node should be stored for reoptimization */
4387          SCIP_CALL( SCIPreoptCheckCutoff(reopt, set, blkmem, *node, SCIP_EVENTTYPE_NODEINFEASIBLE, lp, SCIPlpGetSolstat(lp),
4388                tree->root == (*node), tree->focusnode == (*node), (*node)->lowerbound, tree->effectiverootdepth) );
4389       }
4390 
4391       SCIP_CALL( SCIPnodeFree(node, blkmem, set, stat, eventfilter, eventqueue, tree, lp) );
4392 
4393       return SCIP_OKAY;
4394    }
4395 
4396    assert(tree->cutoffdepth == INT_MAX);
4397    assert(fork == NULL || fork->active);
4398    assert(lpstatefork == NULL || lpfork != NULL);
4399    assert(subroot == NULL || lpstatefork != NULL);
4400 
4401    /* remember the depth of the common fork node for LP updates */
4402    SCIPsetDebugMsg(set, "focus node: old correctlpdepth=%d\n", tree->correctlpdepth);
4403    if( subroot == tree->focussubroot && fork != NULL && lpfork != NULL )
4404    {
4405       /* we are in the same subtree with valid LP fork: the LP is correct at most upto the common fork depth */
4406       assert(subroot == NULL || subroot->active);
4407       tree->correctlpdepth = MIN(tree->correctlpdepth, (int)fork->depth);
4408    }
4409    else
4410    {
4411       /* we are in a different subtree, or no valid LP fork exists: the LP is completely incorrect */
4412       assert(subroot == NULL || !subroot->active
4413          || (tree->focussubroot != NULL && (int)(tree->focussubroot->depth) > subroot->depth));
4414       tree->correctlpdepth = -1;
4415    }
4416 
4417    /* if the LP state fork changed, the lpcount information for the new LP state fork is unknown */
4418    if( lpstatefork != tree->focuslpstatefork )
4419       tree->focuslpstateforklpcount = -1;
4420 
4421    /* in exitsolve we only need to take care of open children
4422     *
4423     * @note because we might do a 'newstart' and converted cuts to constraints might have rendered the LP in the current
4424     *       focusnode unsolved the latter code would have resolved the LP unnecessarily
4425     */
4426    if( exitsolve && tree->nchildren > 0 )
4427    {
4428       SCIPsetDebugMsg(set, " -> deleting the %d children (in exitsolve) of the old focus node\n", tree->nchildren);
4429       SCIP_CALL( treeNodesToQueue(tree, reopt, blkmem, set, stat, eventfilter, eventqueue, lp, tree->children, &tree->nchildren, NULL, -SCIPsetInfinity(set)) );
4430       assert(tree->nchildren == 0);
4431    }
4432 
4433    /* if the old focus node was cut off, we can delete its children;
4434     * if the old focus node's parent was cut off, we can also delete the focus node's siblings
4435     */
4436    /* coverity[var_compare_op] */
4437    if( tree->focusnode != NULL && oldcutoffdepth <= (int)tree->focusnode->depth )
4438    {
4439       SCIPsetDebugMsg(set, "path to old focus node of depth %u was cut off at depth %d\n", tree->focusnode->depth, oldcutoffdepth);
4440 
4441       /* delete the focus node's children by converting them to leaves with a cutoffbound of -SCIPsetInfinity(set);
4442        * we cannot delete them directly, because in SCIPnodeFree(), the children array is changed, which is the
4443        * same array we would have to iterate over here;
4444        * the children don't have an LP fork, because the old focus node is not yet converted into a fork or subroot
4445        */
4446       SCIPsetDebugMsg(set, " -> deleting the %d children of the old focus node\n", tree->nchildren);
4447       SCIP_CALL( treeNodesToQueue(tree, reopt, blkmem, set, stat, eventfilter, eventqueue, lp, tree->children, &tree->nchildren, NULL, -SCIPsetInfinity(set)) );
4448       assert(tree->nchildren == 0);
4449 
4450       if( oldcutoffdepth < (int)tree->focusnode->depth )
4451       {
4452          /* delete the focus node's siblings by converting them to leaves with a cutoffbound of -SCIPsetInfinity(set);
4453           * we cannot delete them directly, because in SCIPnodeFree(), the siblings array is changed, which is the
4454           * same array we would have to iterate over here;
4455           * the siblings have the same LP state fork as the old focus node
4456           */
4457          SCIPsetDebugMsg(set, " -> deleting the %d siblings of the old focus node\n", tree->nsiblings);
4458          SCIP_CALL( treeNodesToQueue(tree, reopt, blkmem, set, stat, eventfilter, eventqueue, lp, tree->siblings, &tree->nsiblings, tree->focuslpstatefork,
4459                -SCIPsetInfinity(set)) );
4460          assert(tree->nsiblings == 0);
4461       }
4462    }
4463 
4464    /* convert the old focus node into a fork or subroot node, if it has children;
4465     * otherwise, convert it into a dead-end, which will be freed later in treeSwitchPath();
4466     * if the node was postponed, make it a leaf.
4467     */
4468    childrenlpstatefork = tree->focuslpstatefork;
4469 
4470    assert(!postponed || *node == NULL);
4471    assert(!postponed || tree->focusnode != NULL);
4472 
4473    if( postponed )
4474    {
4475       assert(tree->nchildren == 0);
4476       assert(*node == NULL);
4477 
4478       /* if the node is infeasible, convert it into a deadend; otherwise, put it into the LEAF queue */
4479       if( SCIPsetIsGE(set, tree->focusnode->lowerbound, primal->cutoffbound) )
4480       {
4481          /* in case the LP was not constructed (due to the parameter settings for example) we have the finally remember the
4482           * old size of the LP (if it was constructed in an earlier node) before we change the current node into a deadend
4483           */
4484          if( !tree->focuslpconstructed )
4485             SCIPlpMarkSize(lp);
4486 
4487          /* convert old focus node into deadend */
4488          SCIP_CALL( focusnodeToDeadend(blkmem, set, stat, eventqueue, transprob, origprob, tree, reopt, lp, branchcand,
4489                cliquetable) );
4490       }
4491       else
4492       {
4493          SCIP_CALL( focusnodeToLeaf(blkmem, set, stat, eventfilter, eventqueue, tree, reopt, lp, tree->focuslpstatefork,
4494                SCIPsetInfinity(set)) );
4495       }
4496    }
4497    else if( tree->nchildren > 0 )
4498    {
4499       SCIP_Bool selectedchild;
4500 
4501       assert(tree->focusnode != NULL);
4502       assert(SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_FOCUSNODE);
4503       assert(oldcutoffdepth == INT_MAX);
4504 
4505       /* check whether the next focus node is a child of the old focus node */
4506       selectedchild = (*node != NULL && SCIPnodeGetType(*node) == SCIP_NODETYPE_CHILD);
4507 
4508       if( tree->focusnodehaslp && lp->isrelax )
4509       {
4510          assert(tree->focuslpconstructed);
4511 
4512 #ifdef WITHSUBROOTS  /** @todo test whether subroots should be created, decide: old focus node becomes fork or subroot */
4513          if( tree->focusnode->depth > 0 && tree->focusnode->depth % 25 == 0 )
4514          {
4515             /* convert old focus node into a subroot node */
4516             SCIP_CALL( focusnodeToSubroot(blkmem, set, messagehdlr, stat, eventqueue, eventfilter, transprob, origprob, tree, lp, branchcand) );
4517             if( *node != NULL && SCIPnodeGetType(*node) == SCIP_NODETYPE_CHILD
4518                && SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_SUBROOT )
4519                subroot = tree->focusnode;
4520          }
4521          else
4522 #endif
4523          {
4524             /* convert old focus node into a fork node */
4525             SCIP_CALL( focusnodeToFork(blkmem, set, messagehdlr, stat, eventqueue, eventfilter, transprob, origprob, tree,
4526                   reopt, lp, branchcand, cliquetable) );
4527          }
4528 
4529          /* check, if the conversion into a subroot or fork was successful */
4530          if( SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_FORK
4531             || SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_SUBROOT )
4532          {
4533             childrenlpstatefork = tree->focusnode;
4534 
4535             /* if a child of the old focus node was selected as new focus node, the old node becomes the new focus
4536              * LP fork and LP state fork
4537              */
4538             if( selectedchild )
4539             {
4540                lpfork = tree->focusnode;
4541                tree->correctlpdepth = (int) tree->focusnode->depth;
4542                lpstatefork = tree->focusnode;
4543                tree->focuslpstateforklpcount = stat->lpcount;
4544             }
4545          }
4546 
4547          /* update the path's LP size */
4548          tree->pathnlpcols[tree->focusnode->depth] = SCIPlpGetNCols(lp);
4549          tree->pathnlprows[tree->focusnode->depth] = SCIPlpGetNRows(lp);
4550       }
4551       else if( tree->focuslpconstructed && (SCIPlpGetNNewcols(lp) > 0 || SCIPlpGetNNewrows(lp) > 0) )
4552       {
4553          /* convert old focus node into pseudofork */
4554          SCIP_CALL( focusnodeToPseudofork(blkmem, set, stat, eventqueue, transprob, origprob, tree, reopt, lp,
4555                branchcand, cliquetable) );
4556          assert(SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_PSEUDOFORK);
4557 
4558          /* update the path's LP size */
4559          tree->pathnlpcols[tree->focusnode->depth] = SCIPlpGetNCols(lp);
4560          tree->pathnlprows[tree->focusnode->depth] = SCIPlpGetNRows(lp);
4561 
4562          /* if a child of the old focus node was selected as new focus node, the old node becomes the new focus LP fork */
4563          if( selectedchild )
4564          {
4565             lpfork = tree->focusnode;
4566             tree->correctlpdepth = (int) tree->focusnode->depth;
4567          }
4568       }
4569       else
4570       {
4571          /* in case the LP was not constructed (due to the parameter settings for example) we have the finally remember the
4572           * old size of the LP (if it was constructed in an earlier node) before we change the current node into a junction
4573           */
4574          SCIPlpMarkSize(lp);
4575 
4576          /* convert old focus node into junction */
4577          SCIP_CALL( focusnodeToJunction(blkmem, set, eventqueue, tree, lp) );
4578       }
4579    }
4580    else if( tree->focusnode != NULL )
4581    {
4582       /* in case the LP was not constructed (due to the parameter settings for example) we have the finally remember the
4583        * old size of the LP (if it was constructed in an earlier node) before we change the current node into a deadend
4584        */
4585       if( !tree->focuslpconstructed )
4586          SCIPlpMarkSize(lp);
4587 
4588       /* convert old focus node into deadend */
4589       SCIP_CALL( focusnodeToDeadend(blkmem, set, stat, eventqueue, transprob, origprob, tree, reopt, lp, branchcand, cliquetable) );
4590    }
4591    assert(subroot == NULL || SCIPnodeGetType(subroot) == SCIP_NODETYPE_SUBROOT);
4592    assert(lpstatefork == NULL
4593       || SCIPnodeGetType(lpstatefork) == SCIP_NODETYPE_SUBROOT
4594       || SCIPnodeGetType(lpstatefork) == SCIP_NODETYPE_FORK);
4595    assert(childrenlpstatefork == NULL
4596       || SCIPnodeGetType(childrenlpstatefork) == SCIP_NODETYPE_SUBROOT
4597       || SCIPnodeGetType(childrenlpstatefork) == SCIP_NODETYPE_FORK);
4598    assert(lpfork == NULL
4599       || SCIPnodeGetType(lpfork) == SCIP_NODETYPE_SUBROOT
4600       || SCIPnodeGetType(lpfork) == SCIP_NODETYPE_FORK
4601       || SCIPnodeGetType(lpfork) == SCIP_NODETYPE_PSEUDOFORK);
4602    SCIPsetDebugMsg(set, "focus node: new correctlpdepth=%d\n", tree->correctlpdepth);
4603 
4604    /* set up the new lists of siblings and children */
4605    oldfocusnode = tree->focusnode;
4606    if( *node == NULL )
4607    {
4608       /* move siblings to the queue, make them LEAFs */
4609       SCIP_CALL( treeNodesToQueue(tree, reopt, blkmem, set, stat, eventfilter, eventqueue, lp, tree->siblings, &tree->nsiblings, tree->focuslpstatefork,
4610             primal->cutoffbound) );
4611 
4612       /* move children to the queue, make them LEAFs */
4613       SCIP_CALL( treeNodesToQueue(tree, reopt, blkmem, set, stat, eventfilter, eventqueue, lp, tree->children, &tree->nchildren, childrenlpstatefork,
4614             primal->cutoffbound) );
4615    }
4616    else
4617    {
4618       SCIP_NODE* bestleaf;
4619 
4620       switch( SCIPnodeGetType(*node) )
4621       {
4622       case SCIP_NODETYPE_SIBLING:
4623          /* reset plunging depth, if the selected node is better than all leaves */
4624          bestleaf = SCIPtreeGetBestLeaf(tree);
4625          if( bestleaf == NULL || SCIPnodepqCompare(tree->leaves, set, *node, bestleaf) <= 0 )
4626             stat->plungedepth = 0;
4627 
4628          /* move children to the queue, make them LEAFs */
4629          SCIP_CALL( treeNodesToQueue(tree, reopt, blkmem, set, stat, eventfilter, eventqueue, lp, tree->children, &tree->nchildren, childrenlpstatefork,
4630                primal->cutoffbound) );
4631 
4632          /* remove selected sibling from the siblings array */
4633          treeRemoveSibling(tree, *node);
4634 
4635          SCIPsetDebugMsg(set, "selected sibling node, lowerbound=%g, plungedepth=%d\n", (*node)->lowerbound, stat->plungedepth);
4636          break;
4637 
4638       case SCIP_NODETYPE_CHILD:
4639          /* reset plunging depth, if the selected node is better than all leaves; otherwise, increase plunging depth */
4640          bestleaf = SCIPtreeGetBestLeaf(tree);
4641          if( bestleaf == NULL || SCIPnodepqCompare(tree->leaves, set, *node, bestleaf) <= 0 )
4642             stat->plungedepth = 0;
4643          else
4644             stat->plungedepth++;
4645 
4646          /* move siblings to the queue, make them LEAFs */
4647          SCIP_CALL( treeNodesToQueue(tree, reopt, blkmem, set, stat, eventfilter, eventqueue, lp, tree->siblings, &tree->nsiblings, tree->focuslpstatefork,
4648                primal->cutoffbound) );
4649 
4650          /* remove selected child from the children array */
4651          treeRemoveChild(tree, *node);
4652 
4653          /* move remaining children to the siblings array, make them SIBLINGs */
4654          treeChildrenToSiblings(tree);
4655 
4656          SCIPsetDebugMsg(set, "selected child node, lowerbound=%g, plungedepth=%d\n", (*node)->lowerbound, stat->plungedepth);
4657          break;
4658 
4659       case SCIP_NODETYPE_LEAF:
4660          /* move siblings to the queue, make them LEAFs */
4661          SCIP_CALL( treeNodesToQueue(tree, reopt, blkmem, set, stat, eventfilter, eventqueue, lp, tree->siblings, &tree->nsiblings, tree->focuslpstatefork,
4662                primal->cutoffbound) );
4663 
4664          /* encounter an early backtrack if there is a child which does not exceed given reference bound */
4665          if( !SCIPsetIsInfinity(set, stat->referencebound) )
4666          {
4667             int c;
4668 
4669             /* loop over children and stop if we find a child with a lower bound below given reference bound */
4670             for( c = 0; c < tree->nchildren; ++c )
4671             {
4672                if( SCIPsetIsLT(set, SCIPnodeGetLowerbound(tree->children[c]), stat->referencebound) )
4673                {
4674                   ++stat->nearlybacktracks;
4675                   break;
4676                }
4677             }
4678          }
4679          /* move children to the queue, make them LEAFs */
4680          SCIP_CALL( treeNodesToQueue(tree, reopt, blkmem, set, stat, eventfilter, eventqueue, lp, tree->children, &tree->nchildren, childrenlpstatefork,
4681                primal->cutoffbound) );
4682 
4683          /* remove node from the queue */
4684          SCIP_CALL( SCIPnodepqRemove(tree->leaves, set, *node) );
4685 
4686          stat->plungedepth = 0;
4687          if( SCIPnodeGetDepth(*node) > 0 )
4688             stat->nbacktracks++;
4689          SCIPsetDebugMsg(set, "selected leaf node, lowerbound=%g, plungedepth=%d\n", (*node)->lowerbound, stat->plungedepth);
4690          break;
4691 
4692       default:
4693          SCIPerrorMessage("selected node is neither sibling, child, nor leaf (nodetype=%d)\n", SCIPnodeGetType(*node));
4694          return SCIP_INVALIDDATA;
4695       }  /*lint !e788*/
4696 
4697       /* convert node into the focus node */
4698       (*node)->nodetype = SCIP_NODETYPE_FOCUSNODE; /*lint !e641*/
4699    }
4700    assert(tree->nchildren == 0);
4701 
4702    /* set new focus node, LP fork, LP state fork, and subroot */
4703    assert(subroot == NULL || (lpstatefork != NULL && subroot->depth <= lpstatefork->depth));
4704    assert(lpstatefork == NULL || (lpfork != NULL && lpstatefork->depth <= lpfork->depth));
4705    assert(lpfork == NULL || (*node != NULL && lpfork->depth < (*node)->depth));
4706    tree->focusnode = *node;
4707    tree->focuslpfork = lpfork;
4708    tree->focuslpstatefork = lpstatefork;
4709    tree->focussubroot = subroot;
4710    tree->focuslpconstructed = FALSE;
4711    lp->resolvelperror = FALSE;
4712 
4713    /* track the path from the old focus node to the new node, and perform domain and constraint set changes */
4714    SCIP_CALL( treeSwitchPath(tree, reopt, blkmem, set, stat, transprob, origprob, primal, lp, branchcand, conflict,
4715          eventfilter, eventqueue, cliquetable, fork, *node, cutoff) );
4716    assert(tree->pathlen >= 0);
4717    assert(*node != NULL || tree->pathlen == 0);
4718    assert(*node == NULL || tree->pathlen-1 <= (int)(*node)->depth);
4719 
4720    /* if the old focus node is a dead end (has no children), delete it */
4721    if( oldfocusnode != NULL && SCIPnodeGetType(oldfocusnode) == SCIP_NODETYPE_DEADEND )
4722    {
4723       int appliedeffectiverootdepth;
4724 
4725       appliedeffectiverootdepth = tree->appliedeffectiverootdepth;
4726       assert(appliedeffectiverootdepth <= tree->effectiverootdepth);
4727 
4728       SCIP_CALL( SCIPnodeFree(&oldfocusnode, blkmem, set, stat, eventfilter, eventqueue, tree, lp) );
4729       assert(tree->effectiverootdepth < tree->pathlen || *node == NULL || *cutoff);
4730 
4731       if( tree->effectiverootdepth > appliedeffectiverootdepth && *node != NULL && !(*cutoff) )
4732       {
4733          int d;
4734 
4735          /* promote the constraint set and bound changes up to the new effective root to be global changes */
4736          SCIPsetDebugMsg(set, "effective root is now at depth %d: applying constraint set and bound changes to global problem\n",
4737             tree->effectiverootdepth);
4738 
4739          for( d = appliedeffectiverootdepth + 1; d <= tree->effectiverootdepth; ++d )
4740          {
4741             SCIP_Bool nodecutoff;
4742 
4743             SCIPsetDebugMsg(set, " -> applying constraint set changes of depth %d\n", d);
4744             SCIP_CALL( SCIPconssetchgMakeGlobal(&tree->path[d]->conssetchg, blkmem, set, stat, transprob, reopt) );
4745             SCIPsetDebugMsg(set, " -> applying bound changes of depth %d\n", d);
4746             SCIP_CALL( SCIPdomchgApplyGlobal(tree->path[d]->domchg, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable,
4747                   &nodecutoff) );
4748 
4749             if( nodecutoff )
4750             {
4751                SCIP_CALL( SCIPnodeCutoff(tree->path[d], set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
4752                *cutoff = TRUE;
4753             }
4754          }
4755 
4756          tree->appliedeffectiverootdepth = tree->effectiverootdepth;
4757       }
4758    }
4759    assert(*cutoff || SCIPtreeIsPathComplete(tree));
4760 
4761    return SCIP_OKAY;
4762 }
4763 
4764 
4765 
4766 
4767 /*
4768  * Tree methods
4769  */
4770 
4771 /** creates an initialized tree data structure */
SCIPtreeCreate(SCIP_TREE ** tree,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_NODESEL * nodesel)4772 SCIP_RETCODE SCIPtreeCreate(
4773    SCIP_TREE**           tree,               /**< pointer to tree data structure */
4774    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4775    SCIP_SET*             set,                /**< global SCIP settings */
4776    SCIP_NODESEL*         nodesel             /**< node selector to use for sorting leaves in the priority queue */
4777    )
4778 {
4779    int p;
4780 
4781    assert(tree != NULL);
4782    assert(blkmem != NULL);
4783 
4784    SCIP_ALLOC( BMSallocMemory(tree) );
4785 
4786    (*tree)->root = NULL;
4787 
4788    SCIP_CALL( SCIPnodepqCreate(&(*tree)->leaves, set, nodesel) );
4789 
4790    /* allocate one slot for the prioritized and the unprioritized bound change */
4791    for( p = 0; p <= 1; ++p )
4792    {
4793       SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*tree)->divebdchgdirs[p], 1) ); /*lint !e866*/
4794       SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*tree)->divebdchgvars[p], 1) ); /*lint !e866*/
4795       SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*tree)->divebdchgvals[p], 1) ); /*lint !e866*/
4796       (*tree)->ndivebdchanges[p] = 0;
4797       (*tree)->divebdchgsize[p] = 1;
4798    }
4799 
4800    (*tree)->path = NULL;
4801    (*tree)->focusnode = NULL;
4802    (*tree)->focuslpfork = NULL;
4803    (*tree)->focuslpstatefork = NULL;
4804    (*tree)->focussubroot = NULL;
4805    (*tree)->children = NULL;
4806    (*tree)->siblings = NULL;
4807    (*tree)->probingroot = NULL;
4808    (*tree)->childrenprio = NULL;
4809    (*tree)->siblingsprio = NULL;
4810    (*tree)->pathnlpcols = NULL;
4811    (*tree)->pathnlprows = NULL;
4812    (*tree)->probinglpistate = NULL;
4813    (*tree)->probinglpinorms = NULL;
4814    (*tree)->pendingbdchgs = NULL;
4815    (*tree)->probdiverelaxsol = NULL;
4816    (*tree)->nprobdiverelaxsol = 0;
4817    (*tree)->pendingbdchgssize = 0;
4818    (*tree)->npendingbdchgs = 0;
4819    (*tree)->focuslpstateforklpcount = -1;
4820    (*tree)->childrensize = 0;
4821    (*tree)->nchildren = 0;
4822    (*tree)->siblingssize = 0;
4823    (*tree)->nsiblings = 0;
4824    (*tree)->pathlen = 0;
4825    (*tree)->pathsize = 0;
4826    (*tree)->effectiverootdepth = 0;
4827    (*tree)->appliedeffectiverootdepth = 0;
4828    (*tree)->lastbranchparentid = -1L;
4829    (*tree)->correctlpdepth = -1;
4830    (*tree)->cutoffdepth = INT_MAX;
4831    (*tree)->repropdepth = INT_MAX;
4832    (*tree)->repropsubtreecount = 0;
4833    (*tree)->focusnodehaslp = FALSE;
4834    (*tree)->probingnodehaslp = FALSE;
4835    (*tree)->focuslpconstructed = FALSE;
4836    (*tree)->cutoffdelayed = FALSE;
4837    (*tree)->probinglpwasflushed = FALSE;
4838    (*tree)->probinglpwassolved = FALSE;
4839    (*tree)->probingloadlpistate = FALSE;
4840    (*tree)->probinglpwasrelax = FALSE;
4841    (*tree)->probingsolvedlp = FALSE;
4842    (*tree)->forcinglpmessage = FALSE;
4843    (*tree)->sbprobing = FALSE;
4844    (*tree)->probinglpwasprimfeas = TRUE;
4845    (*tree)->probinglpwasdualfeas = TRUE;
4846    (*tree)->probdiverelaxstored = FALSE;
4847    (*tree)->probdiverelaxincludeslp = FALSE;
4848 
4849    return SCIP_OKAY;
4850 }
4851 
4852 /** frees tree data structure */
SCIPtreeFree(SCIP_TREE ** tree,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp)4853 SCIP_RETCODE SCIPtreeFree(
4854    SCIP_TREE**           tree,               /**< pointer to tree data structure */
4855    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4856    SCIP_SET*             set,                /**< global SCIP settings */
4857    SCIP_STAT*            stat,               /**< problem statistics */
4858    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
4859    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
4860    SCIP_LP*              lp                  /**< current LP data */
4861    )
4862 {
4863    int p;
4864 
4865    assert(tree != NULL);
4866    assert(*tree != NULL);
4867    assert((*tree)->nchildren == 0);
4868    assert((*tree)->nsiblings == 0);
4869    assert((*tree)->focusnode == NULL);
4870    assert(!SCIPtreeProbing(*tree));
4871 
4872    SCIPsetDebugMsg(set, "free tree\n");
4873 
4874    /* free node queue */
4875    SCIP_CALL( SCIPnodepqFree(&(*tree)->leaves, blkmem, set, stat, eventfilter, eventqueue, *tree, lp) );
4876 
4877    /* free diving bound change storage */
4878    for( p = 0; p <= 1; ++p )
4879    {
4880       BMSfreeBlockMemoryArray(blkmem, &(*tree)->divebdchgdirs[p], (*tree)->divebdchgsize[p]); /*lint !e866*/
4881       BMSfreeBlockMemoryArray(blkmem, &(*tree)->divebdchgvals[p], (*tree)->divebdchgsize[p]); /*lint !e866*/
4882       BMSfreeBlockMemoryArray(blkmem, &(*tree)->divebdchgvars[p], (*tree)->divebdchgsize[p]); /*lint !e866*/
4883    }
4884 
4885    /* free pointer arrays */
4886    BMSfreeMemoryArrayNull(&(*tree)->path);
4887    BMSfreeMemoryArrayNull(&(*tree)->children);
4888    BMSfreeMemoryArrayNull(&(*tree)->siblings);
4889    BMSfreeMemoryArrayNull(&(*tree)->childrenprio);
4890    BMSfreeMemoryArrayNull(&(*tree)->siblingsprio);
4891    BMSfreeMemoryArrayNull(&(*tree)->pathnlpcols);
4892    BMSfreeMemoryArrayNull(&(*tree)->pathnlprows);
4893    BMSfreeMemoryArrayNull(&(*tree)->probdiverelaxsol);
4894    BMSfreeMemoryArrayNull(&(*tree)->pendingbdchgs);
4895 
4896    BMSfreeMemory(tree);
4897 
4898    return SCIP_OKAY;
4899 }
4900 
4901 /** clears and resets tree data structure and deletes all nodes */
SCIPtreeClear(SCIP_TREE * tree,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp)4902 SCIP_RETCODE SCIPtreeClear(
4903    SCIP_TREE*            tree,               /**< tree data structure */
4904    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4905    SCIP_SET*             set,                /**< global SCIP settings */
4906    SCIP_STAT*            stat,               /**< problem statistics */
4907    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
4908    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
4909    SCIP_LP*              lp                  /**< current LP data */
4910    )
4911 {
4912    int v;
4913 
4914    assert(tree != NULL);
4915    assert(tree->nchildren == 0);
4916    assert(tree->nsiblings == 0);
4917    assert(tree->focusnode == NULL);
4918    assert(!SCIPtreeProbing(tree));
4919 
4920    SCIPsetDebugMsg(set, "clearing tree\n");
4921 
4922    /* clear node queue */
4923    SCIP_CALL( SCIPnodepqClear(tree->leaves, blkmem, set, stat, eventfilter, eventqueue, tree, lp) );
4924    assert(tree->root == NULL);
4925 
4926    /* we have to remove the captures of the variables within the pending bound change data structure */
4927    for( v = tree->npendingbdchgs-1; v >= 0; --v )
4928    {
4929       SCIP_VAR* var;
4930 
4931       var = tree->pendingbdchgs[v].var;
4932       assert(var != NULL);
4933 
4934       /* release the variable */
4935       SCIP_CALL( SCIPvarRelease(&var, blkmem, set, eventqueue, lp) );
4936    }
4937 
4938    /* mark working arrays to be empty and reset data */
4939    tree->focuslpstateforklpcount = -1;
4940    tree->nchildren = 0;
4941    tree->nsiblings = 0;
4942    tree->pathlen = 0;
4943    tree->effectiverootdepth = 0;
4944    tree->appliedeffectiverootdepth = 0;
4945    tree->correctlpdepth = -1;
4946    tree->cutoffdepth = INT_MAX;
4947    tree->repropdepth = INT_MAX;
4948    tree->repropsubtreecount = 0;
4949    tree->npendingbdchgs = 0;
4950    tree->focusnodehaslp = FALSE;
4951    tree->probingnodehaslp = FALSE;
4952    tree->cutoffdelayed = FALSE;
4953    tree->probinglpwasflushed = FALSE;
4954    tree->probinglpwassolved = FALSE;
4955    tree->probingloadlpistate = FALSE;
4956    tree->probinglpwasrelax = FALSE;
4957    tree->probingsolvedlp = FALSE;
4958 
4959    return SCIP_OKAY;
4960 }
4961 
4962 /** creates the root node of the tree and puts it into the leaves queue */
SCIPtreeCreateRoot(SCIP_TREE * tree,SCIP_REOPT * reopt,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp)4963 SCIP_RETCODE SCIPtreeCreateRoot(
4964    SCIP_TREE*            tree,               /**< tree data structure */
4965    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
4966    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
4967    SCIP_SET*             set,                /**< global SCIP settings */
4968    SCIP_STAT*            stat,               /**< problem statistics */
4969    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
4970    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
4971    SCIP_LP*              lp                  /**< current LP data */
4972    )
4973 {
4974    assert(tree != NULL);
4975    assert(tree->nchildren == 0);
4976    assert(tree->nsiblings == 0);
4977    assert(tree->root == NULL);
4978    assert(tree->focusnode == NULL);
4979    assert(!SCIPtreeProbing(tree));
4980 
4981    /* create root node */
4982    SCIP_CALL( SCIPnodeCreateChild(&tree->root, blkmem, set, stat, tree, 0.0, -SCIPsetInfinity(set)) );
4983    assert(tree->nchildren == 1);
4984 
4985 #ifndef NDEBUG
4986    /* check, if the sizes in the data structures match the maximal numbers defined here */
4987    tree->root->depth = SCIP_MAXTREEDEPTH + 1;
4988    tree->root->repropsubtreemark = MAXREPROPMARK;
4989    assert(tree->root->depth - 1 == SCIP_MAXTREEDEPTH); /*lint !e650*/
4990    assert(tree->root->repropsubtreemark == MAXREPROPMARK);
4991    tree->root->depth++;             /* this should produce an overflow and reset the value to 0 */
4992    tree->root->repropsubtreemark++; /* this should produce an overflow and reset the value to 0 */
4993    assert(tree->root->depth == 0);
4994    assert((SCIP_NODETYPE)tree->root->nodetype == SCIP_NODETYPE_CHILD);
4995    assert(!tree->root->active);
4996    assert(!tree->root->cutoff);
4997    assert(!tree->root->reprop);
4998    assert(tree->root->repropsubtreemark == 0);
4999 #endif
5000 
5001    /* move root to the queue, convert it to LEAF */
5002    SCIP_CALL( treeNodesToQueue(tree, reopt, blkmem, set, stat, eventfilter, eventqueue, lp, tree->children, &tree->nchildren, NULL,
5003          SCIPsetInfinity(set)) );
5004 
5005    return SCIP_OKAY;
5006 }
5007 
5008 /** creates a temporary presolving root node of the tree and installs it as focus node */
SCIPtreeCreatePresolvingRoot(SCIP_TREE * tree,SCIP_REOPT * reopt,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_PRIMAL * primal,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_CONFLICT * conflict,SCIP_CONFLICTSTORE * conflictstore,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable)5009 SCIP_RETCODE SCIPtreeCreatePresolvingRoot(
5010    SCIP_TREE*            tree,               /**< tree data structure */
5011    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
5012    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
5013    SCIP_SET*             set,                /**< global SCIP settings */
5014    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
5015    SCIP_STAT*            stat,               /**< problem statistics */
5016    SCIP_PROB*            transprob,          /**< transformed problem */
5017    SCIP_PROB*            origprob,           /**< original problem */
5018    SCIP_PRIMAL*          primal,             /**< primal data */
5019    SCIP_LP*              lp,                 /**< current LP data */
5020    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
5021    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
5022    SCIP_CONFLICTSTORE*   conflictstore,      /**< conflict store */
5023    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
5024    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
5025    SCIP_CLIQUETABLE*     cliquetable         /**< clique table data structure */
5026    )
5027 {
5028    SCIP_Bool cutoff;
5029 
5030    assert(tree != NULL);
5031    assert(tree->nchildren == 0);
5032    assert(tree->nsiblings == 0);
5033    assert(tree->root == NULL);
5034    assert(tree->focusnode == NULL);
5035    assert(!SCIPtreeProbing(tree));
5036 
5037    /* create temporary presolving root node */
5038    SCIP_CALL( SCIPtreeCreateRoot(tree, reopt, blkmem, set, stat, eventfilter, eventqueue, lp) );
5039    assert(tree->root != NULL);
5040 
5041    /* install the temporary root node as focus node */
5042    SCIP_CALL( SCIPnodeFocus(&tree->root, blkmem, set, messagehdlr, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
5043          conflict, conflictstore, eventfilter, eventqueue, cliquetable, &cutoff, FALSE, FALSE) );
5044    assert(!cutoff);
5045 
5046    return SCIP_OKAY;
5047 }
5048 
5049 /** frees the temporary presolving root and resets tree data structure */
SCIPtreeFreePresolvingRoot(SCIP_TREE * tree,SCIP_REOPT * reopt,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_PRIMAL * primal,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_CONFLICT * conflict,SCIP_CONFLICTSTORE * conflictstore,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue,SCIP_CLIQUETABLE * cliquetable)5050 SCIP_RETCODE SCIPtreeFreePresolvingRoot(
5051    SCIP_TREE*            tree,               /**< tree data structure */
5052    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
5053    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
5054    SCIP_SET*             set,                /**< global SCIP settings */
5055    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
5056    SCIP_STAT*            stat,               /**< problem statistics */
5057    SCIP_PROB*            transprob,          /**< transformed problem */
5058    SCIP_PROB*            origprob,           /**< original problem */
5059    SCIP_PRIMAL*          primal,             /**< primal data */
5060    SCIP_LP*              lp,                 /**< current LP data */
5061    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
5062    SCIP_CONFLICT*        conflict,           /**< conflict analysis data */
5063    SCIP_CONFLICTSTORE*   conflictstore,      /**< conflict store */
5064    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
5065    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
5066    SCIP_CLIQUETABLE*     cliquetable         /**< clique table data structure */
5067    )
5068 {
5069    SCIP_NODE* node;
5070    SCIP_Bool cutoff;
5071 
5072    assert(tree != NULL);
5073    assert(tree->root != NULL);
5074    assert(tree->focusnode == tree->root);
5075    assert(tree->pathlen == 1);
5076 
5077    /* unfocus the temporary root node */
5078    node = NULL;
5079    SCIP_CALL( SCIPnodeFocus(&node, blkmem, set, messagehdlr, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
5080          conflict, conflictstore, eventfilter, eventqueue, cliquetable, &cutoff, FALSE, FALSE) );
5081    assert(!cutoff);
5082    assert(tree->root == NULL);
5083    assert(tree->focusnode == NULL);
5084    assert(tree->pathlen == 0);
5085 
5086    /* reset tree data structure */
5087    SCIP_CALL( SCIPtreeClear(tree, blkmem, set, stat, eventfilter, eventqueue, lp) );
5088 
5089    return SCIP_OKAY;
5090 }
5091 
5092 /** returns the node selector associated with the given node priority queue */
SCIPtreeGetNodesel(SCIP_TREE * tree)5093 SCIP_NODESEL* SCIPtreeGetNodesel(
5094    SCIP_TREE*            tree                /**< branch and bound tree */
5095    )
5096 {
5097    assert(tree != NULL);
5098 
5099    return SCIPnodepqGetNodesel(tree->leaves);
5100 }
5101 
5102 /** sets the node selector used for sorting the nodes in the priority queue, and resorts the queue if necessary */
SCIPtreeSetNodesel(SCIP_TREE * tree,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat,SCIP_NODESEL * nodesel)5103 SCIP_RETCODE SCIPtreeSetNodesel(
5104    SCIP_TREE*            tree,               /**< branch and bound tree */
5105    SCIP_SET*             set,                /**< global SCIP settings */
5106    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
5107    SCIP_STAT*            stat,               /**< problem statistics */
5108    SCIP_NODESEL*         nodesel             /**< node selector to use for sorting the nodes in the queue */
5109    )
5110 {
5111    assert(tree != NULL);
5112    assert(stat != NULL);
5113 
5114    if( SCIPnodepqGetNodesel(tree->leaves) != nodesel )
5115    {
5116       /* change the node selector used in the priority queue and resort the queue */
5117       SCIP_CALL( SCIPnodepqSetNodesel(&tree->leaves, set, nodesel) );
5118 
5119       /* issue message */
5120       if( stat->nnodes > 0 )
5121       {
5122          SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
5123             "(node %" SCIP_LONGINT_FORMAT ") switching to node selector <%s>\n", stat->nnodes, SCIPnodeselGetName(nodesel));
5124       }
5125    }
5126 
5127    return SCIP_OKAY;
5128 }
5129 
5130 /** cuts off nodes with lower bound not better than given cutoff bound */
SCIPtreeCutoff(SCIP_TREE * tree,SCIP_REOPT * reopt,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_EVENTFILTER * eventfilter,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp,SCIP_Real cutoffbound)5131 SCIP_RETCODE SCIPtreeCutoff(
5132    SCIP_TREE*            tree,               /**< branch and bound tree */
5133    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
5134    BMS_BLKMEM*           blkmem,             /**< block memory */
5135    SCIP_SET*             set,                /**< global SCIP settings */
5136    SCIP_STAT*            stat,               /**< dynamic problem statistics */
5137    SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global (not variable dependent) events */
5138    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
5139    SCIP_LP*              lp,                 /**< current LP data */
5140    SCIP_Real             cutoffbound         /**< cutoff bound: all nodes with lowerbound >= cutoffbound are cut off */
5141    )
5142 {
5143    SCIP_NODE* node;
5144    int i;
5145 
5146    assert(tree != NULL);
5147    assert(stat != NULL);
5148    assert(lp != NULL);
5149 
5150    /* if we are in diving mode, it is not allowed to cut off nodes, because this can lead to deleting LP rows which
5151     * would modify the currently unavailable (due to diving modifications) SCIP_LP
5152     *  -> the cutoff must be delayed and executed after the diving ends
5153     */
5154    if( SCIPlpDiving(lp) )
5155    {
5156       tree->cutoffdelayed = TRUE;
5157       return SCIP_OKAY;
5158    }
5159 
5160    tree->cutoffdelayed = FALSE;
5161 
5162    /* cut off leaf nodes in the queue */
5163    SCIP_CALL( SCIPnodepqBound(tree->leaves, blkmem, set, stat, eventfilter, eventqueue, tree, reopt, lp, cutoffbound) );
5164 
5165    /* cut off siblings: we have to loop backwards, because a removal leads to moving the last node in empty slot */
5166    for( i = tree->nsiblings-1; i >= 0; --i )
5167    {
5168       node = tree->siblings[i];
5169       if( SCIPsetIsGE(set, node->lowerbound, cutoffbound) )
5170       {
5171          SCIPsetDebugMsg(set, "cut off sibling #%" SCIP_LONGINT_FORMAT " at depth %d with lowerbound=%g at position %d\n",
5172             SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), node->lowerbound, i);
5173 
5174          if( set->reopt_enable )
5175          {
5176             assert(reopt != NULL);
5177             /* check if the node should be stored for reoptimization */
5178             SCIP_CALL( SCIPreoptCheckCutoff(reopt, set, blkmem, node, SCIP_EVENTTYPE_NODEINFEASIBLE, lp, SCIPlpGetSolstat(lp),
5179                   tree->root == node, tree->focusnode == node, node->lowerbound, tree->effectiverootdepth) );
5180          }
5181 
5182          SCIPvisualCutoffNode(stat->visual, set, stat, node, FALSE);
5183 
5184          SCIP_CALL( SCIPnodeFree(&node, blkmem, set, stat, eventfilter, eventqueue, tree, lp) );
5185       }
5186    }
5187 
5188    /* cut off children: we have to loop backwards, because a removal leads to moving the last node in empty slot */
5189    for( i = tree->nchildren-1; i >= 0; --i )
5190    {
5191       node = tree->children[i];
5192       if( SCIPsetIsGE(set, node->lowerbound, cutoffbound) )
5193       {
5194          SCIPsetDebugMsg(set, "cut off child #%" SCIP_LONGINT_FORMAT " at depth %d with lowerbound=%g at position %d\n",
5195             SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), node->lowerbound, i);
5196 
5197          if( set->reopt_enable )
5198          {
5199             assert(reopt != NULL);
5200             /* check if the node should be stored for reoptimization */
5201             SCIP_CALL( SCIPreoptCheckCutoff(reopt, set, blkmem, node, SCIP_EVENTTYPE_NODEINFEASIBLE, lp, SCIPlpGetSolstat(lp),
5202                   tree->root == node, tree->focusnode == node, node->lowerbound, tree->effectiverootdepth) );
5203          }
5204 
5205          SCIPvisualCutoffNode(stat->visual, set, stat, node, FALSE);
5206 
5207          SCIP_CALL( SCIPnodeFree(&node, blkmem, set, stat, eventfilter, eventqueue, tree, lp) );
5208       }
5209    }
5210 
5211    return SCIP_OKAY;
5212 }
5213 
5214 /** calculates the node selection priority for moving the given variable's LP value to the given target value;
5215  *  this node selection priority can be given to the SCIPcreateChild() call
5216  */
SCIPtreeCalcNodeselPriority(SCIP_TREE * tree,SCIP_SET * set,SCIP_STAT * stat,SCIP_VAR * var,SCIP_BRANCHDIR branchdir,SCIP_Real targetvalue)5217 SCIP_Real SCIPtreeCalcNodeselPriority(
5218    SCIP_TREE*            tree,               /**< branch and bound tree */
5219    SCIP_SET*             set,                /**< global SCIP settings */
5220    SCIP_STAT*            stat,               /**< dynamic problem statistics */
5221    SCIP_VAR*             var,                /**< variable, of which the branching factor should be applied, or NULL */
5222    SCIP_BRANCHDIR        branchdir,          /**< type of branching that was performed: upwards, downwards, or fixed
5223                                               * fixed should only be used, when both bounds changed
5224                                               */
5225    SCIP_Real             targetvalue         /**< new value of the variable in the child node */
5226    )
5227 {
5228    SCIP_Real prio;
5229    SCIP_Real varsol;
5230    SCIP_Real varrootsol;
5231    SCIP_Real downinfs;
5232    SCIP_Real upinfs;
5233    SCIP_Bool isroot;
5234    SCIP_Bool haslp;
5235 
5236    assert(set != NULL);
5237 
5238    /* extract necessary information */
5239    isroot = (SCIPtreeGetCurrentDepth(tree) == 0);
5240    haslp = SCIPtreeHasFocusNodeLP(tree);
5241    varsol = SCIPvarGetSol(var, haslp);
5242    varrootsol = SCIPvarGetRootSol(var);
5243    downinfs = SCIPvarGetAvgInferences(var, stat, SCIP_BRANCHDIR_DOWNWARDS);
5244    upinfs = SCIPvarGetAvgInferences(var, stat, SCIP_BRANCHDIR_UPWARDS);
5245 
5246    switch( branchdir )
5247    {
5248    case SCIP_BRANCHDIR_DOWNWARDS:
5249       switch( SCIPvarGetBranchDirection(var) )
5250       {
5251       case SCIP_BRANCHDIR_DOWNWARDS:
5252          prio = +1.0;
5253          break;
5254       case SCIP_BRANCHDIR_UPWARDS:
5255          prio = -1.0;
5256          break;
5257       case SCIP_BRANCHDIR_AUTO:
5258          switch( set->nodesel_childsel )
5259          {
5260          case 'd':
5261             prio = +1.0;
5262             break;
5263          case 'u':
5264             prio = -1.0;
5265             break;
5266          case 'p':
5267             prio = -SCIPvarGetPseudocost(var, stat, targetvalue - varsol);
5268             break;
5269          case 'i':
5270             prio = downinfs;
5271             break;
5272          case 'l':
5273             prio = targetvalue - varsol;
5274             break;
5275          case 'r':
5276             prio = varrootsol - varsol;
5277             break;
5278          case 'h':
5279             prio = downinfs + SCIPsetEpsilon(set);
5280             if( !isroot && haslp )
5281                prio *= (varrootsol - varsol + 1.0);
5282             break;
5283          default:
5284             SCIPerrorMessage("invalid child selection rule <%c>\n", set->nodesel_childsel);
5285             prio = 0.0;
5286             break;
5287          }
5288          break;
5289       default:
5290          SCIPerrorMessage("invalid preferred branching direction <%d> of variable <%s>\n",
5291             SCIPvarGetBranchDirection(var), SCIPvarGetName(var));
5292          prio = 0.0;
5293          break;
5294       }
5295       break;
5296    case SCIP_BRANCHDIR_UPWARDS:
5297       /* the branch is directed upwards */
5298       switch( SCIPvarGetBranchDirection(var) )
5299       {
5300       case SCIP_BRANCHDIR_DOWNWARDS:
5301          prio = -1.0;
5302          break;
5303       case SCIP_BRANCHDIR_UPWARDS:
5304          prio = +1.0;
5305          break;
5306       case SCIP_BRANCHDIR_AUTO:
5307          switch( set->nodesel_childsel )
5308          {
5309          case 'd':
5310             prio = -1.0;
5311             break;
5312          case 'u':
5313             prio = +1.0;
5314             break;
5315          case 'p':
5316             prio = -SCIPvarGetPseudocost(var, stat, targetvalue - varsol);
5317             break;
5318          case 'i':
5319             prio = upinfs;
5320             break;
5321          case 'l':
5322             prio = varsol - targetvalue;
5323             break;
5324          case 'r':
5325             prio = varsol - varrootsol;
5326             break;
5327          case 'h':
5328             prio = upinfs  + SCIPsetEpsilon(set);
5329             if( !isroot && haslp )
5330                prio *= (varsol - varrootsol + 1.0);
5331             break;
5332          default:
5333             SCIPerrorMessage("invalid child selection rule <%c>\n", set->nodesel_childsel);
5334             prio = 0.0;
5335             break;
5336          }
5337          /* since choosing the upwards direction is usually superior than the downwards direction (see results of
5338           * Achterberg's thesis (2007)), we break ties towards upwards branching
5339           */
5340          prio += SCIPsetEpsilon(set);
5341          break;
5342 
5343       default:
5344          SCIPerrorMessage("invalid preferred branching direction <%d> of variable <%s>\n",
5345             SCIPvarGetBranchDirection(var), SCIPvarGetName(var));
5346          prio = 0.0;
5347          break;
5348       }
5349       break;
5350    case SCIP_BRANCHDIR_FIXED:
5351       prio = SCIPsetInfinity(set);
5352       break;
5353    case SCIP_BRANCHDIR_AUTO:
5354    default:
5355       SCIPerrorMessage("invalid branching direction <%d> of variable <%s>\n",
5356          SCIPvarGetBranchDirection(var), SCIPvarGetName(var));
5357       prio = 0.0;
5358       break;
5359    }
5360 
5361    return prio;
5362 }
5363 
5364 /** calculates an estimate for the objective of the best feasible solution contained in the subtree after applying the given
5365  *  branching; this estimate can be given to the SCIPcreateChild() call
5366  */
SCIPtreeCalcChildEstimate(SCIP_TREE * tree,SCIP_SET * set,SCIP_STAT * stat,SCIP_VAR * var,SCIP_Real targetvalue)5367 SCIP_Real SCIPtreeCalcChildEstimate(
5368    SCIP_TREE*            tree,               /**< branch and bound tree */
5369    SCIP_SET*             set,                /**< global SCIP settings */
5370    SCIP_STAT*            stat,               /**< dynamic problem statistics */
5371    SCIP_VAR*             var,                /**< variable, of which the branching factor should be applied, or NULL */
5372    SCIP_Real             targetvalue         /**< new value of the variable in the child node */
5373    )
5374 {
5375    SCIP_Real estimateinc;
5376    SCIP_Real estimate;
5377    SCIP_Real varsol;
5378 
5379    assert(tree != NULL);
5380    assert(var != NULL);
5381 
5382    estimate = SCIPnodeGetEstimate(tree->focusnode);
5383    varsol = SCIPvarGetSol(var, SCIPtreeHasFocusNodeLP(tree));
5384 
5385    /* compute increase above parent node's (i.e., focus node's) estimate value */
5386    if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
5387       estimateinc = SCIPvarGetPseudocost(var, stat, targetvalue - varsol);
5388    else
5389    {
5390       SCIP_Real pscdown;
5391       SCIP_Real pscup;
5392 
5393       /* calculate estimate based on pseudo costs:
5394        *   estimate = lowerbound + sum(min{f_j * pscdown_j, (1-f_j) * pscup_j})
5395        *            = parentestimate - min{f_b * pscdown_b, (1-f_b) * pscup_b} + (targetvalue-oldvalue)*{pscdown_b or pscup_b}
5396        */
5397       pscdown = SCIPvarGetPseudocost(var, stat, SCIPsetFeasFloor(set, varsol) - varsol);
5398       pscup = SCIPvarGetPseudocost(var, stat, SCIPsetFeasCeil(set, varsol) - varsol);
5399       estimateinc = SCIPvarGetPseudocost(var, stat, targetvalue - varsol) - MIN(pscdown, pscup);
5400    }
5401 
5402    /* due to rounding errors estimateinc might be slightly negative; in this case return the parent node's estimate */
5403    if( estimateinc > 0.0 )
5404       estimate += estimateinc;
5405 
5406    return estimate;
5407 }
5408 
5409 /** branches on a variable x
5410  *  if x is a continuous variable, then two child nodes will be created
5411  *  (x <= x', x >= x')
5412  *  but if the bounds of x are such that their relative difference is smaller than epsilon,
5413  *  the variable is fixed to val (if not SCIP_INVALID) or a well chosen alternative in the current node,
5414  *  i.e., no children are created
5415  *  if x is not a continuous variable, then:
5416  *  if solution value x' is fractional, two child nodes will be created
5417  *  (x <= floor(x'), x >= ceil(x')),
5418  *  if solution value is integral, the x' is equal to lower or upper bound of the branching
5419  *  variable and the bounds of x are finite, then two child nodes will be created
5420  *  (x <= x", x >= x"+1 with x" = floor((lb + ub)/2)),
5421  *  otherwise (up to) three child nodes will be created
5422  *  (x <= x'-1, x == x', x >= x'+1)
5423  *  if solution value is equal to one of the bounds and the other bound is infinite, only two child nodes
5424  *  will be created (the third one would be infeasible anyway)
5425  */
SCIPtreeBranchVar(SCIP_TREE * tree,SCIP_REOPT * reopt,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_VAR * var,SCIP_Real val,SCIP_NODE ** downchild,SCIP_NODE ** eqchild,SCIP_NODE ** upchild)5426 SCIP_RETCODE SCIPtreeBranchVar(
5427    SCIP_TREE*            tree,               /**< branch and bound tree */
5428    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
5429    BMS_BLKMEM*           blkmem,             /**< block memory */
5430    SCIP_SET*             set,                /**< global SCIP settings */
5431    SCIP_STAT*            stat,               /**< problem statistics data */
5432    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
5433    SCIP_PROB*            origprob,           /**< original problem */
5434    SCIP_LP*              lp,                 /**< current LP data */
5435    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
5436    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
5437    SCIP_VAR*             var,                /**< variable to branch on */
5438    SCIP_Real             val,                /**< value to branch on or SCIP_INVALID for branching on current LP/pseudo solution.
5439                                               *   A branching value is required for branching on continuous variables */
5440    SCIP_NODE**           downchild,          /**< pointer to return the left child with variable rounded down, or NULL */
5441    SCIP_NODE**           eqchild,            /**< pointer to return the middle child with variable fixed, or NULL */
5442    SCIP_NODE**           upchild             /**< pointer to return the right child with variable rounded up, or NULL */
5443    )
5444 {
5445    SCIP_NODE* node;
5446    SCIP_Real priority;
5447    SCIP_Real estimate;
5448 
5449    SCIP_Real downub;
5450    SCIP_Real fixval;
5451    SCIP_Real uplb;
5452    SCIP_Real lpval;
5453 
5454    SCIP_Bool validval;
5455 
5456    assert(tree != NULL);
5457    assert(set != NULL);
5458    assert(var != NULL);
5459 
5460    /* initialize children pointer */
5461    if( downchild != NULL )
5462       *downchild = NULL;
5463    if( eqchild != NULL )
5464       *eqchild = NULL;
5465    if( upchild != NULL )
5466       *upchild = NULL;
5467 
5468    /* store whether a valid value was given for branching */
5469    validval = (val != SCIP_INVALID);  /*lint !e777 */
5470 
5471    /* get the corresponding active problem variable
5472     * if branching value is given, then transform it to the value of the active variable */
5473    if( validval )
5474    {
5475       SCIP_Real scalar;
5476       SCIP_Real constant;
5477 
5478       scalar   = 1.0;
5479       constant = 0.0;
5480 
5481       SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &scalar, &constant) );
5482 
5483       if( scalar == 0.0 )
5484       {
5485          SCIPerrorMessage("cannot branch on fixed variable <%s>\n", SCIPvarGetName(var));
5486          return SCIP_INVALIDDATA;
5487       }
5488 
5489       /* we should have givenvariable = scalar * activevariable + constant */
5490       val = (val - constant) / scalar;
5491    }
5492    else
5493       var = SCIPvarGetProbvar(var);
5494 
5495    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
5496    {
5497       SCIPerrorMessage("cannot branch on fixed or multi-aggregated variable <%s>\n", SCIPvarGetName(var));
5498       SCIPABORT();
5499       return SCIP_INVALIDDATA; /*lint !e527*/
5500    }
5501 
5502    /* ensure, that branching on continuous variables will only be performed when a branching point is given. */
5503    if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS && !validval )
5504    {
5505       SCIPerrorMessage("Cannot branch on continuous variable <%s> without a given branching value.", SCIPvarGetName(var));
5506       SCIPABORT();
5507       return SCIP_INVALIDDATA; /*lint !e527*/
5508    }
5509 
5510    assert(SCIPvarIsActive(var));
5511    assert(SCIPvarGetProbindex(var) >= 0);
5512    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
5513    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, SCIPvarGetLbLocal(var)));
5514    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, SCIPvarGetUbLocal(var)));
5515    assert(SCIPsetIsLT(set, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)));
5516 
5517    /* update the information for the focus node before creating children */
5518    SCIP_CALL( SCIPvisualUpdateChild(stat->visual, set, stat, tree->focusnode) );
5519 
5520    /* get value of variable in current LP or pseudo solution */
5521    lpval = SCIPvarGetSol(var, tree->focusnodehaslp);
5522 
5523    /* if there was no explicit value given for branching, branch on current LP or pseudo solution value */
5524    if( !validval )
5525    {
5526       val = lpval;
5527 
5528       /* avoid branching on infinite values in pseudo solution */
5529       if( SCIPsetIsInfinity(set, -val) || SCIPsetIsInfinity(set, val) )
5530       {
5531          val = SCIPvarGetWorstBoundLocal(var);
5532 
5533          /* if both bounds are infinite, choose zero as branching point */
5534          if( SCIPsetIsInfinity(set, -val) || SCIPsetIsInfinity(set, val) )
5535          {
5536             assert(SCIPsetIsInfinity(set, -SCIPvarGetLbLocal(var)));
5537             assert(SCIPsetIsInfinity(set, SCIPvarGetUbLocal(var)));
5538             val = 0.0;
5539          }
5540       }
5541    }
5542 
5543    assert(SCIPsetIsFeasGE(set, val, SCIPvarGetLbLocal(var)));
5544    assert(SCIPsetIsFeasLE(set, val, SCIPvarGetUbLocal(var)));
5545    /* see comment in SCIPbranchVarVal */
5546    assert(SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS ||
5547       SCIPrelDiff(SCIPvarGetUbLocal(var), SCIPvarGetLbLocal(var)) <= 2.02 * SCIPsetEpsilon(set) ||
5548       SCIPsetIsInfinity(set, -2.1*SCIPvarGetLbLocal(var)) || SCIPsetIsInfinity(set, 2.1*SCIPvarGetUbLocal(var)) ||
5549       (SCIPsetIsLT(set, 2.1*SCIPvarGetLbLocal(var), 2.1*val) && SCIPsetIsLT(set, 2.1*val, 2.1*SCIPvarGetUbLocal(var))) );
5550 
5551    downub = SCIP_INVALID;
5552    fixval = SCIP_INVALID;
5553    uplb = SCIP_INVALID;
5554 
5555    if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
5556    {
5557       if( SCIPsetIsRelEQ(set, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
5558       {
5559          SCIPsetDebugMsg(set, "fixing continuous variable <%s> with value %g and bounds [%.15g, %.15g], priority %d (current lower bound: %g)\n",
5560             SCIPvarGetName(var), val, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPvarGetBranchPriority(var), SCIPnodeGetLowerbound(tree->focusnode));
5561 
5562          /* if val is at least epsilon away from both bounds, then we change both bounds to this value
5563           * otherwise, we fix the variable to its worst bound
5564           */
5565          if( SCIPsetIsGT(set, val, SCIPvarGetLbLocal(var)) && SCIPsetIsLT(set, val, SCIPvarGetUbLocal(var)) )
5566          {
5567             SCIP_CALL( SCIPnodeAddBoundchg(tree->focusnode, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
5568                   branchcand, eventqueue, NULL, var, val, SCIP_BOUNDTYPE_LOWER, FALSE) );
5569             SCIP_CALL( SCIPnodeAddBoundchg(tree->focusnode, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
5570                   branchcand, eventqueue, NULL, var, val, SCIP_BOUNDTYPE_UPPER, FALSE) );
5571          }
5572          else if( SCIPvarGetObj(var) >= 0.0 )
5573          {
5574             SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetCurrentNode(tree), blkmem, set, stat, transprob, origprob,
5575                   tree, reopt, lp, branchcand, eventqueue, NULL, var, SCIPvarGetUbLocal(var), SCIP_BOUNDTYPE_LOWER, FALSE) );
5576          }
5577          else
5578          {
5579             SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetCurrentNode(tree), blkmem, set, stat, transprob, origprob,
5580                   tree, reopt, lp, branchcand, eventqueue, NULL, var, SCIPvarGetLbLocal(var), SCIP_BOUNDTYPE_UPPER, FALSE) );
5581          }
5582       }
5583       else if( SCIPrelDiff(SCIPvarGetUbLocal(var), SCIPvarGetLbLocal(var)) <= 2.02 * SCIPsetEpsilon(set) )
5584       {
5585          /* if the only way to branch is such that in both sides the relative domain width becomes smaller epsilon,
5586           * then fix the variable in both branches right away
5587           *
5588           * however, if one of the bounds is at infinity (and thus the other bound is at most 2eps away from the same infinity (in relative sense),
5589           * then fix the variable to the non-infinite value, as we cannot fix a variable to infinity
5590           */
5591          SCIPsetDebugMsg(set, "continuous branch on variable <%s> with bounds [%.15g, %.15g], priority %d (current lower bound: %g), node %p\n",
5592             SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPvarGetBranchPriority(var), SCIPnodeGetLowerbound(tree->focusnode), (void*)tree->focusnode);
5593          if( SCIPsetIsInfinity(set, -SCIPvarGetLbLocal(var)) )
5594          {
5595             assert(!SCIPsetIsInfinity(set, -SCIPvarGetUbLocal(var)));
5596             SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetCurrentNode(tree), blkmem, set, stat, transprob, origprob,
5597                   tree, reopt, lp, branchcand, eventqueue, NULL, var, SCIPvarGetUbLocal(var), SCIP_BOUNDTYPE_LOWER, FALSE) );
5598          }
5599          else if( SCIPsetIsInfinity(set, SCIPvarGetUbLocal(var)) )
5600          {
5601             assert(!SCIPsetIsInfinity(set, SCIPvarGetLbLocal(var)));
5602             SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetCurrentNode(tree), blkmem, set, stat, transprob, origprob,
5603                   tree, reopt, lp, branchcand, eventqueue, NULL, var, SCIPvarGetLbLocal(var), SCIP_BOUNDTYPE_UPPER, FALSE) );
5604          }
5605          else
5606          {
5607             downub = SCIPvarGetLbLocal(var);
5608             uplb = SCIPvarGetUbLocal(var);
5609          }
5610       }
5611       else
5612       {
5613          /* in the general case, there is enough space for two branches
5614           * a sophisticated user should have also chosen the branching value such that it is not very close to the bounds
5615           * so here we only ensure that it is at least epsilon away from both bounds
5616           */
5617          SCIPsetDebugMsg(set, "continuous branch on variable <%s> with value %g, priority %d (current lower bound: %g)\n",
5618             SCIPvarGetName(var), val, SCIPvarGetBranchPriority(var), SCIPnodeGetLowerbound(tree->focusnode));
5619          downub = MIN(val, SCIPvarGetUbLocal(var) - SCIPsetEpsilon(set)); /*lint !e666*/
5620          uplb   = MAX(val, SCIPvarGetLbLocal(var) + SCIPsetEpsilon(set)); /*lint !e666*/
5621       }
5622    }
5623    else if( SCIPsetIsFeasIntegral(set, val) )
5624    {
5625       SCIP_Real lb;
5626       SCIP_Real ub;
5627 
5628       lb = SCIPvarGetLbLocal(var);
5629       ub = SCIPvarGetUbLocal(var);
5630 
5631       /* if there was no explicit value given for branching, the variable has a finite domain and the current LP/pseudo
5632        * solution is one of the bounds, we branch in the center of the domain */
5633       if( !validval && !SCIPsetIsInfinity(set, -lb) && !SCIPsetIsInfinity(set, ub)
5634          && (SCIPsetIsFeasEQ(set, val, lb) || SCIPsetIsFeasEQ(set, val, ub)) )
5635       {
5636          SCIP_Real center;
5637 
5638          /* create child nodes with x <= x", and x >= x"+1 with x" = floor((lb + ub)/2);
5639           * if x" is integral, make the interval smaller in the child in which the current solution x'
5640           * is still feasible
5641           */
5642          center = (ub + lb) / 2.0;
5643          if( val <= center )
5644          {
5645             downub = SCIPsetFeasFloor(set, center);
5646             uplb = downub + 1.0;
5647          }
5648          else
5649          {
5650             uplb = SCIPsetFeasCeil(set, center);
5651             downub = uplb - 1.0;
5652          }
5653       }
5654       else
5655       {
5656          /* create child nodes with x <= x'-1, x = x', and x >= x'+1 */
5657          assert(SCIPsetIsEQ(set, SCIPsetFeasCeil(set, val), SCIPsetFeasFloor(set, val)));
5658 
5659          fixval = SCIPsetFeasCeil(set, val); /* get rid of numerical issues */
5660 
5661          /* create child node with x <= x'-1, if this would be feasible */
5662          if( SCIPsetIsFeasGE(set, fixval-1.0, lb) )
5663             downub = fixval - 1.0;
5664 
5665          /* create child node with x >= x'+1, if this would be feasible */
5666          if( SCIPsetIsFeasLE(set, fixval+1.0, ub) )
5667             uplb = fixval + 1.0;
5668       }
5669       SCIPsetDebugMsg(set, "integral branch on variable <%s> with value %g, priority %d (current lower bound: %g)\n",
5670          SCIPvarGetName(var), val, SCIPvarGetBranchPriority(var), SCIPnodeGetLowerbound(tree->focusnode));
5671    }
5672    else
5673    {
5674       /* create child nodes with x <= floor(x'), and x >= ceil(x') */
5675       downub = SCIPsetFeasFloor(set, val);
5676       uplb = downub + 1.0;
5677       assert( SCIPsetIsRelEQ(set, SCIPsetCeil(set, val), uplb) );
5678       SCIPsetDebugMsg(set, "fractional branch on variable <%s> with value %g, root value %g, priority %d (current lower bound: %g)\n",
5679          SCIPvarGetName(var), val, SCIPvarGetRootSol(var), SCIPvarGetBranchPriority(var), SCIPnodeGetLowerbound(tree->focusnode));
5680    }
5681 
5682    /* perform the branching;
5683     * set the node selection priority in a way, s.t. a node is preferred whose branching goes in the same direction
5684     * as the deviation from the variable's root solution
5685     */
5686    if( downub != SCIP_INVALID )    /*lint !e777*/
5687    {
5688       /* create child node x <= downub */
5689       priority = SCIPtreeCalcNodeselPriority(tree, set, stat, var, SCIP_BRANCHDIR_DOWNWARDS, downub);
5690       /* if LP solution is cutoff in child, compute a new estimate
5691        * otherwise we cannot expect a direct change in the best solution, so we keep the estimate of the parent node */
5692       if( SCIPsetIsGT(set, lpval, downub) )
5693          estimate = SCIPtreeCalcChildEstimate(tree, set, stat, var, downub);
5694       else
5695          estimate = SCIPnodeGetEstimate(tree->focusnode);
5696       SCIPsetDebugMsg(set, " -> creating child: <%s> <= %g (priority: %g, estimate: %g)\n",
5697          SCIPvarGetName(var), downub, priority, estimate);
5698       SCIP_CALL( SCIPnodeCreateChild(&node, blkmem, set, stat, tree, priority, estimate) );
5699       SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
5700             NULL, var, downub, SCIP_BOUNDTYPE_UPPER, FALSE) );
5701       /* output branching bound change to visualization file */
5702       SCIP_CALL( SCIPvisualUpdateChild(stat->visual, set, stat, node) );
5703 
5704       if( downchild != NULL )
5705          *downchild = node;
5706    }
5707 
5708    if( fixval != SCIP_INVALID )    /*lint !e777*/
5709    {
5710       /* create child node with x = fixval */
5711       priority = SCIPtreeCalcNodeselPriority(tree, set, stat, var, SCIP_BRANCHDIR_FIXED, fixval);
5712       estimate = SCIPtreeCalcChildEstimate(tree, set, stat, var, fixval);
5713       SCIPsetDebugMsg(set, " -> creating child: <%s> == %g (priority: %g, estimate: %g)\n",
5714          SCIPvarGetName(var), fixval, priority, estimate);
5715       SCIP_CALL( SCIPnodeCreateChild(&node, blkmem, set, stat, tree, priority, estimate) );
5716       if( !SCIPsetIsFeasEQ(set, SCIPvarGetLbLocal(var), fixval) )
5717       {
5718          SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
5719                NULL, var, fixval, SCIP_BOUNDTYPE_LOWER, FALSE) );
5720       }
5721       if( !SCIPsetIsFeasEQ(set, SCIPvarGetUbLocal(var), fixval) )
5722       {
5723          SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
5724                NULL, var, fixval, SCIP_BOUNDTYPE_UPPER, FALSE) );
5725       }
5726       /* output branching bound change to visualization file */
5727       SCIP_CALL( SCIPvisualUpdateChild(stat->visual, set, stat, node) );
5728 
5729       if( eqchild != NULL )
5730          *eqchild = node;
5731    }
5732 
5733    if( uplb != SCIP_INVALID )    /*lint !e777*/
5734    {
5735       /* create child node with x >= uplb */
5736       priority = SCIPtreeCalcNodeselPriority(tree, set, stat, var, SCIP_BRANCHDIR_UPWARDS, uplb);
5737       if( SCIPsetIsLT(set, lpval, uplb) )
5738          estimate = SCIPtreeCalcChildEstimate(tree, set, stat, var, uplb);
5739       else
5740          estimate = SCIPnodeGetEstimate(tree->focusnode);
5741       SCIPsetDebugMsg(set, " -> creating child: <%s> >= %g (priority: %g, estimate: %g)\n",
5742          SCIPvarGetName(var), uplb, priority, estimate);
5743       SCIP_CALL( SCIPnodeCreateChild(&node, blkmem, set, stat, tree, priority, estimate) );
5744       SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
5745             NULL, var, uplb, SCIP_BOUNDTYPE_LOWER, FALSE) );
5746       /* output branching bound change to visualization file */
5747       SCIP_CALL( SCIPvisualUpdateChild(stat->visual, set, stat, node) );
5748 
5749       if( upchild != NULL )
5750          *upchild = node;
5751    }
5752 
5753    return SCIP_OKAY;
5754 }
5755 
5756 /** branches a variable x using the given domain hole; two child nodes will be created (x <= left, x >= right) */
SCIPtreeBranchVarHole(SCIP_TREE * tree,SCIP_REOPT * reopt,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_VAR * var,SCIP_Real left,SCIP_Real right,SCIP_NODE ** downchild,SCIP_NODE ** upchild)5757 SCIP_RETCODE SCIPtreeBranchVarHole(
5758    SCIP_TREE*            tree,               /**< branch and bound tree */
5759    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
5760    BMS_BLKMEM*           blkmem,             /**< block memory */
5761    SCIP_SET*             set,                /**< global SCIP settings */
5762    SCIP_STAT*            stat,               /**< problem statistics data */
5763    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
5764    SCIP_PROB*            origprob,           /**< original problem */
5765    SCIP_LP*              lp,                 /**< current LP data */
5766    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
5767    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
5768    SCIP_VAR*             var,                /**< variable to branch on */
5769    SCIP_Real             left,               /**< left side of the domain hole */
5770    SCIP_Real             right,              /**< right side of the domain hole */
5771    SCIP_NODE**           downchild,          /**< pointer to return the left child with variable rounded down, or NULL */
5772    SCIP_NODE**           upchild             /**< pointer to return the right child with variable rounded up, or NULL */
5773    )
5774 {
5775    SCIP_NODE* node;
5776    SCIP_Real priority;
5777    SCIP_Real estimate;
5778    SCIP_Real lpval;
5779 
5780    assert(tree != NULL);
5781    assert(set != NULL);
5782    assert(var != NULL);
5783    assert(SCIPsetIsLT(set, left, SCIPvarGetUbLocal(var)));
5784    assert(SCIPsetIsGE(set, left, SCIPvarGetLbLocal(var)));
5785    assert(SCIPsetIsGT(set, right, SCIPvarGetLbLocal(var)));
5786    assert(SCIPsetIsLE(set, right, SCIPvarGetUbLocal(var)));
5787    assert(SCIPsetIsLE(set, left, right));
5788 
5789    /* initialize children pointer */
5790    if( downchild != NULL )
5791       *downchild = NULL;
5792    if( upchild != NULL )
5793       *upchild = NULL;
5794 
5795    /* get the corresponding active problem variable */
5796    SCIP_CALL( SCIPvarGetProbvarHole(&var, &left, &right) );
5797 
5798    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
5799    {
5800       SCIPerrorMessage("cannot branch on fixed or multi-aggregated variable <%s>\n", SCIPvarGetName(var));
5801       SCIPABORT();
5802       return SCIP_INVALIDDATA; /*lint !e527*/
5803    }
5804 
5805    assert(SCIPvarIsActive(var));
5806    assert(SCIPvarGetProbindex(var) >= 0);
5807    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
5808    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, SCIPvarGetLbLocal(var)));
5809    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, SCIPvarGetUbLocal(var)));
5810    assert(SCIPsetIsLT(set, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)));
5811 
5812    assert(SCIPsetIsFeasGE(set, left, SCIPvarGetLbLocal(var)));
5813    assert(SCIPsetIsFeasLE(set, right, SCIPvarGetUbLocal(var)));
5814 
5815    /* adjust left and right side of the domain hole if the variable is integral */
5816    if( SCIPvarIsIntegral(var) )
5817    {
5818       left = SCIPsetFeasFloor(set, left);
5819       right = SCIPsetFeasCeil(set, right);
5820    }
5821 
5822    assert(SCIPsetIsLT(set, left, SCIPvarGetUbLocal(var)));
5823    assert(SCIPsetIsGE(set, left, SCIPvarGetLbLocal(var)));
5824    assert(SCIPsetIsGT(set, right, SCIPvarGetLbLocal(var)));
5825    assert(SCIPsetIsLE(set, right, SCIPvarGetUbLocal(var)));
5826    assert(SCIPsetIsLE(set, left, right));
5827 
5828    /* get value of variable in current LP or pseudo solution */
5829    lpval = SCIPvarGetSol(var, tree->focusnodehaslp);
5830 
5831    /* perform the branching;
5832     * set the node selection priority in a way, s.t. a node is preferred whose branching goes in the same direction
5833     * as the deviation from the variable's root solution
5834     */
5835 
5836    /* create child node x <= left */
5837    priority = SCIPtreeCalcNodeselPriority(tree, set, stat, var, SCIP_BRANCHDIR_DOWNWARDS, left);
5838 
5839    /* if LP solution is cutoff in child, compute a new estimate
5840     * otherwise we cannot expect a direct change in the best solution, so we keep the estimate of the parent node
5841     */
5842    if( SCIPsetIsGT(set, lpval, left) )
5843       estimate = SCIPtreeCalcChildEstimate(tree, set, stat, var, left);
5844    else
5845       estimate = SCIPnodeGetEstimate(tree->focusnode);
5846 
5847    SCIPsetDebugMsg(set, " -> creating child: <%s> <= %g (priority: %g, estimate: %g)\n",
5848       SCIPvarGetName(var), left, priority, estimate);
5849 
5850    SCIP_CALL( SCIPnodeCreateChild(&node, blkmem, set, stat, tree, priority, estimate) );
5851    SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue, NULL,
5852          var, left, SCIP_BOUNDTYPE_UPPER, FALSE) );
5853    /* output branching bound change to visualization file */
5854    SCIP_CALL( SCIPvisualUpdateChild(stat->visual, set, stat, node) );
5855 
5856    if( downchild != NULL )
5857       *downchild = node;
5858 
5859    /* create child node with x >= right */
5860    priority = SCIPtreeCalcNodeselPriority(tree, set, stat, var, SCIP_BRANCHDIR_UPWARDS, right);
5861 
5862    if( SCIPsetIsLT(set, lpval, right) )
5863       estimate = SCIPtreeCalcChildEstimate(tree, set, stat, var, right);
5864    else
5865       estimate = SCIPnodeGetEstimate(tree->focusnode);
5866 
5867    SCIPsetDebugMsg(set, " -> creating child: <%s> >= %g (priority: %g, estimate: %g)\n",
5868       SCIPvarGetName(var), right, priority, estimate);
5869 
5870    SCIP_CALL( SCIPnodeCreateChild(&node, blkmem, set, stat, tree, priority, estimate) );
5871    SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
5872          NULL, var, right, SCIP_BOUNDTYPE_LOWER, FALSE) );
5873    /* output branching bound change to visualization file */
5874    SCIP_CALL( SCIPvisualUpdateChild(stat->visual, set, stat, node) );
5875 
5876    if( upchild != NULL )
5877       *upchild = node;
5878 
5879    return SCIP_OKAY;
5880 }
5881 
5882 /** n-ary branching on a variable x
5883  * Branches on variable x such that up to n/2 children are created on each side of the usual branching value.
5884  * The branching value is selected as in SCIPtreeBranchVar().
5885  * If n is 2 or the variables local domain is too small for a branching into n pieces, SCIPtreeBranchVar() is called.
5886  * The parameters minwidth and widthfactor determine the domain width of the branching variable in the child nodes.
5887  * If n is odd, one child with domain width 'width' and having the branching value in the middle is created.
5888  * Otherwise, two children with domain width 'width' and being left and right of the branching value are created.
5889  * Next further nodes to the left and right are created, where width is multiplied by widthfactor with increasing distance from the first nodes.
5890  * The initial width is calculated such that n/2 nodes are created to the left and to the right of the branching value.
5891  * If this value is below minwidth, the initial width is set to minwidth, which may result in creating less than n nodes.
5892  *
5893  * Giving a large value for widthfactor results in creating children with small domain when close to the branching value
5894  * and large domain when closer to the current variable bounds. That is, setting widthfactor to a very large value and n to 3
5895  * results in a ternary branching where the branching variable is mostly fixed in the middle child.
5896  * Setting widthfactor to 1.0 results in children where the branching variable always has the same domain width
5897  * (except for one child if the branching value is not in the middle).
5898  */
SCIPtreeBranchVarNary(SCIP_TREE * tree,SCIP_REOPT * reopt,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_LP * lp,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_VAR * var,SCIP_Real val,int n,SCIP_Real minwidth,SCIP_Real widthfactor,int * nchildren)5899 SCIP_RETCODE SCIPtreeBranchVarNary(
5900    SCIP_TREE*            tree,               /**< branch and bound tree */
5901    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
5902    BMS_BLKMEM*           blkmem,             /**< block memory */
5903    SCIP_SET*             set,                /**< global SCIP settings */
5904    SCIP_STAT*            stat,               /**< problem statistics data */
5905    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
5906    SCIP_PROB*            origprob,           /**< original problem */
5907    SCIP_LP*              lp,                 /**< current LP data */
5908    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
5909    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
5910    SCIP_VAR*             var,                /**< variable to branch on */
5911    SCIP_Real             val,                /**< value to branch on or SCIP_INVALID for branching on current LP/pseudo solution.
5912                                               *   A branching value is required for branching on continuous variables */
5913    int                   n,                  /**< attempted number of children to be created, must be >= 2 */
5914    SCIP_Real             minwidth,           /**< minimal domain width in children */
5915    SCIP_Real             widthfactor,        /**< multiplier for children domain width with increasing distance from val, must be >= 1.0 */
5916    int*                  nchildren           /**< buffer to store number of created children, or NULL */
5917    )
5918 {
5919    SCIP_NODE* node;
5920    SCIP_Real priority;
5921    SCIP_Real estimate;
5922    SCIP_Real lpval;
5923    SCIP_Real width;
5924    SCIP_Bool validval;
5925    SCIP_Real left;
5926    SCIP_Real right;
5927    SCIP_Real bnd;
5928    int i;
5929 
5930    assert(tree != NULL);
5931    assert(set != NULL);
5932    assert(var != NULL);
5933    assert(n >= 2);
5934    assert(minwidth >= 0.0);
5935 
5936    /* if binary branching is requested or we have not enough space for n children, delegate to SCIPtreeBranchVar */
5937    if( n == 2 ||
5938       2.0 * minwidth >= SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) ||
5939       SCIPrelDiff(SCIPvarGetUbLocal(SCIPvarGetProbvar(var)), SCIPvarGetLbLocal(SCIPvarGetProbvar(var))) <= n * SCIPsetEpsilon(set) )
5940    {
5941       SCIP_NODE* downchild;
5942       SCIP_NODE* fixchild;
5943       SCIP_NODE* upchild;
5944 
5945       SCIP_CALL( SCIPtreeBranchVar(tree, reopt, blkmem, set, stat, transprob, origprob, lp, branchcand, eventqueue, var, val,
5946             &downchild, &fixchild, &upchild) );
5947 
5948       if( nchildren != NULL )
5949          *nchildren = (downchild != NULL ? 1 : 0) + (fixchild != NULL ? 1 : 0) + (upchild != NULL ? 1 : 0);
5950 
5951       return SCIP_OKAY;
5952    }
5953 
5954    /* store whether a valid value was given for branching */
5955    validval = (val != SCIP_INVALID);  /*lint !e777 */
5956 
5957    /* get the corresponding active problem variable
5958     * if branching value is given, then transform it to the value of the active variable */
5959    if( validval )
5960    {
5961       SCIP_Real scalar;
5962       SCIP_Real constant;
5963 
5964       scalar   = 1.0;
5965       constant = 0.0;
5966 
5967       SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &scalar, &constant) );
5968 
5969       if( scalar == 0.0 )
5970       {
5971          SCIPerrorMessage("cannot branch on fixed variable <%s>\n", SCIPvarGetName(var));
5972          return SCIP_INVALIDDATA;
5973       }
5974 
5975       /* we should have givenvariable = scalar * activevariable + constant */
5976       val = (val - constant) / scalar;
5977    }
5978    else
5979       var = SCIPvarGetProbvar(var);
5980 
5981    if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED || SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
5982    {
5983       SCIPerrorMessage("cannot branch on fixed or multi-aggregated variable <%s>\n", SCIPvarGetName(var));
5984       SCIPABORT();
5985       return SCIP_INVALIDDATA; /*lint !e527*/
5986    }
5987 
5988    /* ensure, that branching on continuous variables will only be performed when a branching point is given. */
5989    if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS && !validval )
5990    {
5991       SCIPerrorMessage("Cannot branch on continuous variable <%s> without a given branching value.", SCIPvarGetName(var));
5992       SCIPABORT();
5993       return SCIP_INVALIDDATA; /*lint !e527*/
5994    }
5995 
5996    assert(SCIPvarIsActive(var));
5997    assert(SCIPvarGetProbindex(var) >= 0);
5998    assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);
5999    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, SCIPvarGetLbLocal(var)));
6000    assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPsetIsFeasIntegral(set, SCIPvarGetUbLocal(var)));
6001    assert(SCIPsetIsLT(set, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)));
6002 
6003    /* get value of variable in current LP or pseudo solution */
6004    lpval = SCIPvarGetSol(var, tree->focusnodehaslp);
6005 
6006    /* if there was no explicit value given for branching, branch on current LP or pseudo solution value */
6007    if( !validval )
6008    {
6009       val = lpval;
6010 
6011       /* avoid branching on infinite values in pseudo solution */
6012       if( SCIPsetIsInfinity(set, -val) || SCIPsetIsInfinity(set, val) )
6013       {
6014          val = SCIPvarGetWorstBoundLocal(var);
6015 
6016          /* if both bounds are infinite, choose zero as branching point */
6017          if( SCIPsetIsInfinity(set, -val) || SCIPsetIsInfinity(set, val) )
6018          {
6019             assert(SCIPsetIsInfinity(set, -SCIPvarGetLbLocal(var)));
6020             assert(SCIPsetIsInfinity(set, SCIPvarGetUbLocal(var)));
6021             val = 0.0;
6022          }
6023       }
6024    }
6025 
6026    assert(SCIPsetIsFeasGE(set, val, SCIPvarGetLbLocal(var)));
6027    assert(SCIPsetIsFeasLE(set, val, SCIPvarGetUbLocal(var)));
6028    assert(SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS ||
6029       SCIPsetIsRelEQ(set, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) ||
6030       (SCIPsetIsLT(set, 2.1*SCIPvarGetLbLocal(var), 2.1*val) && SCIPsetIsLT(set, 2.1*val, 2.1*SCIPvarGetUbLocal(var))) );  /* see comment in SCIPbranchVarVal */
6031 
6032    /* calculate minimal distance of val from bounds */
6033    width = SCIP_REAL_MAX;
6034    if( !SCIPsetIsInfinity(set, -SCIPvarGetLbLocal(var)) )
6035    {
6036       width = val - SCIPvarGetLbLocal(var);
6037    }
6038    if( !SCIPsetIsInfinity(set,  SCIPvarGetUbLocal(var)) )
6039    {
6040       width = MIN(width, SCIPvarGetUbLocal(var) - val); /*lint !e666*/
6041    }
6042    /* calculate initial domain width of child nodes
6043     * if we have at least one finite bound, choose width such that we have roughly the same number of nodes left and right of val
6044     */
6045    if( width == SCIP_REAL_MAX ) /*lint !e777*/
6046    {
6047       /* unbounded variable, let's create a child with a small domain */
6048       width = 1.0;
6049    }
6050    else if( widthfactor == 1.0 )
6051    {
6052       /* most domains get same size */
6053       width /= n/2; /*lint !e653*/ /* rounding is ok at this point */
6054    }
6055    else
6056    {
6057       /* width is increased by widthfactor for each child
6058        * if n is even, compute width such that we can create n/2 nodes with width
6059        * width, widthfactor*width, ..., widthfactor^(n/2)*width on each side, i.e.,
6060        *      sum(width * widthfactor^(i-1), i = 1..n/2) = min(ub-val, val-lb)
6061        *  <-> width * (widthfactor^(n/2) - 1) / (widthfactor - 1) = min(ub-val, val-lb)
6062        *
6063        * if n is odd, compute width such that we can create one middle node with width width
6064        * and n/2 nodes with width widthfactor*width, ..., widthfactor^(n/2)*width on each side, i.e.,
6065        *      width/2 + sum(width * widthfactor^i, i = 1..n/2) = min(ub-val, val-lb)
6066        *  <-> width * (1/2 + widthfactor * (widthfactor^(n/2) - 1) / (widthfactor - 1) = min(ub-val, val-lb)
6067        */
6068       assert(widthfactor > 1.0);
6069       if( n % 2 == 0 )
6070          width *= (widthfactor - 1.0) / (pow(widthfactor, (SCIP_Real)(n/2)) - 1.0); /*lint !e653*/
6071       else
6072          width /= 0.5 + widthfactor * (pow(widthfactor, (SCIP_Real)(n/2)) - 1.0) / (widthfactor - 1.0); /*lint !e653*/
6073    }
6074    if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS )
6075       minwidth = MAX(1.0, minwidth);
6076    if( width < minwidth )
6077       width = minwidth;
6078    assert(SCIPsetIsPositive(set, width));
6079 
6080    SCIPsetDebugMsg(set, "%d-ary branching on variable <%s> [%g, %g] around %g, initial width = %g\n",
6081       n, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), val, width);
6082 
6083    if( nchildren != NULL )
6084       *nchildren = 0;
6085 
6086    /* initialize upper bound on children left of val and children right of val
6087     * if we are supposed to create an odd number of children, then create a child that has val in the middle of its domain */
6088    if( n % 2 == 1 )
6089    {
6090       left  = val - width/2.0;
6091       right = val + width/2.0;
6092       SCIPvarAdjustLb(var, set, &left);
6093       SCIPvarAdjustUb(var, set, &right);
6094 
6095       /* create child node left <= x <= right, if left <= right */
6096       if( left <= right )
6097       {
6098          priority = SCIPtreeCalcNodeselPriority(tree, set, stat, var, SCIP_BRANCHDIR_FIXED, val); /* ????????????? how to compute priority for such a child? */
6099          /* if LP solution is cutoff in child, compute a new estimate
6100           * otherwise we cannot expect a direct change in the best solution, so we keep the estimate of the parent node */
6101          if( SCIPsetIsLT(set, lpval, left) )
6102             estimate = SCIPtreeCalcChildEstimate(tree, set, stat, var, left);
6103          else if( SCIPsetIsGT(set, lpval, right) )
6104             estimate = SCIPtreeCalcChildEstimate(tree, set, stat, var, right);
6105          else
6106             estimate = SCIPnodeGetEstimate(tree->focusnode);
6107 
6108          SCIPsetDebugMsg(set, " -> creating middle child: %g <= <%s> <= %g (priority: %g, estimate: %g, width: %g)\n",
6109             left, SCIPvarGetName(var), right, priority, estimate, right - left);
6110 
6111          SCIP_CALL( SCIPnodeCreateChild(&node, blkmem, set, stat, tree, priority, estimate) );
6112          SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
6113                eventqueue, NULL, var, left , SCIP_BOUNDTYPE_LOWER, FALSE) );
6114          SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
6115                NULL, var, right, SCIP_BOUNDTYPE_UPPER, FALSE) );
6116          /* output branching bound change to visualization file */
6117          SCIP_CALL( SCIPvisualUpdateChild(stat->visual, set, stat, node) );
6118 
6119          if( nchildren != NULL )
6120             ++*nchildren;
6121       }
6122       --n;
6123 
6124       if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS )
6125       {
6126          /* if it's a discrete variable, we can use left-1 and right+1 as upper and lower bounds for following nodes on the left and right, resp. */
6127          left  -= 1.0;
6128          right += 1.0;
6129       }
6130 
6131       width *= widthfactor;
6132    }
6133    else
6134    {
6135       if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS )
6136       {
6137          left  = SCIPsetFloor(set, val);
6138          right = SCIPsetCeil(set, val);
6139          if( right - left < 0.5 )
6140             left -= 1.0;
6141       }
6142       else if( SCIPsetIsZero(set, val) )
6143       {
6144          left  = 0.0;
6145          right = 0.0;
6146       }
6147       else
6148       {
6149          left  = val;
6150          right = val;
6151       }
6152    }
6153 
6154    assert(n % 2 == 0);
6155    n /= 2;
6156    for( i = 0; i < n; ++i )
6157    {
6158       /* create child node left - width <= x <= left, if left > lb(x) or x is discrete */
6159       if( SCIPsetIsRelLT(set, SCIPvarGetLbLocal(var), left) || SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS )
6160       {
6161          /* new lower bound should be variables lower bound, if we are in the last round or left - width is very close to lower bound
6162           * otherwise we take left - width
6163           */
6164          if( i == n-1 || SCIPsetIsRelEQ(set, SCIPvarGetLbLocal(var), left - width))
6165          {
6166             bnd = SCIPvarGetLbLocal(var);
6167          }
6168          else
6169          {
6170             bnd = left - width;
6171             SCIPvarAdjustLb(var, set, &bnd);
6172             bnd = MAX(SCIPvarGetLbLocal(var), bnd); /*lint !e666*/
6173          }
6174          assert(SCIPsetIsRelLT(set, bnd, left));
6175 
6176          /* the nodeselection priority of nodes is decreased as more as they are away from val */
6177          priority = SCIPtreeCalcNodeselPriority(tree, set, stat, var, SCIP_BRANCHDIR_DOWNWARDS, bnd) / (i+1);
6178          /* if LP solution is cutoff in child, compute a new estimate
6179           * otherwise we cannot expect a direct change in the best solution, so we keep the estimate of the parent node */
6180          if( SCIPsetIsLT(set, lpval, bnd) )
6181             estimate = SCIPtreeCalcChildEstimate(tree, set, stat, var, bnd);
6182          else if( SCIPsetIsGT(set, lpval, left) )
6183             estimate = SCIPtreeCalcChildEstimate(tree, set, stat, var, left);
6184          else
6185             estimate = SCIPnodeGetEstimate(tree->focusnode);
6186 
6187          SCIPsetDebugMsg(set, " -> creating left  child: %g <= <%s> <= %g (priority: %g, estimate: %g, width: %g)\n",
6188             bnd, SCIPvarGetName(var), left, priority, estimate, left - bnd);
6189 
6190          SCIP_CALL( SCIPnodeCreateChild(&node, blkmem, set, stat, tree, priority, estimate) );
6191          if( SCIPsetIsGT(set, bnd, SCIPvarGetLbLocal(var)) )
6192          {
6193             SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
6194                NULL, var, bnd, SCIP_BOUNDTYPE_LOWER, FALSE) );
6195          }
6196          SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
6197             NULL, var, left, SCIP_BOUNDTYPE_UPPER, FALSE) );
6198          /* output branching bound change to visualization file */
6199          SCIP_CALL( SCIPvisualUpdateChild(stat->visual, set, stat, node) );
6200 
6201          if( nchildren != NULL )
6202             ++*nchildren;
6203 
6204          left = bnd;
6205          if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS )
6206             left -= 1.0;
6207       }
6208 
6209       /* create child node right <= x <= right + width, if right < ub(x) */
6210       if( SCIPsetIsRelGT(set, SCIPvarGetUbLocal(var), right) || SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS )
6211       {
6212          /* new upper bound should be variables upper bound, if we are in the last round or right + width is very close to upper bound
6213           * otherwise we take right + width
6214           */
6215          if( i == n-1 || SCIPsetIsRelEQ(set, SCIPvarGetUbLocal(var), right + width))
6216          {
6217             bnd = SCIPvarGetUbLocal(var);
6218          }
6219          else
6220          {
6221             bnd = right + width;
6222             SCIPvarAdjustUb(var, set, &bnd);
6223             bnd = MIN(SCIPvarGetUbLocal(var), bnd); /*lint !e666*/
6224          }
6225          assert(SCIPsetIsRelGT(set, bnd, right));
6226 
6227          /* the nodeselection priority of nodes is decreased as more as they are away from val */
6228          priority = SCIPtreeCalcNodeselPriority(tree, set, stat, var, SCIP_BRANCHDIR_UPWARDS, bnd) / (i+1);
6229          /* if LP solution is cutoff in child, compute a new estimate
6230           * otherwise we cannot expect a direct change in the best solution, so we keep the estimate of the parent node */
6231          if( SCIPsetIsLT(set, lpval, right) )
6232             estimate = SCIPtreeCalcChildEstimate(tree, set, stat, var, right);
6233          else if( SCIPsetIsGT(set, lpval, bnd) )
6234             estimate = SCIPtreeCalcChildEstimate(tree, set, stat, var, bnd);
6235          else
6236             estimate = SCIPnodeGetEstimate(tree->focusnode);
6237 
6238          SCIPsetDebugMsg(set, " -> creating right child: %g <= <%s> <= %g (priority: %g, estimate: %g, width: %g)\n",
6239             right, SCIPvarGetName(var), bnd, priority, estimate, bnd - right);
6240 
6241          SCIP_CALL( SCIPnodeCreateChild(&node, blkmem, set, stat, tree, priority, estimate) );
6242          SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
6243             NULL, var, right, SCIP_BOUNDTYPE_LOWER, FALSE) );
6244          if( SCIPsetIsLT(set, bnd, SCIPvarGetUbLocal(var)) )
6245          {
6246             SCIP_CALL( SCIPnodeAddBoundchg(node, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
6247                NULL, var, bnd, SCIP_BOUNDTYPE_UPPER, FALSE) );
6248          }
6249          /* output branching bound change to visualization file */
6250          SCIP_CALL( SCIPvisualUpdateChild(stat->visual, set, stat, node) );
6251 
6252          if( nchildren != NULL )
6253             ++*nchildren;
6254 
6255          right = bnd;
6256          if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS )
6257             right += 1.0;
6258       }
6259 
6260       width *= widthfactor;
6261    }
6262 
6263    return SCIP_OKAY;
6264 }
6265 
6266 /** adds a diving bound change to the tree together with the information if this is a bound change
6267  *  for the preferred direction or not
6268  */
6269 #define ARRAYGROWTH 5
SCIPtreeAddDiveBoundChange(SCIP_TREE * tree,BMS_BLKMEM * blkmem,SCIP_VAR * var,SCIP_BRANCHDIR dir,SCIP_Real value,SCIP_Bool preferred)6270 SCIP_RETCODE SCIPtreeAddDiveBoundChange(
6271    SCIP_TREE*            tree,               /**< branch and bound tree */
6272    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
6273    SCIP_VAR*             var,                /**< variable to apply the bound change to */
6274    SCIP_BRANCHDIR        dir,                /**< direction of the bound change */
6275    SCIP_Real             value,              /**< value to adjust this variable bound to */
6276    SCIP_Bool             preferred           /**< is this a bound change for the preferred child? */
6277    )
6278 {
6279    int idx = preferred ? 0 : 1;
6280    int pos = tree->ndivebdchanges[idx];
6281 
6282    assert(pos < tree->divebdchgsize[idx]);
6283 
6284    if( pos == tree->divebdchgsize[idx] - 1 )
6285    {
6286       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &tree->divebdchgdirs[idx], tree->divebdchgsize[idx], tree->divebdchgsize[idx] + ARRAYGROWTH) ); /*lint !e866*/
6287       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &tree->divebdchgvars[idx], tree->divebdchgsize[idx], tree->divebdchgsize[idx] + ARRAYGROWTH) ); /*lint !e866*/
6288       SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &tree->divebdchgvals[idx], tree->divebdchgsize[idx], tree->divebdchgsize[idx] + ARRAYGROWTH) ); /*lint !e866*/
6289       tree->divebdchgsize[idx] += ARRAYGROWTH;
6290    }
6291 
6292    tree->divebdchgvars[idx][pos] = var;
6293    tree->divebdchgdirs[idx][pos] = dir;
6294    tree->divebdchgvals[idx][pos] = value;
6295 
6296    ++tree->ndivebdchanges[idx];
6297 
6298    return SCIP_OKAY;
6299 }
6300 
6301 /** get the dive bound change data for the preferred or the alternative direction */
SCIPtreeGetDiveBoundChangeData(SCIP_TREE * tree,SCIP_VAR *** variables,SCIP_BRANCHDIR ** directions,SCIP_Real ** values,int * ndivebdchgs,SCIP_Bool preferred)6302 void SCIPtreeGetDiveBoundChangeData(
6303    SCIP_TREE*            tree,               /**< branch and bound tree */
6304    SCIP_VAR***           variables,          /**< pointer to store variables for the specified direction */
6305    SCIP_BRANCHDIR**      directions,         /**< pointer to store the branching directions */
6306    SCIP_Real**           values,             /**< pointer to store bound change values */
6307    int*                  ndivebdchgs,        /**< pointer to store the number of dive bound changes */
6308    SCIP_Bool             preferred           /**< should the dive bound changes for the preferred child be output? */
6309    )
6310 {
6311    int idx = preferred ? 0 : 1;
6312 
6313    assert(variables != NULL);
6314    assert(directions != NULL);
6315    assert(values != NULL);
6316    assert(ndivebdchgs != NULL);
6317 
6318    *variables = tree->divebdchgvars[idx];
6319    *directions = tree->divebdchgdirs[idx];
6320    *values = tree->divebdchgvals[idx];
6321    *ndivebdchgs = tree->ndivebdchanges[idx];
6322 }
6323 
6324 /** clear the tree bound change data structure */
SCIPtreeClearDiveBoundChanges(SCIP_TREE * tree)6325 void SCIPtreeClearDiveBoundChanges(
6326    SCIP_TREE*            tree                /**< branch and bound tree */
6327    )
6328 {
6329    int p;
6330 
6331    for( p = 0; p < 2; ++p )
6332       tree->ndivebdchanges[p] = 0;
6333 }
6334 
6335 /** creates a probing child node of the current node, which must be the focus node, the current refocused node,
6336  *  or another probing node; if the current node is the focus or a refocused node, the created probing node is
6337  *  installed as probing root node
6338  */
6339 static
treeCreateProbingNode(SCIP_TREE * tree,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_LP * lp)6340 SCIP_RETCODE treeCreateProbingNode(
6341    SCIP_TREE*            tree,               /**< branch and bound tree */
6342    BMS_BLKMEM*           blkmem,             /**< block memory */
6343    SCIP_SET*             set,                /**< global SCIP settings */
6344    SCIP_LP*              lp                  /**< current LP data */
6345    )
6346 {
6347    SCIP_NODE* currentnode;
6348    SCIP_NODE* node;
6349    SCIP_RETCODE retcode;
6350 
6351    assert(tree != NULL);
6352    assert(SCIPtreeIsPathComplete(tree));
6353    assert(tree->pathlen > 0);
6354    assert(blkmem != NULL);
6355    assert(set != NULL);
6356 
6357    /* get the current node */
6358    currentnode = SCIPtreeGetCurrentNode(tree);
6359    assert(SCIPnodeGetType(currentnode) == SCIP_NODETYPE_FOCUSNODE
6360       || SCIPnodeGetType(currentnode) == SCIP_NODETYPE_REFOCUSNODE
6361       || SCIPnodeGetType(currentnode) == SCIP_NODETYPE_PROBINGNODE);
6362    assert((SCIPnodeGetType(currentnode) == SCIP_NODETYPE_PROBINGNODE) == SCIPtreeProbing(tree));
6363 
6364    /* create the node data structure */
6365    SCIP_CALL( nodeCreate(&node, blkmem, set) );
6366    assert(node != NULL);
6367 
6368    /* mark node to be a probing node */
6369    node->nodetype = SCIP_NODETYPE_PROBINGNODE; /*lint !e641*/
6370 
6371    /* create the probingnode data */
6372    SCIP_CALL( probingnodeCreate(&node->data.probingnode, blkmem, lp) );
6373 
6374    /* make the current node the parent of the new probing node */
6375    retcode = nodeAssignParent(node, blkmem, set, tree, currentnode, 0.0);
6376 
6377    /* if we reached the maximal depth level we clean up the allocated memory and stop */
6378    if( retcode == SCIP_MAXDEPTHLEVEL )
6379    {
6380       SCIP_CALL( probingnodeFree(&(node->data.probingnode), blkmem, lp) );
6381       BMSfreeBlockMemory(blkmem, &node);
6382    }
6383    SCIP_CALL( retcode );
6384    assert(SCIPnodeGetDepth(node) == tree->pathlen);
6385 
6386    /* check, if the node is the probing root node */
6387    if( tree->probingroot == NULL )
6388    {
6389       tree->probingroot = node;
6390       SCIPsetDebugMsg(set, "created probing root node #%" SCIP_LONGINT_FORMAT " at depth %d\n",
6391          SCIPnodeGetNumber(node), SCIPnodeGetDepth(node));
6392    }
6393    else
6394    {
6395       assert(SCIPnodeGetType(tree->probingroot) == SCIP_NODETYPE_PROBINGNODE);
6396       assert(SCIPnodeGetDepth(tree->probingroot) < SCIPnodeGetDepth(node));
6397 
6398       SCIPsetDebugMsg(set, "created probing child node #%" SCIP_LONGINT_FORMAT " at depth %d, probing depth %d\n",
6399          SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), SCIPnodeGetDepth(node) - SCIPnodeGetDepth(tree->probingroot));
6400 
6401       currentnode->data.probingnode->ncols = SCIPlpGetNCols(lp);
6402       currentnode->data.probingnode->nrows = SCIPlpGetNRows(lp);
6403 
6404       SCIPsetDebugMsg(set, "updated probingnode information of parent (%d cols, %d rows)\n",
6405          currentnode->data.probingnode->ncols, currentnode->data.probingnode->nrows);
6406    }
6407 
6408    /* create the new active path */
6409    SCIP_CALL( treeEnsurePathMem(tree, set, tree->pathlen+1) );
6410    node->active = TRUE;
6411    tree->path[tree->pathlen] = node;
6412    tree->pathlen++;
6413 
6414    /* update the path LP size for the previous node and set the (initial) path LP size for the newly created node */
6415    SCIP_CALL( treeUpdatePathLPSize(tree, tree->pathlen-2) );
6416 
6417    /* mark the LP's size */
6418    SCIPlpMarkSize(lp);
6419    assert(tree->pathlen >= 2);
6420    assert(lp->firstnewrow == tree->pathnlprows[tree->pathlen-1]); /* marked LP size should be initial size of new node */
6421    assert(lp->firstnewcol == tree->pathnlpcols[tree->pathlen-1]);
6422 
6423    /* the current probing node does not yet have a solved LP */
6424    tree->probingnodehaslp = FALSE;
6425 
6426    return SCIP_OKAY;
6427 }
6428 
6429 /** switches to probing mode and creates a probing root */
SCIPtreeStartProbing(SCIP_TREE * tree,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_LP * lp,SCIP_RELAXATION * relaxation,SCIP_PROB * transprob,SCIP_Bool strongbranching)6430 SCIP_RETCODE SCIPtreeStartProbing(
6431    SCIP_TREE*            tree,               /**< branch and bound tree */
6432    BMS_BLKMEM*           blkmem,             /**< block memory */
6433    SCIP_SET*             set,                /**< global SCIP settings */
6434    SCIP_LP*              lp,                 /**< current LP data */
6435    SCIP_RELAXATION*      relaxation,         /**< global relaxation data */
6436    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
6437    SCIP_Bool             strongbranching     /**< is the probing mode used for strongbranching? */
6438    )
6439 {
6440    assert(tree != NULL);
6441    assert(tree->probinglpistate == NULL);
6442    assert(tree->probinglpinorms == NULL);
6443    assert(!SCIPtreeProbing(tree));
6444    assert(lp != NULL);
6445 
6446    SCIPsetDebugMsg(set, "probing started in depth %d (LP flushed: %u, LP solved: %u, solstat: %d), probing root in depth %d\n",
6447       tree->pathlen-1, lp->flushed, lp->solved, SCIPlpGetSolstat(lp), tree->pathlen);
6448 
6449    /* store all marked constraints for propagation */
6450    SCIP_CALL( SCIPconshdlrsStorePropagationStatus(set, set->conshdlrs, set->nconshdlrs) );
6451 
6452    /* inform LP about probing mode */
6453    SCIP_CALL( SCIPlpStartProbing(lp) );
6454 
6455    assert(!lp->divingobjchg);
6456 
6457    /* remember, whether the LP was flushed and solved */
6458    tree->probinglpwasflushed = lp->flushed;
6459    tree->probinglpwassolved = lp->solved;
6460    tree->probingloadlpistate = FALSE;
6461    tree->probinglpwasrelax = lp->isrelax;
6462    lp->isrelax = TRUE;
6463    tree->probingsolvedlp = FALSE;
6464    tree->probingobjchanged = FALSE;
6465    lp->divingobjchg = FALSE;
6466    tree->probingsumchgdobjs = 0;
6467    tree->sbprobing = strongbranching;
6468 
6469    /* remember the LP state in order to restore the LP solution quickly after probing */
6470    /**@todo could the lp state be worth storing if the LP is not flushed (and hence not solved)? */
6471    if( lp->flushed && lp->solved )
6472    {
6473       SCIP_CALL( SCIPlpGetState(lp, blkmem, &tree->probinglpistate) );
6474       SCIP_CALL( SCIPlpGetNorms(lp, blkmem, &tree->probinglpinorms) );
6475       tree->probinglpwasprimfeas = lp->primalfeasible;
6476       tree->probinglpwasprimchecked = lp->primalchecked;
6477       tree->probinglpwasdualfeas = lp->dualfeasible;
6478       tree->probinglpwasdualchecked = lp->dualchecked;
6479    }
6480 
6481    /* remember the relaxation solution to reset it later */
6482    if( SCIPrelaxationIsSolValid(relaxation) )
6483    {
6484       SCIP_CALL( SCIPtreeStoreRelaxSol(tree, set, relaxation, transprob) );
6485    }
6486 
6487    /* create temporary probing root node */
6488    SCIP_CALL( treeCreateProbingNode(tree, blkmem, set, lp) );
6489    assert(SCIPtreeProbing(tree));
6490 
6491    return SCIP_OKAY;
6492 }
6493 
6494 /** creates a new probing child node in the probing path */
SCIPtreeCreateProbingNode(SCIP_TREE * tree,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_LP * lp)6495 SCIP_RETCODE SCIPtreeCreateProbingNode(
6496    SCIP_TREE*            tree,               /**< branch and bound tree */
6497    BMS_BLKMEM*           blkmem,             /**< block memory */
6498    SCIP_SET*             set,                /**< global SCIP settings */
6499    SCIP_LP*              lp                  /**< current LP data */
6500    )
6501 {
6502    assert(SCIPtreeProbing(tree));
6503 
6504    SCIPsetDebugMsg(set, "new probing child in depth %d (probing depth: %d)\n", tree->pathlen, tree->pathlen-1 - SCIPnodeGetDepth(tree->probingroot));
6505 
6506    /* create temporary probing root node */
6507    SCIP_CALL( treeCreateProbingNode(tree, blkmem, set, lp) );
6508 
6509    return SCIP_OKAY;
6510 }
6511 
6512 /** sets the LP state for the current probing node
6513  *
6514  *  @note state and norms are stored at the node and later released by SCIP; therefore, the pointers are set
6515  *        to NULL by the method
6516  *
6517  *  @note the pointers to state and norms must not be NULL; however, they may point to a NULL pointer if the
6518  *        respective information should not be set
6519  */
SCIPtreeSetProbingLPState(SCIP_TREE * tree,BMS_BLKMEM * blkmem,SCIP_LP * lp,SCIP_LPISTATE ** lpistate,SCIP_LPINORMS ** lpinorms,SCIP_Bool primalfeas,SCIP_Bool dualfeas)6520 SCIP_RETCODE SCIPtreeSetProbingLPState(
6521    SCIP_TREE*            tree,               /**< branch and bound tree */
6522    BMS_BLKMEM*           blkmem,             /**< block memory */
6523    SCIP_LP*              lp,                 /**< current LP data */
6524    SCIP_LPISTATE**       lpistate,           /**< pointer to LP state information (like basis information) */
6525    SCIP_LPINORMS**       lpinorms,           /**< pointer to LP pricing norms information */
6526    SCIP_Bool             primalfeas,         /**< primal feasibility when LP state information was stored */
6527    SCIP_Bool             dualfeas            /**< dual feasibility when LP state information was stored */
6528    )
6529 {
6530    SCIP_NODE* node;
6531 
6532    assert(tree != NULL);
6533    assert(SCIPtreeProbing(tree));
6534    assert(lpistate != NULL);
6535    assert(lpinorms != NULL);
6536 
6537    /* get the current probing node */
6538    node = SCIPtreeGetCurrentNode(tree);
6539 
6540    /* this check is necessary to avoid cppcheck warnings */
6541    if( node == NULL )
6542       return SCIP_INVALIDDATA;
6543 
6544    assert(SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE);
6545    assert(node->data.probingnode != NULL);
6546 
6547    /* free already present LP state */
6548    if( node->data.probingnode->lpistate != NULL )
6549    {
6550       SCIP_CALL( SCIPlpFreeState(lp, blkmem, &(node->data.probingnode->lpistate)) );
6551    }
6552 
6553    /* free already present LP pricing norms */
6554    if( node->data.probingnode->lpinorms != NULL )
6555    {
6556       SCIP_CALL( SCIPlpFreeNorms(lp, blkmem, &(node->data.probingnode->lpinorms)) );
6557    }
6558 
6559    node->data.probingnode->lpistate = *lpistate;
6560    node->data.probingnode->lpinorms = *lpinorms;
6561    node->data.probingnode->lpwasprimfeas = primalfeas;
6562    node->data.probingnode->lpwasdualfeas = dualfeas;
6563 
6564    /* set the pointers to NULL to avoid that they are still used and modified by the caller */
6565    *lpistate = NULL;
6566    *lpinorms = NULL;
6567 
6568    tree->probingloadlpistate = TRUE;
6569 
6570    return SCIP_OKAY;
6571 }
6572 
6573 /** loads the LP state for the current probing node */
SCIPtreeLoadProbingLPState(SCIP_TREE * tree,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_EVENTQUEUE * eventqueue,SCIP_LP * lp)6574 SCIP_RETCODE SCIPtreeLoadProbingLPState(
6575    SCIP_TREE*            tree,               /**< branch and bound tree */
6576    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
6577    SCIP_SET*             set,                /**< global SCIP settings */
6578    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
6579    SCIP_LP*              lp                  /**< current LP data */
6580    )
6581 {
6582    assert(tree != NULL);
6583    assert(SCIPtreeProbing(tree));
6584 
6585    /* loading the LP state is only necessary if we backtracked */
6586    if( tree->probingloadlpistate )
6587    {
6588       SCIP_NODE* node;
6589       SCIP_LPISTATE* lpistate;
6590       SCIP_LPINORMS* lpinorms;
6591       SCIP_Bool lpwasprimfeas = FALSE;
6592       SCIP_Bool lpwasprimchecked = FALSE;
6593       SCIP_Bool lpwasdualfeas = FALSE;
6594       SCIP_Bool lpwasdualchecked = FALSE;
6595 
6596       /* get the current probing node */
6597       node = SCIPtreeGetCurrentNode(tree);
6598       assert(node != NULL);
6599       assert(SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE);
6600 
6601       /* search the last node where an LP state information was attached */
6602       lpistate = NULL;
6603       lpinorms = NULL;
6604       do
6605       {
6606          assert(SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE);
6607          assert(node->data.probingnode != NULL);
6608          if( node->data.probingnode->lpistate != NULL )
6609          {
6610             lpistate = node->data.probingnode->lpistate;
6611             lpinorms = node->data.probingnode->lpinorms;
6612             lpwasprimfeas = node->data.probingnode->lpwasprimfeas;
6613             lpwasprimchecked = node->data.probingnode->lpwasprimchecked;
6614             lpwasdualfeas = node->data.probingnode->lpwasdualfeas;
6615             lpwasdualchecked = node->data.probingnode->lpwasdualchecked;
6616             break;
6617          }
6618          node = node->parent;
6619          assert(node != NULL); /* the root node cannot be a probing node! */
6620       }
6621       while( SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE );
6622 
6623       /* if there was no LP information stored in the probing nodes, use the one stored before probing started */
6624       if( lpistate == NULL )
6625       {
6626          lpistate = tree->probinglpistate;
6627          lpinorms = tree->probinglpinorms;
6628          lpwasprimfeas = tree->probinglpwasprimfeas;
6629          lpwasprimchecked = tree->probinglpwasprimchecked;
6630          lpwasdualfeas = tree->probinglpwasdualfeas;
6631          lpwasdualchecked = tree->probinglpwasdualchecked;
6632       }
6633 
6634       /* set the LP state */
6635       if( lpistate != NULL )
6636       {
6637          SCIP_CALL( SCIPlpSetState(lp, blkmem, set, eventqueue, lpistate,
6638                lpwasprimfeas, lpwasprimchecked, lpwasdualfeas, lpwasdualchecked) );
6639       }
6640 
6641       /* set the LP pricing norms */
6642       if( lpinorms != NULL )
6643       {
6644          SCIP_CALL( SCIPlpSetNorms(lp, blkmem, lpinorms) );
6645       }
6646 
6647       /* now we don't need to load the LP state again until the next backtracking */
6648       tree->probingloadlpistate = FALSE;
6649    }
6650 
6651    return SCIP_OKAY;
6652 }
6653 
6654 /** marks the probing node to have a solved LP relaxation */
SCIPtreeMarkProbingNodeHasLP(SCIP_TREE * tree,BMS_BLKMEM * blkmem,SCIP_LP * lp)6655 SCIP_RETCODE SCIPtreeMarkProbingNodeHasLP(
6656    SCIP_TREE*            tree,               /**< branch and bound tree */
6657    BMS_BLKMEM*           blkmem,             /**< block memory */
6658    SCIP_LP*              lp                  /**< current LP data */
6659    )
6660 {
6661    SCIP_NODE* node;
6662 
6663    assert(tree != NULL);
6664    assert(SCIPtreeProbing(tree));
6665 
6666    /* mark the probing node to have an LP */
6667    tree->probingnodehaslp = TRUE;
6668 
6669    /* get current probing node */
6670    node = SCIPtreeGetCurrentNode(tree);
6671    assert(SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE);
6672    assert(node != NULL && node->data.probingnode != NULL);
6673 
6674    /* update LP information in probingnode data */
6675    /* cppcheck-suppress nullPointer */
6676    SCIP_CALL( probingnodeUpdate(node->data.probingnode, blkmem, tree, lp) );
6677 
6678    return SCIP_OKAY;
6679 }
6680 
6681 /** undoes all changes to the problem applied in probing up to the given probing depth */
6682 static
treeBacktrackProbing(SCIP_TREE * tree,SCIP_REOPT * reopt,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_LP * lp,SCIP_PRIMAL * primal,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter,SCIP_CLIQUETABLE * cliquetable,int probingdepth)6683 SCIP_RETCODE treeBacktrackProbing(
6684    SCIP_TREE*            tree,               /**< branch and bound tree */
6685    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
6686    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
6687    SCIP_SET*             set,                /**< global SCIP settings */
6688    SCIP_STAT*            stat,               /**< problem statistics */
6689    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
6690    SCIP_PROB*            origprob,           /**< original problem */
6691    SCIP_LP*              lp,                 /**< current LP data */
6692    SCIP_PRIMAL*          primal,             /**< primal data structure */
6693    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
6694    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
6695    SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
6696    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
6697    int                   probingdepth        /**< probing depth of the node in the probing path that should be reactivated,
6698                                               *   -1 to even deactivate the probing root, thus exiting probing mode */
6699    )
6700 {
6701    int newpathlen;
6702    int i;
6703 
6704    assert(tree != NULL);
6705    assert(SCIPtreeProbing(tree));
6706    assert(tree->probingroot != NULL);
6707    assert(tree->focusnode != NULL);
6708    assert(SCIPnodeGetType(tree->probingroot) == SCIP_NODETYPE_PROBINGNODE);
6709    assert(SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_FOCUSNODE
6710       || SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_REFOCUSNODE);
6711    assert(tree->probingroot->parent == tree->focusnode);
6712    assert(SCIPnodeGetDepth(tree->probingroot) == SCIPnodeGetDepth(tree->focusnode)+1);
6713    assert(tree->pathlen >= 2);
6714    assert(SCIPnodeGetType(tree->path[tree->pathlen-1]) == SCIP_NODETYPE_PROBINGNODE);
6715    assert(-1 <= probingdepth && probingdepth <= SCIPtreeGetProbingDepth(tree));
6716 
6717    treeCheckPath(tree);
6718 
6719    newpathlen = SCIPnodeGetDepth(tree->probingroot) + probingdepth + 1;
6720    assert(newpathlen >= 1); /* at least root node of the tree remains active */
6721 
6722    /* check if we have to do any backtracking */
6723    if( newpathlen < tree->pathlen )
6724    {
6725       int ncols;
6726       int nrows;
6727 
6728       /* the correct LP size of the node to which we backtracked is stored as initial LP size for its child */
6729       assert(SCIPnodeGetType(tree->path[newpathlen]) == SCIP_NODETYPE_PROBINGNODE);
6730       ncols = tree->path[newpathlen]->data.probingnode->ninitialcols;
6731       nrows = tree->path[newpathlen]->data.probingnode->ninitialrows;
6732       assert(ncols >= tree->pathnlpcols[newpathlen-1] || !tree->focuslpconstructed);
6733       assert(nrows >= tree->pathnlprows[newpathlen-1] || !tree->focuslpconstructed);
6734 
6735       while( tree->pathlen > newpathlen )
6736       {
6737          SCIP_NODE* node;
6738 
6739          node = tree->path[tree->pathlen-1];
6740 
6741          assert(SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE);
6742          assert(tree->pathlen-1 == SCIPnodeGetDepth(node));
6743          assert(tree->pathlen-1 >= SCIPnodeGetDepth(tree->probingroot));
6744 
6745          if( node->data.probingnode->nchgdobjs > 0 )
6746          {
6747             /* @todo only do this if we don't backtrack to the root node - in that case, we can just restore the unchanged
6748              *       objective values
6749              */
6750             for( i = node->data.probingnode->nchgdobjs - 1; i >= 0; --i )
6751             {
6752                assert(tree->probingobjchanged);
6753 
6754                SCIP_CALL( SCIPvarChgObj(node->data.probingnode->origobjvars[i], blkmem, set, transprob, primal, lp,
6755                      eventqueue, node->data.probingnode->origobjvals[i]) );
6756             }
6757             tree->probingsumchgdobjs -= node->data.probingnode->nchgdobjs;
6758             assert(tree->probingsumchgdobjs >= 0);
6759 
6760             /* reset probingobjchanged flag and cutoff bound */
6761             if( tree->probingsumchgdobjs == 0 )
6762             {
6763                SCIPlpUnmarkDivingObjChanged(lp);
6764                tree->probingobjchanged = FALSE;
6765 
6766                SCIP_CALL( SCIPlpSetCutoffbound(lp, set, transprob, primal->cutoffbound) );
6767             }
6768 
6769             /* recompute global and local pseudo objective values */
6770             SCIPlpRecomputeLocalAndGlobalPseudoObjval(lp, set, transprob);
6771          }
6772 
6773          /* undo bound changes by deactivating the probing node */
6774          SCIP_CALL( nodeDeactivate(node, blkmem, set, stat, tree, lp, branchcand, eventfilter, eventqueue) );
6775 
6776          /* free the probing node */
6777          SCIP_CALL( SCIPnodeFree(&tree->path[tree->pathlen-1], blkmem, set, stat, eventfilter, eventqueue, tree, lp) );
6778          tree->pathlen--;
6779       }
6780       assert(tree->pathlen == newpathlen);
6781 
6782       /* reset the path LP size to the initial size of the probing node */
6783       if( SCIPnodeGetType(tree->path[tree->pathlen-1]) == SCIP_NODETYPE_PROBINGNODE )
6784       {
6785          tree->pathnlpcols[tree->pathlen-1] = tree->path[tree->pathlen-1]->data.probingnode->ninitialcols;
6786          tree->pathnlprows[tree->pathlen-1] = tree->path[tree->pathlen-1]->data.probingnode->ninitialrows;
6787       }
6788       else
6789          assert(SCIPnodeGetType(tree->path[tree->pathlen-1]) == SCIP_NODETYPE_FOCUSNODE);
6790       treeCheckPath(tree);
6791 
6792       /* undo LP extensions */
6793       SCIP_CALL( SCIPlpShrinkCols(lp, set, ncols) );
6794       SCIP_CALL( SCIPlpShrinkRows(lp, blkmem, set, eventqueue, eventfilter, nrows) );
6795       tree->probingloadlpistate = TRUE; /* LP state must be reloaded if the next LP is solved */
6796 
6797       /* reset the LP's marked size to the initial size of the LP at the node stored in the path */
6798       assert(lp->nrows >= tree->pathnlprows[tree->pathlen-1] || !tree->focuslpconstructed);
6799       assert(lp->ncols >= tree->pathnlpcols[tree->pathlen-1] || !tree->focuslpconstructed);
6800       SCIPlpSetSizeMark(lp, tree->pathnlprows[tree->pathlen-1], tree->pathnlpcols[tree->pathlen-1]);
6801 
6802       /* if the highest cutoff or repropagation depth is inside the deleted part of the probing path,
6803        * reset them to infinity
6804        */
6805       if( tree->cutoffdepth >= tree->pathlen )
6806       {
6807          /* apply the pending bound changes */
6808          SCIP_CALL( treeApplyPendingBdchgs(tree, reopt, blkmem, set, stat, transprob, origprob, lp, branchcand, eventqueue, cliquetable) );
6809 
6810          /* applying the pending bound changes might have changed the cutoff depth; so the highest cutoff depth might
6811           * be outside of the deleted part of the probing path now
6812           */
6813          if( tree->cutoffdepth >= tree->pathlen )
6814             tree->cutoffdepth = INT_MAX;
6815       }
6816       if( tree->repropdepth >= tree->pathlen )
6817          tree->repropdepth = INT_MAX;
6818    }
6819 
6820    SCIPsetDebugMsg(set, "probing backtracked to depth %d (%d cols, %d rows)\n", tree->pathlen-1, SCIPlpGetNCols(lp), SCIPlpGetNRows(lp));
6821 
6822    return SCIP_OKAY;
6823 }
6824 
6825 /** undoes all changes to the problem applied in probing up to the given probing depth;
6826  *  the changes of the probing node of the given probing depth are the last ones that remain active;
6827  *  changes that were applied before calling SCIPtreeCreateProbingNode() cannot be undone
6828  */
SCIPtreeBacktrackProbing(SCIP_TREE * tree,SCIP_REOPT * reopt,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_LP * lp,SCIP_PRIMAL * primal,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter,SCIP_CLIQUETABLE * cliquetable,int probingdepth)6829 SCIP_RETCODE SCIPtreeBacktrackProbing(
6830    SCIP_TREE*            tree,               /**< branch and bound tree */
6831    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
6832    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
6833    SCIP_SET*             set,                /**< global SCIP settings */
6834    SCIP_STAT*            stat,               /**< problem statistics */
6835    SCIP_PROB*            transprob,          /**< transformed problem */
6836    SCIP_PROB*            origprob,           /**< original problem */
6837    SCIP_LP*              lp,                 /**< current LP data */
6838    SCIP_PRIMAL*          primal,             /**< primal data structure */
6839    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
6840    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
6841    SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
6842    SCIP_CLIQUETABLE*     cliquetable,        /**< clique table data structure */
6843    int                   probingdepth        /**< probing depth of the node in the probing path that should be reactivated */
6844    )
6845 {
6846    assert(tree != NULL);
6847    assert(SCIPtreeProbing(tree));
6848    assert(0 <= probingdepth && probingdepth <= SCIPtreeGetProbingDepth(tree));
6849 
6850    /* undo the domain and constraint set changes and free the temporary probing nodes below the given probing depth */
6851    SCIP_CALL( treeBacktrackProbing(tree, reopt, blkmem, set, stat, transprob, origprob, lp, primal, branchcand,
6852          eventqueue, eventfilter, cliquetable, probingdepth) );
6853 
6854    assert(SCIPtreeProbing(tree));
6855    assert(SCIPnodeGetType(SCIPtreeGetCurrentNode(tree)) == SCIP_NODETYPE_PROBINGNODE);
6856 
6857    return SCIP_OKAY;
6858 }
6859 
6860 /** switches back from probing to normal operation mode, frees all nodes on the probing path, restores bounds of all
6861  *  variables and restores active constraints arrays of focus node
6862  */
SCIPtreeEndProbing(SCIP_TREE * tree,SCIP_REOPT * reopt,BMS_BLKMEM * blkmem,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,SCIP_STAT * stat,SCIP_PROB * transprob,SCIP_PROB * origprob,SCIP_LP * lp,SCIP_RELAXATION * relaxation,SCIP_PRIMAL * primal,SCIP_BRANCHCAND * branchcand,SCIP_EVENTQUEUE * eventqueue,SCIP_EVENTFILTER * eventfilter,SCIP_CLIQUETABLE * cliquetable)6863 SCIP_RETCODE SCIPtreeEndProbing(
6864    SCIP_TREE*            tree,               /**< branch and bound tree */
6865    SCIP_REOPT*           reopt,              /**< reoptimization data structure */
6866    BMS_BLKMEM*           blkmem,             /**< block memory buffers */
6867    SCIP_SET*             set,                /**< global SCIP settings */
6868    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
6869    SCIP_STAT*            stat,               /**< problem statistics */
6870    SCIP_PROB*            transprob,          /**< transformed problem after presolve */
6871    SCIP_PROB*            origprob,           /**< original problem */
6872    SCIP_LP*              lp,                 /**< current LP data */
6873    SCIP_RELAXATION*      relaxation,         /**< global relaxation data */
6874    SCIP_PRIMAL*          primal,             /**< Primal LP data */
6875    SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
6876    SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
6877    SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
6878    SCIP_CLIQUETABLE*     cliquetable         /**< clique table data structure */
6879    )
6880 {
6881    assert(tree != NULL);
6882    assert(SCIPtreeProbing(tree));
6883    assert(tree->probingroot != NULL);
6884    assert(tree->focusnode != NULL);
6885    assert(SCIPnodeGetType(tree->probingroot) == SCIP_NODETYPE_PROBINGNODE);
6886    assert(SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_FOCUSNODE
6887       || SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_REFOCUSNODE);
6888    assert(tree->probingroot->parent == tree->focusnode);
6889    assert(SCIPnodeGetDepth(tree->probingroot) == SCIPnodeGetDepth(tree->focusnode)+1);
6890    assert(tree->pathlen >= 2);
6891    assert(SCIPnodeGetType(tree->path[tree->pathlen-1]) == SCIP_NODETYPE_PROBINGNODE);
6892    assert(set != NULL);
6893 
6894    /* undo the domain and constraint set changes of the temporary probing nodes and free the probing nodes */
6895    SCIP_CALL( treeBacktrackProbing(tree, reopt, blkmem, set, stat, transprob, origprob, lp, primal, branchcand,
6896          eventqueue, eventfilter, cliquetable, -1) );
6897    assert(tree->probingsumchgdobjs == 0);
6898    assert(!tree->probingobjchanged);
6899    assert(!lp->divingobjchg);
6900    assert(lp->cutoffbound == primal->cutoffbound); /*lint !e777*/
6901    assert(SCIPtreeGetCurrentNode(tree) == tree->focusnode);
6902    assert(!SCIPtreeProbing(tree));
6903 
6904    /* if the LP was flushed before probing starts, flush it again */
6905    if( tree->probinglpwasflushed )
6906    {
6907       SCIP_CALL( SCIPlpFlush(lp, blkmem, set, eventqueue) );
6908 
6909       /* if the LP was solved before probing starts, solve it again to restore the LP solution */
6910       if( tree->probinglpwassolved )
6911       {
6912          SCIP_Bool lperror;
6913 
6914          /* reset the LP state before probing started */
6915          if( tree->probinglpistate == NULL )
6916          {
6917             assert(tree->probinglpinorms == NULL);
6918             SCIP_CALL( SCIPlpiClearState(lp->lpi) );
6919             lp->primalfeasible = (lp->nlpicols == 0 && lp->nlpirows == 0);
6920             lp->primalchecked = (lp->nlpicols == 0 && lp->nlpirows == 0);
6921             lp->dualfeasible = (lp->nlpicols == 0 && lp->nlpirows == 0);
6922             lp->dualchecked = (lp->nlpicols == 0 && lp->nlpirows == 0);
6923             lp->solisbasic = FALSE;
6924          }
6925          else
6926          {
6927             SCIP_CALL( SCIPlpSetState(lp, blkmem, set, eventqueue, tree->probinglpistate,
6928                   tree->probinglpwasprimfeas, tree->probinglpwasprimchecked, tree->probinglpwasdualfeas,
6929                   tree->probinglpwasdualchecked) );
6930             SCIP_CALL( SCIPlpFreeState(lp, blkmem, &tree->probinglpistate) );
6931 
6932             if( tree->probinglpinorms != NULL )
6933             {
6934                SCIP_CALL( SCIPlpSetNorms(lp, blkmem, tree->probinglpinorms) );
6935                SCIP_CALL( SCIPlpFreeNorms(lp, blkmem, &tree->probinglpinorms) );
6936                tree->probinglpinorms = NULL;
6937             }
6938          }
6939          SCIPlpSetIsRelax(lp, tree->probinglpwasrelax);
6940 
6941          /* resolve LP to reset solution */
6942          SCIP_CALL( SCIPlpSolveAndEval(lp, set, messagehdlr, blkmem, stat, eventqueue, eventfilter, transprob, -1LL, FALSE, FALSE, FALSE, &lperror) );
6943          if( lperror )
6944          {
6945             SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
6946                "(node %" SCIP_LONGINT_FORMAT ") unresolved numerical troubles while resolving LP %" SCIP_LONGINT_FORMAT " after probing\n",
6947                stat->nnodes, stat->nlps);
6948             lp->resolvelperror = TRUE;
6949             tree->focusnodehaslp = FALSE;
6950          }
6951          else if( SCIPlpGetSolstat(lp) != SCIP_LPSOLSTAT_OPTIMAL
6952             && SCIPlpGetSolstat(lp) != SCIP_LPSOLSTAT_INFEASIBLE
6953             && SCIPlpGetSolstat(lp) != SCIP_LPSOLSTAT_UNBOUNDEDRAY
6954             && SCIPlpGetSolstat(lp) != SCIP_LPSOLSTAT_OBJLIMIT )
6955          {
6956             SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
6957                "LP was not resolved to a sufficient status after probing\n");
6958             lp->resolvelperror = TRUE;
6959             tree->focusnodehaslp = FALSE;
6960          }
6961          else if( tree->focuslpconstructed && SCIPlpIsRelax(lp) && SCIPprobAllColsInLP(transprob, set, lp))
6962          {
6963             SCIP_CALL( SCIPnodeUpdateLowerboundLP(tree->focusnode, set, stat, tree, transprob, origprob, lp) );
6964          }
6965       }
6966    }
6967    else
6968       lp->flushed = FALSE;
6969 
6970    assert(tree->probinglpistate == NULL);
6971 
6972    /* if no LP was solved during probing and the LP before probing was not solved, then it should not be solved now */
6973    assert(tree->probingsolvedlp || tree->probinglpwassolved || !lp->solved);
6974 
6975    /* if the LP was solved (and hence flushed) before probing, then lp->solved should be TRUE unless we occured an error
6976     * during resolving right above
6977     */
6978    assert(!tree->probinglpwassolved || !tree->probinglpwasflushed || lp->solved || lp->resolvelperror);
6979 
6980    /* if the LP was not solved before probing it should be marked unsolved now; this can occur if a probing LP was
6981     * solved in between
6982     */
6983    if( !tree->probinglpwassolved )
6984    {
6985       lp->solved = FALSE;
6986       lp->lpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
6987    }
6988 
6989    /* if the LP was solved during probing, but had been unsolved before probing started, we discard the LP state */
6990    if( set->lp_clearinitialprobinglp && tree->probingsolvedlp && !tree->probinglpwassolved )
6991    {
6992       SCIPsetDebugMsg(set, "clearing lp state at end of probing mode because LP was initially unsolved\n");
6993       SCIP_CALL( SCIPlpiClearState(lp->lpi) );
6994    }
6995 
6996    /* if a relaxation was stored before probing, restore it now */
6997    if( tree->probdiverelaxstored )
6998    {
6999       SCIP_CALL( SCIPtreeRestoreRelaxSol(tree, set, relaxation, transprob) );
7000    }
7001 
7002    assert(tree->probingobjchanged == SCIPlpDivingObjChanged(lp));
7003 
7004    /* reset flags */
7005    tree->probinglpwasflushed = FALSE;
7006    tree->probinglpwassolved = FALSE;
7007    tree->probingloadlpistate = FALSE;
7008    tree->probinglpwasrelax = FALSE;
7009    tree->probingsolvedlp = FALSE;
7010    tree->sbprobing = FALSE;
7011 
7012    /* inform LP about end of probing mode */
7013    SCIP_CALL( SCIPlpEndProbing(lp) );
7014 
7015    /* reset all marked constraints for propagation */
7016    SCIP_CALL( SCIPconshdlrsResetPropagationStatus(set, blkmem, set->conshdlrs, set->nconshdlrs) );
7017 
7018    SCIPsetDebugMsg(set, "probing ended in depth %d (LP flushed: %u, solstat: %d)\n", tree->pathlen-1, lp->flushed, SCIPlpGetSolstat(lp));
7019 
7020    return SCIP_OKAY;
7021 }
7022 
7023 /** stores relaxation solution before diving or probing */
SCIPtreeStoreRelaxSol(SCIP_TREE * tree,SCIP_SET * set,SCIP_RELAXATION * relaxation,SCIP_PROB * transprob)7024 SCIP_RETCODE SCIPtreeStoreRelaxSol(
7025    SCIP_TREE*            tree,               /**< branch and bound tree */
7026    SCIP_SET*             set,                /**< global SCIP settings */
7027    SCIP_RELAXATION*      relaxation,         /**< global relaxation data */
7028    SCIP_PROB*            transprob           /**< transformed problem after presolve */
7029    )
7030 {
7031    SCIP_VAR** vars;
7032    int nvars;
7033    int v;
7034 
7035    assert(tree != NULL);
7036    assert(set != NULL);
7037    assert(relaxation != NULL);
7038    assert(transprob != NULL);
7039    assert(SCIPrelaxationIsSolValid(relaxation));
7040 
7041    nvars = transprob->nvars;
7042    vars = transprob->vars;
7043 
7044    /* check if memory still needs to be allocated or resized */
7045    if( tree->probdiverelaxsol == NULL )
7046    {
7047       SCIP_ALLOC( BMSallocMemoryArray(&(tree->probdiverelaxsol), nvars) );
7048       tree->nprobdiverelaxsol = nvars;
7049    }
7050    else if( nvars > tree->nprobdiverelaxsol )
7051    {
7052       SCIP_ALLOC( BMSreallocMemoryArray(&tree->probdiverelaxsol, nvars) );
7053       tree->nprobdiverelaxsol = nvars;
7054    }
7055    assert(tree->nprobdiverelaxsol >= nvars);
7056 
7057    /* iterate over all variables to save the relaxation solution */
7058    for( v = 0; v < nvars; ++v )
7059       tree->probdiverelaxsol[v] = SCIPvarGetRelaxSol(vars[v], set);
7060 
7061    tree->probdiverelaxstored = TRUE;
7062    tree->probdiverelaxincludeslp = SCIPrelaxationIsLpIncludedForSol(relaxation);
7063 
7064    return SCIP_OKAY;
7065 }
7066 
7067 /** restores relaxation solution after diving or probing */
SCIPtreeRestoreRelaxSol(SCIP_TREE * tree,SCIP_SET * set,SCIP_RELAXATION * relaxation,SCIP_PROB * transprob)7068 SCIP_RETCODE SCIPtreeRestoreRelaxSol(
7069    SCIP_TREE*            tree,               /**< branch and bound tree */
7070    SCIP_SET*             set,                /**< global SCIP settings */
7071    SCIP_RELAXATION*      relaxation,         /**< global relaxation data */
7072    SCIP_PROB*            transprob           /**< transformed problem after presolve */
7073    )
7074 {
7075    SCIP_VAR** vars;
7076    int nvars;
7077    int v;
7078 
7079    assert(tree != NULL);
7080    assert(set != NULL);
7081    assert(tree->probdiverelaxstored);
7082    assert(tree->probdiverelaxsol != NULL);
7083 
7084    nvars = transprob->nvars;
7085    vars = transprob->vars;
7086    assert( nvars <= tree->nprobdiverelaxsol );
7087 
7088    /* iterate over all variables to restore the relaxation solution */
7089    for( v = 0; v < nvars; ++v )
7090    {
7091       SCIP_CALL( SCIPvarSetRelaxSol(vars[v], set, relaxation, tree->probdiverelaxsol[v], TRUE) );
7092    }
7093 
7094    tree->probdiverelaxstored = FALSE;
7095    SCIPrelaxationSetSolValid(relaxation, TRUE, tree->probdiverelaxincludeslp);
7096 
7097    return SCIP_OKAY;
7098 }
7099 
7100 /** gets the best child of the focus node w.r.t. the node selection priority assigned by the branching rule */
SCIPtreeGetPrioChild(SCIP_TREE * tree)7101 SCIP_NODE* SCIPtreeGetPrioChild(
7102    SCIP_TREE*            tree                /**< branch and bound tree */
7103    )
7104 {
7105    SCIP_NODE* bestnode;
7106    SCIP_Real bestprio;
7107    int i;
7108 
7109    assert(tree != NULL);
7110 
7111    bestnode = NULL;
7112    bestprio = SCIP_REAL_MIN;
7113    for( i = 0; i < tree->nchildren; ++i )
7114    {
7115       if( tree->childrenprio[i] > bestprio )
7116       {
7117          bestnode = tree->children[i];
7118          bestprio = tree->childrenprio[i];
7119       }
7120    }
7121    assert((tree->nchildren == 0) == (bestnode == NULL));
7122 
7123    return bestnode;
7124 }
7125 
7126 /** gets the best sibling of the focus node w.r.t. the node selection priority assigned by the branching rule */
SCIPtreeGetPrioSibling(SCIP_TREE * tree)7127 SCIP_NODE* SCIPtreeGetPrioSibling(
7128    SCIP_TREE*            tree                /**< branch and bound tree */
7129    )
7130 {
7131    SCIP_NODE* bestnode;
7132    SCIP_Real bestprio;
7133    int i;
7134 
7135    assert(tree != NULL);
7136 
7137    bestnode = NULL;
7138    bestprio = SCIP_REAL_MIN;
7139    for( i = 0; i < tree->nsiblings; ++i )
7140    {
7141       if( tree->siblingsprio[i] > bestprio )
7142       {
7143          bestnode = tree->siblings[i];
7144          bestprio = tree->siblingsprio[i];
7145       }
7146    }
7147    assert((tree->nsiblings == 0) == (bestnode == NULL));
7148 
7149    return bestnode;
7150 }
7151 
7152 /** gets the best child of the focus node w.r.t. the node selection strategy */
SCIPtreeGetBestChild(SCIP_TREE * tree,SCIP_SET * set)7153 SCIP_NODE* SCIPtreeGetBestChild(
7154    SCIP_TREE*            tree,               /**< branch and bound tree */
7155    SCIP_SET*             set                 /**< global SCIP settings */
7156    )
7157 {
7158    SCIP_NODESEL* nodesel;
7159    SCIP_NODE* bestnode;
7160    int i;
7161 
7162    assert(tree != NULL);
7163 
7164    nodesel = SCIPnodepqGetNodesel(tree->leaves);
7165    assert(nodesel != NULL);
7166 
7167    bestnode = NULL;
7168    for( i = 0; i < tree->nchildren; ++i )
7169    {
7170       if( bestnode == NULL || SCIPnodeselCompare(nodesel, set, tree->children[i], bestnode) < 0 )
7171       {
7172          bestnode = tree->children[i];
7173       }
7174    }
7175 
7176    return bestnode;
7177 }
7178 
7179 /** gets the best sibling of the focus node w.r.t. the node selection strategy */
SCIPtreeGetBestSibling(SCIP_TREE * tree,SCIP_SET * set)7180 SCIP_NODE* SCIPtreeGetBestSibling(
7181    SCIP_TREE*            tree,               /**< branch and bound tree */
7182    SCIP_SET*             set                 /**< global SCIP settings */
7183    )
7184 {
7185    SCIP_NODESEL* nodesel;
7186    SCIP_NODE* bestnode;
7187    int i;
7188 
7189    assert(tree != NULL);
7190 
7191    nodesel = SCIPnodepqGetNodesel(tree->leaves);
7192    assert(nodesel != NULL);
7193 
7194    bestnode = NULL;
7195    for( i = 0; i < tree->nsiblings; ++i )
7196    {
7197       if( bestnode == NULL || SCIPnodeselCompare(nodesel, set, tree->siblings[i], bestnode) < 0 )
7198       {
7199          bestnode = tree->siblings[i];
7200       }
7201    }
7202 
7203    return bestnode;
7204 }
7205 
7206 /** gets the best leaf from the node queue w.r.t. the node selection strategy */
SCIPtreeGetBestLeaf(SCIP_TREE * tree)7207 SCIP_NODE* SCIPtreeGetBestLeaf(
7208    SCIP_TREE*            tree                /**< branch and bound tree */
7209    )
7210 {
7211    assert(tree != NULL);
7212 
7213    return SCIPnodepqFirst(tree->leaves);
7214 }
7215 
7216 /** gets the best node from the tree (child, sibling, or leaf) w.r.t. the node selection strategy */
SCIPtreeGetBestNode(SCIP_TREE * tree,SCIP_SET * set)7217 SCIP_NODE* SCIPtreeGetBestNode(
7218    SCIP_TREE*            tree,               /**< branch and bound tree */
7219    SCIP_SET*             set                 /**< global SCIP settings */
7220    )
7221 {
7222    SCIP_NODESEL* nodesel;
7223    SCIP_NODE* bestchild;
7224    SCIP_NODE* bestsibling;
7225    SCIP_NODE* bestleaf;
7226    SCIP_NODE* bestnode;
7227 
7228    assert(tree != NULL);
7229 
7230    nodesel = SCIPnodepqGetNodesel(tree->leaves);
7231    assert(nodesel != NULL);
7232 
7233    /* get the best child, sibling, and leaf */
7234    bestchild = SCIPtreeGetBestChild(tree, set);
7235    bestsibling = SCIPtreeGetBestSibling(tree, set);
7236    bestleaf = SCIPtreeGetBestLeaf(tree);
7237 
7238    /* return the best of the three */
7239    bestnode = bestchild;
7240    if( bestsibling != NULL && (bestnode == NULL || SCIPnodeselCompare(nodesel, set, bestsibling, bestnode) < 0) )
7241       bestnode = bestsibling;
7242    if( bestleaf != NULL && (bestnode == NULL || SCIPnodeselCompare(nodesel, set, bestleaf, bestnode) < 0) )
7243       bestnode = bestleaf;
7244 
7245    assert(SCIPtreeGetNLeaves(tree) == 0 || bestnode != NULL);
7246 
7247    return bestnode;
7248 }
7249 
7250 /** gets the minimal lower bound of all nodes in the tree */
SCIPtreeGetLowerbound(SCIP_TREE * tree,SCIP_SET * set)7251 SCIP_Real SCIPtreeGetLowerbound(
7252    SCIP_TREE*            tree,               /**< branch and bound tree */
7253    SCIP_SET*             set                 /**< global SCIP settings */
7254    )
7255 {
7256    SCIP_Real lowerbound;
7257    int i;
7258 
7259    assert(tree != NULL);
7260    assert(set != NULL);
7261 
7262    /* get the lower bound from the queue */
7263    lowerbound = SCIPnodepqGetLowerbound(tree->leaves, set);
7264 
7265    /* compare lower bound with children */
7266    for( i = 0; i < tree->nchildren; ++i )
7267    {
7268       assert(tree->children[i] != NULL);
7269       lowerbound = MIN(lowerbound, tree->children[i]->lowerbound);
7270    }
7271 
7272    /* compare lower bound with siblings */
7273    for( i = 0; i < tree->nsiblings; ++i )
7274    {
7275       assert(tree->siblings[i] != NULL);
7276       lowerbound = MIN(lowerbound, tree->siblings[i]->lowerbound);
7277    }
7278 
7279    /* compare lower bound with focus node */
7280    if( tree->focusnode != NULL )
7281    {
7282       lowerbound = MIN(lowerbound, tree->focusnode->lowerbound);
7283    }
7284 
7285    return lowerbound;
7286 }
7287 
7288 /** gets the node with minimal lower bound of all nodes in the tree (child, sibling, or leaf) */
SCIPtreeGetLowerboundNode(SCIP_TREE * tree,SCIP_SET * set)7289 SCIP_NODE* SCIPtreeGetLowerboundNode(
7290    SCIP_TREE*            tree,               /**< branch and bound tree */
7291    SCIP_SET*             set                 /**< global SCIP settings */
7292    )
7293 {
7294    SCIP_NODE* lowerboundnode;
7295    SCIP_Real lowerbound;
7296    SCIP_Real bestprio;
7297    int i;
7298 
7299    assert(tree != NULL);
7300    assert(set != NULL);
7301 
7302    /* get the lower bound from the queue */
7303    lowerboundnode = SCIPnodepqGetLowerboundNode(tree->leaves, set);
7304    lowerbound = lowerboundnode != NULL ? lowerboundnode->lowerbound : SCIPsetInfinity(set);
7305    bestprio = -SCIPsetInfinity(set);
7306 
7307    /* compare lower bound with children */
7308    for( i = 0; i < tree->nchildren; ++i )
7309    {
7310       assert(tree->children[i] != NULL);
7311       if( SCIPsetIsLE(set, tree->children[i]->lowerbound, lowerbound) )
7312       {
7313          if( SCIPsetIsLT(set, tree->children[i]->lowerbound, lowerbound) || tree->childrenprio[i] > bestprio )
7314          {
7315             lowerboundnode = tree->children[i];
7316             lowerbound = lowerboundnode->lowerbound;
7317             bestprio = tree->childrenprio[i];
7318          }
7319       }
7320    }
7321 
7322    /* compare lower bound with siblings */
7323    for( i = 0; i < tree->nsiblings; ++i )
7324    {
7325       assert(tree->siblings[i] != NULL);
7326       if( SCIPsetIsLE(set, tree->siblings[i]->lowerbound, lowerbound) )
7327       {
7328          if( SCIPsetIsLT(set, tree->siblings[i]->lowerbound, lowerbound) || tree->siblingsprio[i] > bestprio )
7329          {
7330             lowerboundnode = tree->siblings[i];
7331             lowerbound = lowerboundnode->lowerbound;
7332             bestprio = tree->siblingsprio[i];
7333          }
7334       }
7335    }
7336 
7337    return lowerboundnode;
7338 }
7339 
7340 /** gets the average lower bound of all nodes in the tree */
SCIPtreeGetAvgLowerbound(SCIP_TREE * tree,SCIP_Real cutoffbound)7341 SCIP_Real SCIPtreeGetAvgLowerbound(
7342    SCIP_TREE*            tree,               /**< branch and bound tree */
7343    SCIP_Real             cutoffbound         /**< global cutoff bound */
7344    )
7345 {
7346    SCIP_Real lowerboundsum;
7347    int nnodes;
7348    int i;
7349 
7350    assert(tree != NULL);
7351 
7352    /* get sum of lower bounds from nodes in the queue */
7353    lowerboundsum = SCIPnodepqGetLowerboundSum(tree->leaves);
7354    nnodes = SCIPtreeGetNLeaves(tree);
7355 
7356    /* add lower bound of focus node */
7357    if( tree->focusnode != NULL && tree->focusnode->lowerbound < cutoffbound )
7358    {
7359       lowerboundsum += tree->focusnode->lowerbound;
7360       nnodes++;
7361    }
7362 
7363    /* add lower bounds of siblings */
7364    for( i = 0; i < tree->nsiblings; ++i )
7365    {
7366       assert(tree->siblings[i] != NULL);
7367       lowerboundsum += tree->siblings[i]->lowerbound;
7368    }
7369    nnodes += tree->nsiblings;
7370 
7371    /* add lower bounds of children */
7372    for( i = 0; i < tree->nchildren; ++i )
7373    {
7374       assert(tree->children[i] != NULL);
7375       lowerboundsum += tree->children[i]->lowerbound;
7376    }
7377    nnodes += tree->nchildren;
7378 
7379    return nnodes == 0 ? 0.0 : lowerboundsum/nnodes;
7380 }
7381 
7382 
7383 
7384 
7385 /*
7386  * simple functions implemented as defines
7387  */
7388 
7389 /* In debug mode, the following methods are implemented as function calls to ensure
7390  * type validity.
7391  * In optimized mode, the methods are implemented as defines to improve performance.
7392  * However, we want to have them in the library anyways, so we have to undef the defines.
7393  */
7394 
7395 #undef SCIPnodeGetType
7396 #undef SCIPnodeGetNumber
7397 #undef SCIPnodeGetDepth
7398 #undef SCIPnodeGetLowerbound
7399 #undef SCIPnodeGetEstimate
7400 #undef SCIPnodeGetDomchg
7401 #undef SCIPnodeGetParent
7402 #undef SCIPnodeGetConssetchg
7403 #undef SCIPnodeIsActive
7404 #undef SCIPnodeIsPropagatedAgain
7405 #undef SCIPtreeGetNLeaves
7406 #undef SCIPtreeGetNChildren
7407 #undef SCIPtreeGetNSiblings
7408 #undef SCIPtreeGetNNodes
7409 #undef SCIPtreeIsPathComplete
7410 #undef SCIPtreeProbing
7411 #undef SCIPtreeGetProbingRoot
7412 #undef SCIPtreeGetProbingDepth
7413 #undef SCIPtreeGetFocusNode
7414 #undef SCIPtreeGetFocusDepth
7415 #undef SCIPtreeHasFocusNodeLP
7416 #undef SCIPtreeSetFocusNodeLP
7417 #undef SCIPtreeIsFocusNodeLPConstructed
7418 #undef SCIPtreeInRepropagation
7419 #undef SCIPtreeGetCurrentNode
7420 #undef SCIPtreeGetCurrentDepth
7421 #undef SCIPtreeHasCurrentNodeLP
7422 #undef SCIPtreeGetEffectiveRootDepth
7423 #undef SCIPtreeGetRootNode
7424 #undef SCIPtreeProbingObjChanged
7425 #undef SCIPtreeMarkProbingObjChanged
7426 
7427 /** gets the type of the node */
SCIPnodeGetType(SCIP_NODE * node)7428 SCIP_NODETYPE SCIPnodeGetType(
7429    SCIP_NODE*            node                /**< node */
7430    )
7431 {
7432    assert(node != NULL);
7433 
7434    return (SCIP_NODETYPE)(node->nodetype);
7435 }
7436 
7437 /** gets successively assigned number of the node */
SCIPnodeGetNumber(SCIP_NODE * node)7438 SCIP_Longint SCIPnodeGetNumber(
7439    SCIP_NODE*            node                /**< node */
7440    )
7441 {
7442    assert(node != NULL);
7443 
7444    return node->number;
7445 }
7446 
7447 /** gets the depth of the node */
SCIPnodeGetDepth(SCIP_NODE * node)7448 int SCIPnodeGetDepth(
7449    SCIP_NODE*            node                /**< node */
7450    )
7451 {
7452    assert(node != NULL);
7453 
7454    return (int) node->depth;
7455 }
7456 
7457 /** gets the lower bound of the node */
SCIPnodeGetLowerbound(SCIP_NODE * node)7458 SCIP_Real SCIPnodeGetLowerbound(
7459    SCIP_NODE*            node                /**< node */
7460    )
7461 {
7462    assert(node != NULL);
7463 
7464    return node->lowerbound;
7465 }
7466 
7467 /** gets the estimated value of the best feasible solution in subtree of the node */
SCIPnodeGetEstimate(SCIP_NODE * node)7468 SCIP_Real SCIPnodeGetEstimate(
7469    SCIP_NODE*            node                /**< node */
7470    )
7471 {
7472    assert(node != NULL);
7473 
7474    return node->estimate;
7475 }
7476 
7477 /** gets the reoptimization type of this node */
SCIPnodeGetReopttype(SCIP_NODE * node)7478 SCIP_REOPTTYPE SCIPnodeGetReopttype(
7479    SCIP_NODE*            node                /**< node */
7480    )
7481 {
7482    assert(node != NULL);
7483 
7484    return (SCIP_REOPTTYPE)node->reopttype;
7485 }
7486 
7487 /** sets the reoptimization type of this node */
SCIPnodeSetReopttype(SCIP_NODE * node,SCIP_REOPTTYPE reopttype)7488 void SCIPnodeSetReopttype(
7489    SCIP_NODE*            node,               /**< node */
7490    SCIP_REOPTTYPE        reopttype           /**< reoptimization type */
7491    )
7492 {
7493    assert(node != NULL);
7494    assert(reopttype == SCIP_REOPTTYPE_NONE
7495        || reopttype == SCIP_REOPTTYPE_TRANSIT
7496        || reopttype == SCIP_REOPTTYPE_INFSUBTREE
7497        || reopttype == SCIP_REOPTTYPE_STRBRANCHED
7498        || reopttype == SCIP_REOPTTYPE_LOGICORNODE
7499        || reopttype == SCIP_REOPTTYPE_LEAF
7500        || reopttype == SCIP_REOPTTYPE_PRUNED
7501        || reopttype == SCIP_REOPTTYPE_FEASIBLE);
7502 
7503    node->reopttype = (unsigned int) reopttype;
7504 }
7505 
7506 /** gets the unique id to identify the node during reoptimization; the id is 0 if the node is the root or not part of
7507  * the reoptimization tree
7508  */
SCIPnodeGetReoptID(SCIP_NODE * node)7509 unsigned int SCIPnodeGetReoptID(
7510    SCIP_NODE*            node                /**< node */
7511    )
7512 {
7513    assert(node != NULL);
7514 
7515    return node->reoptid; /*lint !e732*/
7516 }
7517 
7518 /** set a unique id to identify the node during reoptimization */
SCIPnodeSetReoptID(SCIP_NODE * node,unsigned int id)7519 void SCIPnodeSetReoptID(
7520    SCIP_NODE*            node,               /**< node */
7521    unsigned int          id                  /**< unique id */
7522    )
7523 {
7524    assert(node != NULL);
7525    assert(id <= 536870911); /* id has only 29 bits and needs to be smaller than 2^29 */
7526 
7527    node->reoptid = id;
7528 }
7529 
7530 /** gets the domain change information of the node, i.e., the information about the differences in the
7531  *  variables domains to the parent node
7532  */
SCIPnodeGetDomchg(SCIP_NODE * node)7533 SCIP_DOMCHG* SCIPnodeGetDomchg(
7534    SCIP_NODE*            node                /**< node */
7535    )
7536 {
7537    assert(node != NULL);
7538 
7539    return node->domchg;
7540 }
7541 
7542 /** counts the number of bound changes due to branching, constraint propagation, and propagation */
SCIPnodeGetNDomchg(SCIP_NODE * node,int * nbranchings,int * nconsprop,int * nprop)7543 void SCIPnodeGetNDomchg(
7544    SCIP_NODE*            node,               /**< node */
7545    int*                  nbranchings,        /**< pointer to store number of branchings (or NULL if not needed) */
7546    int*                  nconsprop,          /**< pointer to store number of constraint propagations (or NULL if not needed) */
7547    int*                  nprop               /**< pointer to store number of propagations (or NULL if not needed) */
7548    )
7549 {  /*lint --e{641}*/
7550    SCIP_Bool count_branchings;
7551    SCIP_Bool count_consprop;
7552    SCIP_Bool count_prop;
7553    int i;
7554 
7555    assert(node != NULL);
7556 
7557    count_branchings = (nbranchings != NULL);
7558    count_consprop = (nconsprop != NULL);
7559    count_prop = (nprop != NULL);
7560 
7561    /* set counter to zero */
7562    if( count_branchings )
7563       *nbranchings = 0;
7564    if( count_consprop )
7565       *nconsprop = 0;
7566    if( count_prop )
7567       *nprop = 0;
7568 
7569    if( node->domchg != NULL )
7570    {
7571       for( i = 0; i < (int) node->domchg->domchgbound.nboundchgs; i++ )
7572       {
7573          if( count_branchings && node->domchg->domchgbound.boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING )
7574             (*nbranchings)++; /*lint !e413*/
7575          else if( count_consprop && node->domchg->domchgbound.boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER )
7576             (*nconsprop)++; /*lint !e413*/
7577          else if( count_prop && node->domchg->domchgbound.boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER )
7578             (*nprop)++; /*lint !e413*/
7579       }
7580    }
7581 }
7582 
7583 /* return the number of bound changes based on dual information.
7584  *
7585  * currently, this methods works only for bound changes made by strong branching on binary variables. we need this
7586  * method to ensure optimality within reoptimization.
7587  *
7588  * since the bound changes made by strong branching are stored as SCIP_BOUNDCHGTYPE_CONSINFER or SCIP_BOUNDCHGTYPE_PROPINFER
7589  * with no constraint or propagator, resp., we are are interested in bound changes with these attributes.
7590  *
7591  * all bound changes of type SCIP_BOUNDCHGTYPE_BRANCHING are stored in the beginning of the bound change array, afterwards,
7592  * we can find the other two types. thus, we start the search at the end of the list and stop when reaching the first
7593  * bound change of type SCIP_BOUNDCHGTYPE_BRANCHING.
7594  */
SCIPnodeGetNDualBndchgs(SCIP_NODE * node)7595 int SCIPnodeGetNDualBndchgs(
7596    SCIP_NODE*            node                /**< node */
7597    )
7598 {  /*lint --e{641}*/
7599    SCIP_BOUNDCHG* boundchgs;
7600    int i;
7601    int nboundchgs;
7602    int npseudobranchvars;
7603 
7604    assert(node != NULL);
7605 
7606    if( node->domchg == NULL )
7607       return 0;
7608 
7609    nboundchgs = (int)node->domchg->domchgbound.nboundchgs;
7610    boundchgs = node->domchg->domchgbound.boundchgs;
7611 
7612    npseudobranchvars = 0;
7613 
7614    assert(boundchgs != NULL);
7615    assert(nboundchgs >= 0);
7616 
7617    /* count the number of pseudo-branching decisions; pseudo-branching decisions have to be in the ending of the bound change
7618     * array
7619     */
7620    for( i = nboundchgs-1; i >= 0; i--)
7621    {
7622       SCIP_Bool isint;
7623 
7624       isint = boundchgs[i].var->vartype == SCIP_VARTYPE_BINARY || boundchgs[i].var->vartype == SCIP_VARTYPE_INTEGER
7625            || boundchgs[i].var->vartype == SCIP_VARTYPE_IMPLINT;
7626 
7627       if( isint && ((boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER
7628             && boundchgs[i].data.inferencedata.reason.cons == NULL)
7629         || (boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER
7630             && boundchgs[i].data.inferencedata.reason.prop == NULL)) )
7631          npseudobranchvars++;
7632       else if( boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING )
7633          break;
7634    }
7635 
7636    return npseudobranchvars;
7637 }
7638 
7639 /** returns the set of variable branchings that were performed in the parent node to create this node */
SCIPnodeGetDualBoundchgs(SCIP_NODE * node,SCIP_VAR ** vars,SCIP_Real * bounds,SCIP_BOUNDTYPE * boundtypes,int * nvars,int varssize)7640 void SCIPnodeGetDualBoundchgs(
7641    SCIP_NODE*            node,               /**< node data */
7642    SCIP_VAR**            vars,               /**< array of variables on which the bound change is based on dual information */
7643    SCIP_Real*            bounds,             /**< array of bounds which are based on dual information */
7644    SCIP_BOUNDTYPE*       boundtypes,         /**< array of boundtypes which are based on dual information */
7645    int*                  nvars,              /**< number of variables on which the bound change is based on dual information
7646                                               *   if this is larger than the array size, arrays should be reallocated and method
7647                                               *   should be called again */
7648    int                   varssize            /**< available slots in arrays */
7649    )
7650 {  /*lint --e{641}*/
7651    SCIP_BOUNDCHG* boundchgs;
7652    int nboundchgs;
7653    int i;
7654 
7655    assert(node != NULL);
7656    assert(vars != NULL);
7657    assert(bounds != NULL);
7658    assert(boundtypes != NULL);
7659    assert(nvars != NULL);
7660    assert(varssize >= 0);
7661 
7662    (*nvars) = 0;
7663 
7664    if( SCIPnodeGetDepth(node) == 0 || node->domchg == NULL )
7665       return;
7666 
7667    nboundchgs = (int)node->domchg->domchgbound.nboundchgs;
7668    boundchgs = node->domchg->domchgbound.boundchgs;
7669 
7670    assert(boundchgs != NULL);
7671    assert(nboundchgs >= 0);
7672 
7673    /* count the number of pseudo-branching decisions; pseudo-branching decisions have to be in the ending of the bound change
7674     * array
7675     */
7676    for( i = nboundchgs-1; i >= 0; i--)
7677    {
7678       if( boundchgs[i].var->vartype == SCIP_VARTYPE_BINARY || boundchgs[i].var->vartype == SCIP_VARTYPE_INTEGER
7679        || boundchgs[i].var->vartype == SCIP_VARTYPE_IMPLINT )
7680       {
7681          if( (boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER
7682                && boundchgs[i].data.inferencedata.reason.cons == NULL)
7683           || (boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER
7684                 && boundchgs[i].data.inferencedata.reason.prop == NULL) )
7685             (*nvars)++;
7686          else if( boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING )
7687             break;
7688       }
7689    }
7690 
7691    /* if the arrays have enough space store the branching decisions */
7692    if( varssize >= *nvars )
7693    {
7694       int j;
7695       j = 0;
7696       for( i = i+1; i < nboundchgs; i++)
7697       {
7698          if( boundchgs[i].var->vartype == SCIP_VARTYPE_BINARY || boundchgs[i].var->vartype == SCIP_VARTYPE_INTEGER
7699           || boundchgs[i].var->vartype == SCIP_VARTYPE_IMPLINT )
7700          {
7701             assert( boundchgs[i].boundchgtype != SCIP_BOUNDCHGTYPE_BRANCHING );
7702             if( (boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER
7703                   && boundchgs[i].data.inferencedata.reason.cons == NULL)
7704              || (boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER
7705                   && boundchgs[i].data.inferencedata.reason.prop == NULL) )
7706             {
7707                vars[j] = boundchgs[i].var;
7708                bounds[j] = boundchgs[i].newbound;
7709                boundtypes[j] = (SCIP_BOUNDTYPE) boundchgs[i].boundtype;
7710                j++;
7711             }
7712          }
7713       }
7714    }
7715 }
7716 
7717 /** gets the parent node of a node in the branch-and-bound tree, if any */
SCIPnodeGetParent(SCIP_NODE * node)7718 SCIP_NODE* SCIPnodeGetParent(
7719    SCIP_NODE*            node                /**< node */
7720    )
7721 {
7722    assert(node != NULL);
7723 
7724    return node->parent;
7725 }
7726 
7727 /** returns the set of variable branchings that were performed in the parent node to create this node */
SCIPnodeGetParentBranchings(SCIP_NODE * node,SCIP_VAR ** branchvars,SCIP_Real * branchbounds,SCIP_BOUNDTYPE * boundtypes,int * nbranchvars,int branchvarssize)7728 void SCIPnodeGetParentBranchings(
7729    SCIP_NODE*            node,               /**< node data */
7730    SCIP_VAR**            branchvars,         /**< array of variables on which the branching has been performed in the parent node */
7731    SCIP_Real*            branchbounds,       /**< array of bounds which the branching in the parent node set */
7732    SCIP_BOUNDTYPE*       boundtypes,         /**< array of boundtypes which the branching in the parent node set */
7733    int*                  nbranchvars,        /**< number of variables on which branching has been performed in the parent node
7734                                               *   if this is larger than the array size, arrays should be reallocated and method
7735                                               *   should be called again */
7736    int                   branchvarssize      /**< available slots in arrays */
7737    )
7738 {
7739    SCIP_BOUNDCHG* boundchgs;
7740    int nboundchgs;
7741    int i;
7742 
7743    assert(node != NULL);
7744    assert(branchvars != NULL);
7745    assert(branchbounds != NULL);
7746    assert(boundtypes != NULL);
7747    assert(nbranchvars != NULL);
7748    assert(branchvarssize >= 0);
7749 
7750    (*nbranchvars) = 0;
7751 
7752    if( SCIPnodeGetDepth(node) == 0 || node->domchg == NULL )
7753       return;
7754 
7755    nboundchgs = (int)node->domchg->domchgbound.nboundchgs;
7756    boundchgs = node->domchg->domchgbound.boundchgs;
7757 
7758    assert(boundchgs != NULL);
7759    assert(nboundchgs >= 0);
7760 
7761    /* count the number of branching decisions; branching decisions have to be in the beginning of the bound change
7762     * array
7763     */
7764    for( i = 0; i < nboundchgs; i++)
7765    {
7766       if( boundchgs[i].boundchgtype != SCIP_BOUNDCHGTYPE_BRANCHING ) /*lint !e641*/
7767          break;
7768 
7769       (*nbranchvars)++;
7770    }
7771 
7772 #ifndef NDEBUG
7773    /* check that the remaining bound change are no branching decisions */
7774    for( ; i < nboundchgs; i++)
7775       assert(boundchgs[i].boundchgtype != SCIP_BOUNDCHGTYPE_BRANCHING); /*lint !e641*/
7776 #endif
7777 
7778    /* if the arrays have enough space store the branching decisions */
7779    if( branchvarssize >= *nbranchvars )
7780    {
7781       for( i = 0; i < *nbranchvars; i++)
7782       {
7783          assert( boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING ); /*lint !e641*/
7784          branchvars[i] = boundchgs[i].var;
7785          boundtypes[i] = (SCIP_BOUNDTYPE) boundchgs[i].boundtype;
7786          branchbounds[i] = boundchgs[i].newbound;
7787       }
7788    }
7789 }
7790 
7791 /** returns the set of variable branchings that were performed in all ancestor nodes (nodes on the path to the root) to create this node */
SCIPnodeGetAncestorBranchings(SCIP_NODE * node,SCIP_VAR ** branchvars,SCIP_Real * branchbounds,SCIP_BOUNDTYPE * boundtypes,int * nbranchvars,int branchvarssize)7792 void SCIPnodeGetAncestorBranchings(
7793    SCIP_NODE*            node,               /**< node data */
7794    SCIP_VAR**            branchvars,         /**< array of variables on which the branchings has been performed in all ancestors */
7795    SCIP_Real*            branchbounds,       /**< array of bounds which the branchings in all ancestors set */
7796    SCIP_BOUNDTYPE*       boundtypes,         /**< array of boundtypes which the branchings in all ancestors set */
7797    int*                  nbranchvars,        /**< number of variables on which branchings have been performed in all ancestors
7798                                               *   if this is larger than the array size, arrays should be reallocated and method
7799                                               *   should be called again */
7800    int                   branchvarssize      /**< available slots in arrays */
7801    )
7802 {
7803    assert(node != NULL);
7804    assert(branchvars != NULL);
7805    assert(branchbounds != NULL);
7806    assert(boundtypes != NULL);
7807    assert(nbranchvars != NULL);
7808    assert(branchvarssize >= 0);
7809 
7810    (*nbranchvars) = 0;
7811 
7812    while( SCIPnodeGetDepth(node) != 0 )
7813    {
7814       int nodenbranchvars;
7815       int start;
7816       int size;
7817 
7818       start = *nbranchvars < branchvarssize - 1 ? *nbranchvars : branchvarssize - 1;
7819       size = *nbranchvars > branchvarssize ? 0 : branchvarssize-(*nbranchvars);
7820 
7821       SCIPnodeGetParentBranchings(node, &branchvars[start], &branchbounds[start], &boundtypes[start], &nodenbranchvars, size);
7822       *nbranchvars += nodenbranchvars;
7823 
7824       node = node->parent;
7825    }
7826 }
7827 
7828 /** returns the set of variable branchings that were performed between the given @p node and the given @p parent node. */
SCIPnodeGetAncestorBranchingsPart(SCIP_NODE * node,SCIP_NODE * parent,SCIP_VAR ** branchvars,SCIP_Real * branchbounds,SCIP_BOUNDTYPE * boundtypes,int * nbranchvars,int branchvarssize)7829 void SCIPnodeGetAncestorBranchingsPart(
7830    SCIP_NODE*            node,               /**< node data */
7831    SCIP_NODE*            parent,             /**< node data of the last ancestor node */
7832    SCIP_VAR**            branchvars,         /**< array of variables on which the branchings has been performed in all ancestors */
7833    SCIP_Real*            branchbounds,       /**< array of bounds which the branchings in all ancestors set */
7834    SCIP_BOUNDTYPE*       boundtypes,         /**< array of boundtypes which the branchings in all ancestors set */
7835    int*                  nbranchvars,        /**< number of variables on which branchings have been performed in all ancestors
7836                                               *   if this is larger than the array size, arrays should be reallocated and method
7837                                               *   should be called again */
7838    int                   branchvarssize      /**< available slots in arrays */
7839    )
7840 {
7841    assert(node != NULL);
7842    assert(parent != NULL);
7843    assert(branchvars != NULL);
7844    assert(branchbounds != NULL);
7845    assert(boundtypes != NULL);
7846    assert(nbranchvars != NULL);
7847    assert(branchvarssize >= 0);
7848 
7849    (*nbranchvars) = 0;
7850 
7851    while( node != parent )
7852    {
7853       int nodenbranchvars;
7854       int start;
7855       int size;
7856 
7857       start = *nbranchvars < branchvarssize - 1 ? *nbranchvars : branchvarssize - 1;
7858       size = *nbranchvars > branchvarssize ? 0 : branchvarssize-(*nbranchvars);
7859 
7860       SCIPnodeGetParentBranchings(node, &branchvars[start], &branchbounds[start], &boundtypes[start], &nodenbranchvars, size);
7861       *nbranchvars += nodenbranchvars;
7862 
7863       node = node->parent;
7864    }
7865 }
7866 
7867 /** return all bound changes based on constraint propagation; stop saving the bound changes if we reach a branching
7868  *  decision based on a dual information
7869  */
SCIPnodeGetConsProps(SCIP_NODE * node,SCIP_VAR ** vars,SCIP_Real * varbounds,SCIP_BOUNDTYPE * varboundtypes,int * nconspropvars,int conspropvarssize)7870 void SCIPnodeGetConsProps(
7871    SCIP_NODE*            node,               /**< node */
7872    SCIP_VAR**            vars,               /**< array of variables on which constraint propagation triggers a bound change */
7873    SCIP_Real*            varbounds,          /**< array of bounds set by constraint propagation */
7874    SCIP_BOUNDTYPE*       varboundtypes,      /**< array of boundtypes set by constraint propagation */
7875    int*                  nconspropvars,      /**< number of variables on which constraint propagation triggers a bound change
7876                                               *   if this is larger than the array size, arrays should be reallocated and method
7877                                               *   should be called again */
7878    int                   conspropvarssize    /**< available slots in arrays */
7879    )
7880 {  /*lint --e{641}*/
7881    SCIP_BOUNDCHG* boundchgs;
7882    int nboundchgs;
7883    int first_dual;
7884    int nskip;
7885    int i;
7886 
7887    assert(node != NULL);
7888    assert(vars != NULL);
7889    assert(varbounds != NULL);
7890    assert(varboundtypes != NULL);
7891    assert(nconspropvars != NULL);
7892    assert(conspropvarssize >= 0);
7893 
7894    (*nconspropvars) = 0;
7895 
7896    if( SCIPnodeGetDepth(node) == 0 || node->domchg == NULL )
7897       return;
7898 
7899    nboundchgs = (int)node->domchg->domchgbound.nboundchgs;
7900    boundchgs = node->domchg->domchgbound.boundchgs;
7901 
7902    assert(boundchgs != NULL);
7903    assert(nboundchgs >= 0);
7904 
7905    SCIPnodeGetNDomchg(node, &nskip, NULL, NULL);
7906    i = nskip;
7907 
7908    while( i < nboundchgs
7909        && !(boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER && boundchgs[i].data.inferencedata.reason.cons == NULL)
7910        && !(boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER && boundchgs[i].data.inferencedata.reason.prop == NULL) )
7911       i++;
7912 
7913    first_dual = i;
7914 
7915    /* count the number of bound changes because of constraint propagation and propagation */
7916    for(i = nskip; i < first_dual; i++)
7917    {
7918       assert(boundchgs[i].boundchgtype != SCIP_BOUNDCHGTYPE_BRANCHING);
7919 
7920       if( (boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER && boundchgs[i].data.inferencedata.reason.cons != NULL)
7921        || (boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER && boundchgs[i].data.inferencedata.reason.prop != NULL) )
7922       {
7923          if( boundchgs[i].var->vartype != SCIP_VARTYPE_CONTINUOUS )
7924             (*nconspropvars)++;
7925       }
7926       else if( (boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER && boundchgs[i].data.inferencedata.reason.cons == NULL)
7927             || (boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER && boundchgs[i].data.inferencedata.reason.prop == NULL))
7928          break;
7929    }
7930 
7931    /* if the arrays have enough space store the branching decisions */
7932    if( conspropvarssize >= *nconspropvars )
7933    {
7934       int pos;
7935 
7936       for(i = nskip, pos = 0; i < first_dual; i++)
7937       {
7938          if( boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER && boundchgs[i].data.inferencedata.reason.cons != NULL )
7939          {
7940             if( boundchgs[i].var->vartype != SCIP_VARTYPE_CONTINUOUS )
7941             {
7942                vars[pos] = boundchgs[i].var;
7943                varboundtypes[pos] = (SCIP_BOUNDTYPE) boundchgs[i].boundtype;
7944                varbounds[pos] = boundchgs[i].newbound;
7945                pos++;
7946             }
7947          }
7948       }
7949    }
7950 
7951    return;
7952 }
7953 
7954 /** gets all bound changes applied after the first bound change based on dual information.
7955  *
7956  *  @note: currently, we can only detect bound changes based in dual information if they arise from strong branching.
7957  */
SCIPnodeGetBdChgsAfterDual(SCIP_NODE * node,SCIP_VAR ** vars,SCIP_Real * varbounds,SCIP_BOUNDTYPE * varboundtypes,int start,int * nbranchvars,int branchvarssize)7958 void SCIPnodeGetBdChgsAfterDual(
7959    SCIP_NODE*            node,               /**< node */
7960    SCIP_VAR**            vars,               /**< array of variables on which the branching has been performed in the parent node */
7961    SCIP_Real*            varbounds,          /**< array of bounds which the branching in the parent node set */
7962    SCIP_BOUNDTYPE*       varboundtypes,      /**< array of boundtypes which the branching in the parent node set */
7963    int                   start,              /**< first free slot in the arrays */
7964    int*                  nbranchvars,        /**< number of variables on which branching has been performed in the parent node
7965                                               *   if this is larger than the array size, arrays should be reallocated and method
7966                                               *   should be called again */
7967    int                   branchvarssize      /**< available slots in arrays */
7968    )
7969 {  /*lint --e{641}*/
7970    SCIP_BOUNDCHG* boundchgs;
7971    int nboundchgs;
7972    int first_dual;
7973    int i;
7974 
7975    assert(node != NULL);
7976    assert(vars != NULL);
7977    assert(varbounds != NULL);
7978    assert(varboundtypes != NULL);
7979    assert(nbranchvars != NULL);
7980    assert(branchvarssize >= 0);
7981 
7982    (*nbranchvars) = 0;
7983 
7984    if( SCIPnodeGetDepth(node) == 0 || node->domchg == NULL )
7985       return;
7986 
7987    nboundchgs = (int)node->domchg->domchgbound.nboundchgs;
7988    boundchgs = node->domchg->domchgbound.boundchgs;
7989 
7990    assert(boundchgs != NULL);
7991    assert(nboundchgs >= 0);
7992 
7993    /* find the first based on dual information */
7994    i = 0;
7995    while( i < nboundchgs
7996        && !(boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER && boundchgs[i].data.inferencedata.reason.cons == NULL)
7997        && !(boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER && boundchgs[i].data.inferencedata.reason.prop == NULL) )
7998       i++;
7999 
8000    first_dual = i;
8001 
8002    /* count the number of branching decisions; branching decisions have to be in the beginning of the bound change array */
8003    for( ; i < nboundchgs; i++)
8004    {
8005       assert(boundchgs[i].boundchgtype != SCIP_BOUNDCHGTYPE_BRANCHING);
8006 
8007       if( (boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER && boundchgs[i].data.inferencedata.reason.cons != NULL)
8008        || (boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER && boundchgs[i].data.inferencedata.reason.prop != NULL) )
8009       {
8010          if( boundchgs[i].var->vartype != SCIP_VARTYPE_CONTINUOUS )
8011             (*nbranchvars)++;
8012       }
8013    }
8014 
8015    /* if the arrays have enough space store the branching decisions */
8016    if( branchvarssize >= *nbranchvars )
8017    {
8018       int p;
8019       for(i = first_dual, p = start; i < nboundchgs; i++)
8020       {
8021          if( (boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_CONSINFER && boundchgs[i].data.inferencedata.reason.cons != NULL)
8022           || (boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_PROPINFER && boundchgs[i].data.inferencedata.reason.prop != NULL)  )
8023          {
8024             if( boundchgs[i].var->vartype != SCIP_VARTYPE_CONTINUOUS )
8025             {
8026                vars[p] = boundchgs[i].var;
8027                varboundtypes[p] = (SCIP_BOUNDTYPE) boundchgs[i].boundtype;
8028                varbounds[p] = boundchgs[i].newbound;
8029                p++;
8030             }
8031          }
8032       }
8033    }
8034 }
8035 
8036 /** outputs the path into given file stream in GML format */
SCIPnodePrintAncestorBranchings(SCIP_NODE * node,FILE * file)8037 SCIP_RETCODE SCIPnodePrintAncestorBranchings(
8038    SCIP_NODE*            node,               /**< node data */
8039    FILE*                 file                /**< file to output the path */
8040    )
8041 {
8042    int nbranchings;
8043 
8044    nbranchings = 0;
8045 
8046    /* print opening in GML format */
8047    SCIPgmlWriteOpening(file, TRUE);
8048 
8049    while( SCIPnodeGetDepth(node) != 0 )
8050    {
8051       SCIP_BOUNDCHG* boundchgs;
8052       char label[SCIP_MAXSTRLEN];
8053       int nboundchgs;
8054       int i;
8055 
8056       nboundchgs = (int)node->domchg->domchgbound.nboundchgs;
8057       boundchgs = node->domchg->domchgbound.boundchgs;
8058 
8059       for( i = 0; i < nboundchgs; i++)
8060       {
8061          if( boundchgs[i].boundchgtype != SCIP_BOUNDCHGTYPE_BRANCHING ) /*lint !e641*/
8062             break;
8063 
8064          (void) SCIPsnprintf(label, SCIP_MAXSTRLEN, "%s %s %g", SCIPvarGetName(boundchgs[i].var),
8065             (SCIP_BOUNDTYPE) boundchgs[i].boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", boundchgs[i].newbound);
8066 
8067          SCIPgmlWriteNode(file, (unsigned int)nbranchings, label, "circle", NULL, NULL);
8068 
8069          if( nbranchings > 0 )
8070          {
8071             SCIPgmlWriteArc(file, (unsigned int)nbranchings, (unsigned int)(nbranchings-1), NULL, NULL);
8072          }
8073 
8074          nbranchings++;
8075       }
8076 
8077       node = node->parent;
8078    }
8079 
8080    /* print closing in GML format */
8081    SCIPgmlWriteClosing(file);
8082 
8083    return SCIP_OKAY;
8084 }
8085 
8086 /**  returns the set of variable branchings that were performed in all ancestor nodes (nodes on the path to the root) to create this node
8087  *  sorted by the nodes, starting from the current node going up to the root
8088  */
SCIPnodeGetAncestorBranchingPath(SCIP_NODE * node,SCIP_VAR ** branchvars,SCIP_Real * branchbounds,SCIP_BOUNDTYPE * boundtypes,int * nbranchvars,int branchvarssize,int * nodeswitches,int * nnodes,int nodeswitchsize)8089 void SCIPnodeGetAncestorBranchingPath(
8090    SCIP_NODE*            node,               /**< node data */
8091    SCIP_VAR**            branchvars,         /**< array of variables on which the branchings has been performed in all ancestors */
8092    SCIP_Real*            branchbounds,       /**< array of bounds which the branchings in all ancestors set */
8093    SCIP_BOUNDTYPE*       boundtypes,         /**< array of boundtypes which the branchings in all ancestors set */
8094    int*                  nbranchvars,        /**< number of variables on which branchings have been performed in all ancestors
8095                                               *   if this is larger than the array size, arrays should be reallocated and method
8096                                               *   should be called again */
8097    int                   branchvarssize,     /**< available slots in arrays */
8098    int*                  nodeswitches,       /**< marks, where in the arrays the branching decisions of the next node on the path
8099                                               *   start branchings performed at the parent of node always start at position 0.
8100                                               *   For single variable branching, nodeswitches[i] = i holds */
8101    int*                  nnodes,             /**< number of nodes in the nodeswitch array */
8102    int                   nodeswitchsize      /**< available slots in node switch array */
8103    )
8104 {
8105    assert(node != NULL);
8106    assert(branchvars != NULL);
8107    assert(branchbounds != NULL);
8108    assert(boundtypes != NULL);
8109    assert(nbranchvars != NULL);
8110    assert(branchvarssize >= 0);
8111 
8112    (*nbranchvars) = 0;
8113    (*nnodes) = 0;
8114 
8115    /* go up to the root, in the root no domains were changed due to branching */
8116    while( SCIPnodeGetDepth(node) != 0 )
8117    {
8118       int nodenbranchvars;
8119       int start;
8120       int size;
8121 
8122       /* calculate the start position for the current node and the maximum remaining slots in the arrays */
8123       start = *nbranchvars < branchvarssize - 1 ? *nbranchvars : branchvarssize - 1;
8124       size = *nbranchvars > branchvarssize ? 0 : branchvarssize-(*nbranchvars);
8125       if( *nnodes < nodeswitchsize )
8126          nodeswitches[*nnodes] = start;
8127 
8128       /* get branchings for a single node */
8129       SCIPnodeGetParentBranchings(node, &branchvars[start], &branchbounds[start], &boundtypes[start], &nodenbranchvars, size);
8130       *nbranchvars += nodenbranchvars;
8131       (*nnodes)++;
8132 
8133       node = node->parent;
8134    }
8135 }
8136 
8137 /** checks for two nodes whether they share the same root path, i.e., whether one is an ancestor of the other */
SCIPnodesSharePath(SCIP_NODE * node1,SCIP_NODE * node2)8138 SCIP_Bool SCIPnodesSharePath(
8139    SCIP_NODE*            node1,              /**< node data */
8140    SCIP_NODE*            node2               /**< node data */
8141    )
8142 {
8143    assert(node1 != NULL);
8144    assert(node2 != NULL);
8145    assert(SCIPnodeGetDepth(node1) >= 0);
8146    assert(SCIPnodeGetDepth(node2) >= 0);
8147 
8148    /* if node2 is deeper than node1, follow the path until the level of node2 */
8149    while( SCIPnodeGetDepth(node1) < SCIPnodeGetDepth(node2) )
8150       node2 = node2->parent;
8151 
8152    /* if node1 is deeper than node2, follow the path until the level of node1 */
8153    while( SCIPnodeGetDepth(node2) < SCIPnodeGetDepth(node1) )
8154       node1 = node1->parent;
8155 
8156    assert(SCIPnodeGetDepth(node2) == SCIPnodeGetDepth(node1));
8157 
8158    return (node1 == node2);
8159 }
8160 
8161 /** finds the common ancestor node of two given nodes */
SCIPnodesGetCommonAncestor(SCIP_NODE * node1,SCIP_NODE * node2)8162 SCIP_NODE* SCIPnodesGetCommonAncestor(
8163    SCIP_NODE*            node1,              /**< node data */
8164    SCIP_NODE*            node2               /**< node data */
8165    )
8166 {
8167    assert(node1 != NULL);
8168    assert(node2 != NULL);
8169    assert(SCIPnodeGetDepth(node1) >= 0);
8170    assert(SCIPnodeGetDepth(node2) >= 0);
8171 
8172    /* if node2 is deeper than node1, follow the path until the level of node2 */
8173    while( SCIPnodeGetDepth(node1) < SCIPnodeGetDepth(node2) )
8174       node2 = node2->parent;
8175 
8176    /* if node1 is deeper than node2, follow the path until the level of node1 */
8177    while( SCIPnodeGetDepth(node2) < SCIPnodeGetDepth(node1) )
8178       node1 = node1->parent;
8179 
8180    /* move up level by level until you found a common ancestor */
8181    while( node1 != node2 )
8182    {
8183       node1 = node1->parent;
8184       node2 = node2->parent;
8185       assert(SCIPnodeGetDepth(node1) == SCIPnodeGetDepth(node2));
8186    }
8187    assert(SCIPnodeGetDepth(node1) >= 0);
8188 
8189    return node1;
8190 }
8191 
8192 /** returns whether node is in the path to the current node */
SCIPnodeIsActive(SCIP_NODE * node)8193 SCIP_Bool SCIPnodeIsActive(
8194    SCIP_NODE*            node                /**< node */
8195    )
8196 {
8197    assert(node != NULL);
8198 
8199    return node->active;
8200 }
8201 
8202 /** returns whether the node is marked to be propagated again */
SCIPnodeIsPropagatedAgain(SCIP_NODE * node)8203 SCIP_Bool SCIPnodeIsPropagatedAgain(
8204    SCIP_NODE*            node                /**< node data */
8205    )
8206 {
8207    assert(node != NULL);
8208 
8209    return node->reprop;
8210 }
8211 
8212 /* returns the set of changed constraints for a particular node */
SCIPnodeGetConssetchg(SCIP_NODE * node)8213 SCIP_CONSSETCHG* SCIPnodeGetConssetchg(
8214    SCIP_NODE*            node                /**< node data */
8215    )
8216 {
8217    assert(node != NULL);
8218 
8219    return node->conssetchg;
8220 }
8221 
8222 /** gets number of children of the focus node */
SCIPtreeGetNChildren(SCIP_TREE * tree)8223 int SCIPtreeGetNChildren(
8224    SCIP_TREE*            tree                /**< branch and bound tree */
8225    )
8226 {
8227    assert(tree != NULL);
8228 
8229    return tree->nchildren;
8230 }
8231 
8232 /** gets number of siblings of the focus node  */
SCIPtreeGetNSiblings(SCIP_TREE * tree)8233 int SCIPtreeGetNSiblings(
8234    SCIP_TREE*            tree                /**< branch and bound tree */
8235    )
8236 {
8237    assert(tree != NULL);
8238 
8239    return tree->nsiblings;
8240 }
8241 
8242 /** gets number of leaves in the tree (excluding children and siblings of focus nodes) */
SCIPtreeGetNLeaves(SCIP_TREE * tree)8243 int SCIPtreeGetNLeaves(
8244    SCIP_TREE*            tree                /**< branch and bound tree */
8245    )
8246 {
8247    assert(tree != NULL);
8248 
8249    return SCIPnodepqLen(tree->leaves);
8250 }
8251 
8252 /** gets number of open nodes in the tree (children + siblings + leaves) */
SCIPtreeGetNNodes(SCIP_TREE * tree)8253 int SCIPtreeGetNNodes(
8254    SCIP_TREE*            tree                /**< branch and bound tree */
8255    )
8256 {
8257    assert(tree != NULL);
8258 
8259    return tree->nchildren + tree->nsiblings + SCIPtreeGetNLeaves(tree);
8260 }
8261 
8262 /** returns whether the active path goes completely down to the focus node */
SCIPtreeIsPathComplete(SCIP_TREE * tree)8263 SCIP_Bool SCIPtreeIsPathComplete(
8264    SCIP_TREE*            tree                /**< branch and bound tree */
8265    )
8266 {
8267    assert(tree != NULL);
8268    assert(tree->focusnode != NULL || !SCIPtreeProbing(tree));
8269    assert(tree->pathlen == 0 || tree->focusnode != NULL);
8270    assert(tree->pathlen >= 2 || !SCIPtreeProbing(tree));
8271    assert(tree->pathlen == 0 || tree->path[tree->pathlen-1] != NULL);
8272    assert(tree->pathlen == 0 || tree->path[tree->pathlen-1]->depth == tree->pathlen-1);
8273    assert(tree->focusnode == NULL || (int)tree->focusnode->depth >= tree->pathlen
8274       || tree->path[tree->focusnode->depth] == tree->focusnode);
8275 
8276    return (tree->focusnode == NULL || (int)tree->focusnode->depth < tree->pathlen);
8277 }
8278 
8279 /** returns whether the current node is a temporary probing node */
SCIPtreeProbing(SCIP_TREE * tree)8280 SCIP_Bool SCIPtreeProbing(
8281    SCIP_TREE*            tree                /**< branch and bound tree */
8282    )
8283 {
8284    assert(tree != NULL);
8285    assert(tree->probingroot == NULL || (SCIP_NODETYPE)tree->probingroot->nodetype == SCIP_NODETYPE_PROBINGNODE);
8286    assert(tree->probingroot == NULL || tree->pathlen > SCIPnodeGetDepth(tree->probingroot));
8287    assert(tree->probingroot == NULL || tree->path[SCIPnodeGetDepth(tree->probingroot)] == tree->probingroot);
8288 
8289    return (tree->probingroot != NULL);
8290 }
8291 
8292 /** returns the temporary probing root node, or NULL if the we are not in probing mode */
SCIPtreeGetProbingRoot(SCIP_TREE * tree)8293 SCIP_NODE* SCIPtreeGetProbingRoot(
8294    SCIP_TREE*            tree                /**< branch and bound tree */
8295    )
8296 {
8297    assert(tree != NULL);
8298    assert(tree->probingroot == NULL || (SCIP_NODETYPE)tree->probingroot->nodetype == SCIP_NODETYPE_PROBINGNODE);
8299    assert(tree->probingroot == NULL || tree->pathlen > SCIPnodeGetDepth(tree->probingroot));
8300    assert(tree->probingroot == NULL || tree->path[SCIPnodeGetDepth(tree->probingroot)] == tree->probingroot);
8301 
8302    return tree->probingroot;
8303 }
8304 
8305 /** gets focus node of the tree */
SCIPtreeGetFocusNode(SCIP_TREE * tree)8306 SCIP_NODE* SCIPtreeGetFocusNode(
8307    SCIP_TREE*            tree                /**< branch and bound tree */
8308    )
8309 {
8310    assert(tree != NULL);
8311    assert(tree->focusnode != NULL || !SCIPtreeProbing(tree));
8312    assert(tree->pathlen == 0 || tree->focusnode != NULL);
8313    assert(tree->pathlen >= 2 || !SCIPtreeProbing(tree));
8314    assert(tree->pathlen == 0 || tree->path[tree->pathlen-1] != NULL);
8315    assert(tree->pathlen == 0 || tree->path[tree->pathlen-1]->depth == tree->pathlen-1);
8316    assert(tree->focusnode == NULL || (int)tree->focusnode->depth >= tree->pathlen
8317       || tree->path[tree->focusnode->depth] == tree->focusnode);
8318 
8319    return tree->focusnode;
8320 }
8321 
8322 /** gets depth of focus node in the tree */
SCIPtreeGetFocusDepth(SCIP_TREE * tree)8323 int SCIPtreeGetFocusDepth(
8324    SCIP_TREE*            tree                /**< branch and bound tree */
8325    )
8326 {
8327    assert(tree != NULL);
8328    assert(tree->focusnode != NULL || !SCIPtreeProbing(tree));
8329    assert(tree->pathlen == 0 || tree->focusnode != NULL);
8330    assert(tree->pathlen >= 2 || !SCIPtreeProbing(tree));
8331    assert(tree->pathlen == 0 || tree->path[tree->pathlen-1] != NULL);
8332    assert(tree->pathlen == 0 || tree->path[tree->pathlen-1]->depth == tree->pathlen-1);
8333    assert(tree->focusnode == NULL || (int)tree->focusnode->depth >= tree->pathlen
8334       || tree->path[tree->focusnode->depth] == tree->focusnode);
8335 
8336    return tree->focusnode != NULL ? (int)tree->focusnode->depth : -1;
8337 }
8338 
8339 /** returns, whether the LP was or is to be solved in the focus node */
SCIPtreeHasFocusNodeLP(SCIP_TREE * tree)8340 SCIP_Bool SCIPtreeHasFocusNodeLP(
8341    SCIP_TREE*            tree                /**< branch and bound tree */
8342    )
8343 {
8344    assert(tree != NULL);
8345 
8346    return tree->focusnodehaslp;
8347 }
8348 
8349 /** sets mark to solve or to ignore the LP while processing the focus node */
SCIPtreeSetFocusNodeLP(SCIP_TREE * tree,SCIP_Bool solvelp)8350 void SCIPtreeSetFocusNodeLP(
8351    SCIP_TREE*            tree,               /**< branch and bound tree */
8352    SCIP_Bool             solvelp             /**< should the LP be solved in focus node? */
8353    )
8354 {
8355    assert(tree != NULL);
8356 
8357    tree->focusnodehaslp = solvelp;
8358 }
8359 
8360 /** returns whether the LP of the focus node is already constructed */
SCIPtreeIsFocusNodeLPConstructed(SCIP_TREE * tree)8361 SCIP_Bool SCIPtreeIsFocusNodeLPConstructed(
8362    SCIP_TREE*            tree                /**< branch and bound tree */
8363    )
8364 {
8365    assert(tree != NULL);
8366 
8367    return tree->focuslpconstructed;
8368 }
8369 
8370 /** returns whether the focus node is already solved and only propagated again */
SCIPtreeInRepropagation(SCIP_TREE * tree)8371 SCIP_Bool SCIPtreeInRepropagation(
8372    SCIP_TREE*            tree                /**< branch and bound tree */
8373    )
8374 {
8375    assert(tree != NULL);
8376 
8377    return (tree->focusnode != NULL && SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_REFOCUSNODE);
8378 }
8379 
8380 /** gets current node of the tree, i.e. the last node in the active path, or NULL if no current node exists */
SCIPtreeGetCurrentNode(SCIP_TREE * tree)8381 SCIP_NODE* SCIPtreeGetCurrentNode(
8382    SCIP_TREE*            tree                /**< branch and bound tree */
8383    )
8384 {
8385    assert(tree != NULL);
8386    assert(tree->focusnode != NULL || !SCIPtreeProbing(tree));
8387    assert(tree->pathlen == 0 || tree->focusnode != NULL);
8388    assert(tree->pathlen >= 2 || !SCIPtreeProbing(tree));
8389    assert(tree->pathlen == 0 || tree->path[tree->pathlen-1] != NULL);
8390    assert(tree->pathlen == 0 || tree->path[tree->pathlen-1]->depth == tree->pathlen-1);
8391    assert(tree->focusnode == NULL || (int)tree->focusnode->depth >= tree->pathlen
8392       || tree->path[tree->focusnode->depth] == tree->focusnode);
8393 
8394    return (tree->pathlen > 0 ? tree->path[tree->pathlen-1] : NULL);
8395 }
8396 
8397 /** gets depth of current node in the tree, i.e. the length of the active path minus 1, or -1 if no current node exists */
SCIPtreeGetCurrentDepth(SCIP_TREE * tree)8398 int SCIPtreeGetCurrentDepth(
8399    SCIP_TREE*            tree                /**< branch and bound tree */
8400    )
8401 {
8402    assert(tree != NULL);
8403    assert(tree->focusnode != NULL || !SCIPtreeProbing(tree));
8404    assert(tree->pathlen == 0 || tree->focusnode != NULL);
8405    assert(tree->pathlen >= 2 || !SCIPtreeProbing(tree));
8406    assert(tree->pathlen == 0 || tree->path[tree->pathlen-1] != NULL);
8407    assert(tree->pathlen == 0 || tree->path[tree->pathlen-1]->depth == tree->pathlen-1);
8408    assert(tree->focusnode == NULL || (int)tree->focusnode->depth >= tree->pathlen
8409       || tree->path[tree->focusnode->depth] == tree->focusnode);
8410 
8411    return tree->pathlen-1;
8412 }
8413 
8414 /** returns, whether the LP was or is to be solved in the current node */
SCIPtreeHasCurrentNodeLP(SCIP_TREE * tree)8415 SCIP_Bool SCIPtreeHasCurrentNodeLP(
8416    SCIP_TREE*            tree                /**< branch and bound tree */
8417    )
8418 {
8419    assert(tree != NULL);
8420    assert(SCIPtreeIsPathComplete(tree));
8421 
8422    return SCIPtreeProbing(tree) ? tree->probingnodehaslp : SCIPtreeHasFocusNodeLP(tree);
8423 }
8424 
8425 /** returns the current probing depth, i.e. the number of probing sub nodes existing in the probing path */
SCIPtreeGetProbingDepth(SCIP_TREE * tree)8426 int SCIPtreeGetProbingDepth(
8427    SCIP_TREE*            tree                /**< branch and bound tree */
8428    )
8429 {
8430    assert(tree != NULL);
8431    assert(SCIPtreeProbing(tree));
8432 
8433    return SCIPtreeGetCurrentDepth(tree) - SCIPnodeGetDepth(tree->probingroot);
8434 }
8435 
8436 /** returns the depth of the effective root node (i.e. the first depth level of a node with at least two children) */
SCIPtreeGetEffectiveRootDepth(SCIP_TREE * tree)8437 int SCIPtreeGetEffectiveRootDepth(
8438    SCIP_TREE*            tree                /**< branch and bound tree */
8439    )
8440 {
8441    assert(tree != NULL);
8442    assert(tree->effectiverootdepth >= 0);
8443 
8444    return tree->effectiverootdepth;
8445 }
8446 
8447 /** gets the root node of the tree */
SCIPtreeGetRootNode(SCIP_TREE * tree)8448 SCIP_NODE* SCIPtreeGetRootNode(
8449    SCIP_TREE*            tree                /**< branch and bound tree */
8450    )
8451 {
8452    assert(tree != NULL);
8453 
8454    return tree->root;
8455 }
8456 
8457 /** returns whether we are in probing and the objective value of at least one column was changed */
8458 
SCIPtreeProbingObjChanged(SCIP_TREE * tree)8459 SCIP_Bool SCIPtreeProbingObjChanged(
8460    SCIP_TREE*            tree                /**< branch and bound tree */
8461    )
8462 {
8463    assert(tree != NULL);
8464    assert(SCIPtreeProbing(tree) || !tree->probingobjchanged);
8465 
8466    return tree->probingobjchanged;
8467 }
8468 
8469 /** marks the current probing node to have a changed objective function */
SCIPtreeMarkProbingObjChanged(SCIP_TREE * tree)8470 void SCIPtreeMarkProbingObjChanged(
8471    SCIP_TREE*            tree                /**< branch and bound tree */
8472    )
8473 {
8474    assert(tree != NULL);
8475    assert(SCIPtreeProbing(tree));
8476 
8477    tree->probingobjchanged = TRUE;
8478 }
8479