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