Scippy

SCIP

Solving Constraint Integer Programs

tree.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2024 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file tree.c
26 * @ingroup OTHER_CFILES
27 * @brief methods for branch and bound tree
28 * @author Tobias Achterberg
29 * @author Timo Berthold
30 * @author Gerald Gamrath
31 */
32
33/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
34
35#include <assert.h>
36
37#include "scip/def.h"
38#include "scip/set.h"
39#include "scip/stat.h"
40#include "scip/clock.h"
41#include "scip/visual.h"
42#include "scip/event.h"
43#include "scip/lp.h"
44#include "scip/relax.h"
45#include "scip/var.h"
46#include "scip/implics.h"
47#include "scip/primal.h"
48#include "scip/tree.h"
49#include "scip/reopt.h"
50#include "scip/conflictstore.h"
51#include "scip/solve.h"
52#include "scip/cons.h"
53#include "scip/nodesel.h"
54#include "scip/prop.h"
55#include "scip/debug.h"
56#include "scip/prob.h"
57#include "scip/scip.h"
58#include "scip/struct_event.h"
59#include "scip/pub_message.h"
60#include "scip/struct_branch.h"
61#include "lpi/lpi.h"
62
63
64#define MAXREPROPMARK 511 /**< maximal subtree repropagation marker; must correspond to node data structure */
65
66
67/*
68 * dynamic memory arrays
69 */
70
71/** resizes children arrays to be able to store at least num nodes */
72static
74 SCIP_TREE* tree, /**< branch and bound tree */
75 SCIP_SET* set, /**< global SCIP settings */
76 int num /**< minimal number of node slots in array */
77 )
78{
79 assert(tree != NULL);
80 assert(set != NULL);
81
82 if( num > tree->childrensize )
83 {
84 int newsize;
85
86 newsize = SCIPsetCalcMemGrowSize(set, num);
87 SCIP_ALLOC( BMSreallocMemoryArray(&tree->children, newsize) );
89 tree->childrensize = newsize;
90 }
91 assert(num <= tree->childrensize);
92
93 return SCIP_OKAY;
94}
95
96/** resizes path array to be able to store at least num nodes */
97static
99 SCIP_TREE* tree, /**< branch and bound tree */
100 SCIP_SET* set, /**< global SCIP settings */
101 int num /**< minimal number of node slots in path */
102 )
103{
104 assert(tree != NULL);
105 assert(set != NULL);
106
107 if( num > tree->pathsize )
108 {
109 int newsize;
110
111 newsize = SCIPsetCalcPathGrowSize(set, num);
112 SCIP_ALLOC( BMSreallocMemoryArray(&tree->path, newsize) );
113 SCIP_ALLOC( BMSreallocMemoryArray(&tree->pathnlpcols, newsize) );
114 SCIP_ALLOC( BMSreallocMemoryArray(&tree->pathnlprows, newsize) );
115 tree->pathsize = newsize;
116 }
117 assert(num <= tree->pathsize);
118
119 return SCIP_OKAY;
120}
121
122/** resizes pendingbdchgs array to be able to store at least num nodes */
123static
125 SCIP_TREE* tree, /**< branch and bound tree */
126 SCIP_SET* set, /**< global SCIP settings */
127 int num /**< minimal number of node slots in path */
128 )
129{
130 assert(tree != NULL);
131 assert(set != NULL);
132
133 if( num > tree->pendingbdchgssize )
134 {
135 int newsize;
136
137 newsize = SCIPsetCalcMemGrowSize(set, num);
139 tree->pendingbdchgssize = newsize;
140 }
141 assert(num <= tree->pendingbdchgssize);
142
143 return SCIP_OKAY;
144}
145
146
147
148
149/*
150 * Node methods
151 */
152
153/** node comparator for best lower bound */
154SCIP_DECL_SORTPTRCOMP(SCIPnodeCompLowerbound)
155{ /*lint --e{715}*/
156 assert(elem1 != NULL);
157 assert(elem2 != NULL);
158
159 if( ((SCIP_NODE*)elem1)->lowerbound < ((SCIP_NODE*)elem2)->lowerbound )
160 return -1;
161 else if( ((SCIP_NODE*)elem1)->lowerbound > ((SCIP_NODE*)elem2)->lowerbound )
162 return +1;
163 else
164 return 0;
165}
166
167/** increases the reference counter of the LP state in the fork */
168static
170 SCIP_FORK* fork, /**< fork data */
171 int nuses /**< number to add to the usage counter */
172 )
173{
174 assert(fork != NULL);
175 assert(fork->nlpistateref >= 0);
176 assert(nuses > 0);
177
178 fork->nlpistateref += nuses;
179 SCIPdebugMessage("captured LPI state of fork %p %d times -> new nlpistateref=%d\n", (void*)fork, nuses, fork->nlpistateref);
180}
181
182/** decreases the reference counter of the LP state in the fork */
183static
185 SCIP_FORK* fork, /**< fork data */
186 BMS_BLKMEM* blkmem, /**< block memory buffers */
187 SCIP_LP* lp /**< current LP data */
188 )
189{
190 assert(fork != NULL);
191 assert(fork->nlpistateref > 0);
192 assert(blkmem != NULL);
193 assert(lp != NULL);
194
195 fork->nlpistateref--;
196 if( fork->nlpistateref == 0 )
197 {
198 SCIP_CALL( SCIPlpFreeState(lp, blkmem, &(fork->lpistate)) );
199 }
200
201 SCIPdebugMessage("released LPI state of fork %p -> new nlpistateref=%d\n", (void*)fork, fork->nlpistateref);
202
203 return SCIP_OKAY;
204}
205
206/** increases the reference counter of the LP state in the subroot */
207static
209 SCIP_SUBROOT* subroot, /**< subroot data */
210 int nuses /**< number to add to the usage counter */
211 )
212{
213 assert(subroot != NULL);
214 assert(subroot->nlpistateref >= 0);
215 assert(nuses > 0);
216
217 subroot->nlpistateref += nuses;
218 SCIPdebugMessage("captured LPI state of subroot %p %d times -> new nlpistateref=%d\n",
219 (void*)subroot, nuses, subroot->nlpistateref);
220}
221
222/** decreases the reference counter of the LP state in the subroot */
223static
225 SCIP_SUBROOT* subroot, /**< subroot data */
226 BMS_BLKMEM* blkmem, /**< block memory buffers */
227 SCIP_LP* lp /**< current LP data */
228 )
229{
230 assert(subroot != NULL);
231 assert(subroot->nlpistateref > 0);
232 assert(blkmem != NULL);
233 assert(lp != NULL);
234
235 subroot->nlpistateref--;
236 if( subroot->nlpistateref == 0 )
237 {
238 SCIP_CALL( SCIPlpFreeState(lp, blkmem, &(subroot->lpistate)) );
239 }
240
241 SCIPdebugMessage("released LPI state of subroot %p -> new nlpistateref=%d\n", (void*)subroot, subroot->nlpistateref);
242
243 return SCIP_OKAY;
244}
245
246/** increases the reference counter of the LP state in the fork or subroot node */
248 SCIP_NODE* node, /**< fork/subroot node */
249 int nuses /**< number to add to the usage counter */
250 )
251{
252 assert(node != NULL);
253
254 SCIPdebugMessage("capture %d times LPI state of node #%" SCIP_LONGINT_FORMAT " at depth %d (current: %d)\n",
255 nuses, SCIPnodeGetNumber(node), SCIPnodeGetDepth(node),
257
258 switch( SCIPnodeGetType(node) )
259 {
261 forkCaptureLPIState(node->data.fork, nuses);
262 break;
264 subrootCaptureLPIState(node->data.subroot, nuses);
265 break;
266 default:
267 SCIPerrorMessage("node for capturing the LPI state is neither fork nor subroot\n");
268 SCIPABORT();
269 return SCIP_INVALIDDATA; /*lint !e527*/
270 } /*lint !e788*/
271 return SCIP_OKAY;
272}
273
274/** decreases the reference counter of the LP state in the fork or subroot node */
276 SCIP_NODE* node, /**< fork/subroot node */
277 BMS_BLKMEM* blkmem, /**< block memory buffers */
278 SCIP_LP* lp /**< current LP data */
279 )
280{
281 assert(node != NULL);
282
283 SCIPdebugMessage("release LPI state of node #%" SCIP_LONGINT_FORMAT " at depth %d (current: %d)\n",
286 switch( SCIPnodeGetType(node) )
287 {
289 return forkReleaseLPIState(node->data.fork, blkmem, lp);
291 return subrootReleaseLPIState(node->data.subroot, blkmem, lp);
292 default:
293 SCIPerrorMessage("node for releasing the LPI state is neither fork nor subroot\n");
294 return SCIP_INVALIDDATA;
295 } /*lint !e788*/
296}
297
298/** creates probingnode data without LP information */
299static
301 SCIP_PROBINGNODE** probingnode, /**< pointer to probingnode data */
302 BMS_BLKMEM* blkmem, /**< block memory */
303 SCIP_LP* lp /**< current LP data */
304 )
305{
306 assert(probingnode != NULL);
307
308 SCIP_ALLOC( BMSallocBlockMemory(blkmem, probingnode) );
309
310 (*probingnode)->lpistate = NULL;
311 (*probingnode)->lpinorms = NULL;
312 (*probingnode)->ninitialcols = SCIPlpGetNCols(lp);
313 (*probingnode)->ninitialrows = SCIPlpGetNRows(lp);
314 (*probingnode)->ncols = (*probingnode)->ninitialcols;
315 (*probingnode)->nrows = (*probingnode)->ninitialrows;
316 (*probingnode)->origobjvars = NULL;
317 (*probingnode)->origobjvals = NULL;
318 (*probingnode)->nchgdobjs = 0;
319
320 SCIPdebugMessage("created probingnode information (%d cols, %d rows)\n", (*probingnode)->ncols, (*probingnode)->nrows);
321
322 return SCIP_OKAY;
323}
324
325/** updates LP information in probingnode data */
326static
328 SCIP_PROBINGNODE* probingnode, /**< probingnode data */
329 BMS_BLKMEM* blkmem, /**< block memory */
330 SCIP_TREE* tree, /**< branch and bound tree */
331 SCIP_LP* lp /**< current LP data */
332 )
333{
334 SCIP_Bool storenorms = FALSE;
335
336 assert(probingnode != NULL);
337 assert(SCIPtreeIsPathComplete(tree));
338 assert(lp != NULL);
339
340 /* free old LP state */
341 if( probingnode->lpistate != NULL )
342 {
343 SCIP_CALL( SCIPlpFreeState(lp, blkmem, &probingnode->lpistate) );
344 }
345
346 /* free old LP norms */
347 if( probingnode->lpinorms != NULL )
348 {
349 SCIP_CALL( SCIPlpFreeNorms(lp, blkmem, &probingnode->lpinorms) );
350 probingnode->lpinorms = NULL;
351 storenorms = TRUE;
352 }
353
354 /* get current LP state */
355 if( lp->flushed && lp->solved )
356 {
357 SCIP_CALL( SCIPlpGetState(lp, blkmem, &probingnode->lpistate) );
358
359 /* if LP norms were stored at this node before, store the new ones */
360 if( storenorms )
361 {
362 SCIP_CALL( SCIPlpGetNorms(lp, blkmem, &probingnode->lpinorms) );
363 }
364 probingnode->lpwasprimfeas = lp->primalfeasible;
365 probingnode->lpwasprimchecked = lp->primalchecked;
366 probingnode->lpwasdualfeas = lp->dualfeasible;
367 probingnode->lpwasdualchecked = lp->dualchecked;
368 }
369 else
370 probingnode->lpistate = NULL;
371
372 probingnode->ncols = SCIPlpGetNCols(lp);
373 probingnode->nrows = SCIPlpGetNRows(lp);
374
375 SCIPdebugMessage("updated probingnode information (%d cols, %d rows)\n", probingnode->ncols, probingnode->nrows);
376
377 return SCIP_OKAY;
378}
379
380/** frees probingnode data */
381static
383 SCIP_PROBINGNODE** probingnode, /**< probingnode data */
384 BMS_BLKMEM* blkmem, /**< block memory */
385 SCIP_LP* lp /**< current LP data */
386 )
387{
388 assert(probingnode != NULL);
389 assert(*probingnode != NULL);
390
391 /* free the associated LP state */
392 if( (*probingnode)->lpistate != NULL )
393 {
394 SCIP_CALL( SCIPlpFreeState(lp, blkmem, &(*probingnode)->lpistate) );
395 }
396 /* free the associated LP norms */
397 if( (*probingnode)->lpinorms != NULL )
398 {
399 SCIP_CALL( SCIPlpFreeNorms(lp, blkmem, &(*probingnode)->lpinorms) );
400 }
401
402 /* free objective information */
403 if( (*probingnode)->nchgdobjs > 0 )
404 {
405 assert((*probingnode)->origobjvars != NULL);
406 assert((*probingnode)->origobjvals != NULL);
407
408 BMSfreeMemoryArray(&(*probingnode)->origobjvars);
409 BMSfreeMemoryArray(&(*probingnode)->origobjvals);
410 }
411
412 BMSfreeBlockMemory(blkmem, probingnode);
413
414 return SCIP_OKAY;
415}
416
417/** initializes junction data */
418static
420 SCIP_JUNCTION* junction, /**< pointer to junction data */
421 SCIP_TREE* tree /**< branch and bound tree */
422 )
423{
424 assert(junction != NULL);
425 assert(tree != NULL);
426 assert(tree->nchildren > 0);
427 assert(SCIPtreeIsPathComplete(tree));
428 assert(tree->focusnode != NULL);
429
430 junction->nchildren = tree->nchildren;
431
432 /* increase the LPI state usage counter of the current LP fork */
433 if( tree->focuslpstatefork != NULL )
434 {
436 }
437
438 return SCIP_OKAY;
439}
440
441/** creates pseudofork data */
442static
444 SCIP_PSEUDOFORK** pseudofork, /**< pointer to pseudofork data */
445 BMS_BLKMEM* blkmem, /**< block memory */
446 SCIP_TREE* tree, /**< branch and bound tree */
447 SCIP_LP* lp /**< current LP data */
448 )
449{
450 assert(pseudofork != NULL);
451 assert(blkmem != NULL);
452 assert(tree != NULL);
453 assert(tree->nchildren > 0);
454 assert(SCIPtreeIsPathComplete(tree));
455 assert(tree->focusnode != NULL);
456
457 SCIP_ALLOC( BMSallocBlockMemory(blkmem, pseudofork) );
458
459 (*pseudofork)->addedcols = NULL;
460 (*pseudofork)->addedrows = NULL;
461 (*pseudofork)->naddedcols = SCIPlpGetNNewcols(lp);
462 (*pseudofork)->naddedrows = SCIPlpGetNNewrows(lp);
463 (*pseudofork)->nchildren = tree->nchildren;
464
465 SCIPdebugMessage("creating pseudofork information with %d children (%d new cols, %d new rows)\n",
466 (*pseudofork)->nchildren, (*pseudofork)->naddedcols, (*pseudofork)->naddedrows);
467
468 if( (*pseudofork)->naddedcols > 0 )
469 {
470 /* copy the newly created columns to the pseudofork's col array */
471 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*pseudofork)->addedcols, SCIPlpGetNewcols(lp), (*pseudofork)->naddedcols) ); /*lint !e666*/
472 }
473 if( (*pseudofork)->naddedrows > 0 )
474 {
475 int i;
476
477 /* copy the newly created rows to the pseudofork's row array */
478 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*pseudofork)->addedrows, SCIPlpGetNewrows(lp), (*pseudofork)->naddedrows) ); /*lint !e666*/
479
480 /* capture the added rows */
481 for( i = 0; i < (*pseudofork)->naddedrows; ++i )
482 SCIProwCapture((*pseudofork)->addedrows[i]);
483 }
484
485 /* increase the LPI state usage counter of the current LP fork */
486 if( tree->focuslpstatefork != NULL )
487 {
489 }
490
491 return SCIP_OKAY;
492}
493
494/** frees pseudofork data */
495static
497 SCIP_PSEUDOFORK** pseudofork, /**< pseudofork data */
498 BMS_BLKMEM* blkmem, /**< block memory */
499 SCIP_SET* set, /**< global SCIP settings */
500 SCIP_LP* lp /**< current LP data */
501 )
502{
503 int i;
504
505 assert(pseudofork != NULL);
506 assert(*pseudofork != NULL);
507 assert((*pseudofork)->nchildren == 0);
508 assert(blkmem != NULL);
509 assert(set != NULL);
510
511 /* release the added rows */
512 for( i = 0; i < (*pseudofork)->naddedrows; ++i )
513 {
514 SCIP_CALL( SCIProwRelease(&(*pseudofork)->addedrows[i], blkmem, set, lp) );
515 }
516
517 BMSfreeBlockMemoryArrayNull(blkmem, &(*pseudofork)->addedcols, (*pseudofork)->naddedcols);
518 BMSfreeBlockMemoryArrayNull(blkmem, &(*pseudofork)->addedrows, (*pseudofork)->naddedrows);
519 BMSfreeBlockMemory(blkmem, pseudofork);
520
521 return SCIP_OKAY;
522}
523
524/** creates fork data */
525static
527 SCIP_FORK** fork, /**< pointer to fork data */
528 BMS_BLKMEM* blkmem, /**< block memory */
529 SCIP_SET* set, /**< global SCIP settings */
530 SCIP_PROB* prob, /**< transformed problem after presolve */
531 SCIP_TREE* tree, /**< branch and bound tree */
532 SCIP_LP* lp /**< current LP data */
533 )
534{
535 assert(fork != NULL);
536 assert(blkmem != NULL);
537 assert(tree != NULL);
538 assert(tree->nchildren > 0);
539 assert(tree->nchildren < (1 << 30));
540 assert(SCIPtreeIsPathComplete(tree));
541 assert(tree->focusnode != NULL);
542 assert(lp != NULL);
543 assert(lp->flushed);
544 assert(lp->solved);
546
547 SCIP_ALLOC( BMSallocBlockMemory(blkmem, fork) );
548
549 SCIP_CALL( SCIPlpGetState(lp, blkmem, &((*fork)->lpistate)) );
550 (*fork)->lpwasprimfeas = lp->primalfeasible;
551 (*fork)->lpwasprimchecked = lp->primalchecked;
552 (*fork)->lpwasdualfeas = lp->dualfeasible;
553 (*fork)->lpwasdualchecked = lp->dualchecked;
554 (*fork)->lpobjval = SCIPlpGetObjval(lp, set, prob);
555 (*fork)->nlpistateref = 0;
556 (*fork)->addedcols = NULL;
557 (*fork)->addedrows = NULL;
558 (*fork)->naddedcols = SCIPlpGetNNewcols(lp);
559 (*fork)->naddedrows = SCIPlpGetNNewrows(lp);
560 (*fork)->nchildren = (unsigned int) tree->nchildren;
561
562 SCIPsetDebugMsg(set, "creating fork information with %u children (%d new cols, %d new rows)\n", (*fork)->nchildren, (*fork)->naddedcols, (*fork)->naddedrows);
563
564 if( (*fork)->naddedcols > 0 )
565 {
566 /* copy the newly created columns to the fork's col array */
567 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*fork)->addedcols, SCIPlpGetNewcols(lp), (*fork)->naddedcols) ); /*lint !e666*/
568 }
569 if( (*fork)->naddedrows > 0 )
570 {
571 int i;
572
573 /* copy the newly created rows to the fork's row array */
574 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*fork)->addedrows, SCIPlpGetNewrows(lp), (*fork)->naddedrows) ); /*lint !e666*/
575
576 /* capture the added rows */
577 for( i = 0; i < (*fork)->naddedrows; ++i )
578 SCIProwCapture((*fork)->addedrows[i]);
579 }
580
581 /* capture the LPI state for the children */
582 forkCaptureLPIState(*fork, tree->nchildren);
583
584 return SCIP_OKAY;
585}
586
587/** frees fork data */
588static
590 SCIP_FORK** fork, /**< fork data */
591 BMS_BLKMEM* blkmem, /**< block memory */
592 SCIP_SET* set, /**< global SCIP settings */
593 SCIP_LP* lp /**< current LP data */
594 )
595{
596 int i;
597
598 assert(fork != NULL);
599 assert(*fork != NULL);
600 assert((*fork)->nchildren == 0);
601 assert((*fork)->nlpistateref == 0);
602 assert((*fork)->lpistate == NULL);
603 assert(blkmem != NULL);
604 assert(set != NULL);
605 assert(lp != NULL);
606
607 /* release the added rows */
608 for( i = (*fork)->naddedrows - 1; i >= 0; --i )
609 {
610 SCIP_CALL( SCIProwRelease(&(*fork)->addedrows[i], blkmem, set, lp) );
611 }
612
613 BMSfreeBlockMemoryArrayNull(blkmem, &(*fork)->addedcols, (*fork)->naddedcols);
614 BMSfreeBlockMemoryArrayNull(blkmem, &(*fork)->addedrows, (*fork)->naddedrows);
615 BMSfreeBlockMemory(blkmem, fork);
616
617 return SCIP_OKAY;
618}
619
620#ifdef WITHSUBROOTS /** @todo test whether subroots should be created */
621/** creates subroot data */
622static
623SCIP_RETCODE subrootCreate(
624 SCIP_SUBROOT** subroot, /**< pointer to subroot data */
625 BMS_BLKMEM* blkmem, /**< block memory */
626 SCIP_SET* set, /**< global SCIP settings */
627 SCIP_PROB* prob, /**< transformed problem after presolve */
628 SCIP_TREE* tree, /**< branch and bound tree */
629 SCIP_LP* lp /**< current LP data */
630 )
631{
632 int i;
633
634 assert(subroot != NULL);
635 assert(blkmem != NULL);
636 assert(tree != NULL);
637 assert(tree->nchildren > 0);
638 assert(SCIPtreeIsPathComplete(tree));
639 assert(tree->focusnode != NULL);
640 assert(lp != NULL);
641 assert(lp->flushed);
642 assert(lp->solved);
644
645 SCIP_ALLOC( BMSallocBlockMemory(blkmem, subroot) );
646 (*subroot)->lpobjval = SCIPlpGetObjval(lp, set, prob);
647 (*subroot)->nlpistateref = 0;
648 (*subroot)->ncols = SCIPlpGetNCols(lp);
649 (*subroot)->nrows = SCIPlpGetNRows(lp);
650 (*subroot)->nchildren = (unsigned int) tree->nchildren;
651 SCIP_CALL( SCIPlpGetState(lp, blkmem, &((*subroot)->lpistate)) );
652 (*subroot)->lpwasprimfeas = lp->primalfeasible;
653 (*subroot)->lpwasprimchecked = lp->primalchecked;
654 (*subroot)->lpwasdualfeas = lp->dualfeasible;
655 (*subroot)->lpwasdualchecked = lp->dualchecked;
656
657 if( (*subroot)->ncols != 0 )
658 {
659 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*subroot)->cols, SCIPlpGetCols(lp), (*subroot)->ncols) );
660 }
661 else
662 (*subroot)->cols = NULL;
663 if( (*subroot)->nrows != 0 )
664 {
665 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*subroot)->rows, SCIPlpGetRows(lp), (*subroot)->nrows) );
666 }
667 else
668 (*subroot)->rows = NULL;
669
670 /* capture the rows of the subroot */
671 for( i = 0; i < (*subroot)->nrows; ++i )
672 SCIProwCapture((*subroot)->rows[i]);
673
674 /* capture the LPI state for the children */
675 subrootCaptureLPIState(*subroot, tree->nchildren);
676
677 return SCIP_OKAY;
678}
679#endif
680
681/** frees subroot */
682static
684 SCIP_SUBROOT** subroot, /**< subroot data */
685 BMS_BLKMEM* blkmem, /**< block memory */
686 SCIP_SET* set, /**< global SCIP settings */
687 SCIP_LP* lp /**< current LP data */
688 )
689{
690 int i;
691
692 assert(subroot != NULL);
693 assert(*subroot != NULL);
694 assert((*subroot)->nchildren == 0);
695 assert((*subroot)->nlpistateref == 0);
696 assert((*subroot)->lpistate == NULL);
697 assert(blkmem != NULL);
698 assert(set != NULL);
699 assert(lp != NULL);
700
701 /* release the rows of the subroot */
702 for( i = 0; i < (*subroot)->nrows; ++i )
703 {
704 SCIP_CALL( SCIProwRelease(&(*subroot)->rows[i], blkmem, set, lp) );
705 }
706
707 BMSfreeBlockMemoryArrayNull(blkmem, &(*subroot)->cols, (*subroot)->ncols);
708 BMSfreeBlockMemoryArrayNull(blkmem, &(*subroot)->rows, (*subroot)->nrows);
709 BMSfreeBlockMemory(blkmem, subroot);
710
711 return SCIP_OKAY;
712}
713
714/** removes given sibling node from the siblings array */
715static
717 SCIP_TREE* tree, /**< branch and bound tree */
718 SCIP_NODE* sibling /**< sibling node to remove */
719 )
720{
721 int delpos;
722
723 assert(tree != NULL);
724 assert(sibling != NULL);
725 assert(SCIPnodeGetType(sibling) == SCIP_NODETYPE_SIBLING);
726 assert(sibling->data.sibling.arraypos >= 0 && sibling->data.sibling.arraypos < tree->nsiblings);
727 assert(tree->siblings[sibling->data.sibling.arraypos] == sibling);
728 assert(SCIPnodeGetType(tree->siblings[tree->nsiblings-1]) == SCIP_NODETYPE_SIBLING);
729
730 delpos = sibling->data.sibling.arraypos;
731
732 /* move last sibling in array to position of removed sibling */
733 tree->siblings[delpos] = tree->siblings[tree->nsiblings-1];
734 tree->siblingsprio[delpos] = tree->siblingsprio[tree->nsiblings-1];
735 tree->siblings[delpos]->data.sibling.arraypos = delpos;
736 sibling->data.sibling.arraypos = -1;
737 tree->nsiblings--;
738}
739
740/** adds given child node to children array of focus node */
741static
743 SCIP_TREE* tree, /**< branch and bound tree */
744 SCIP_SET* set, /**< global SCIP settings */
745 SCIP_NODE* child, /**< child node to add */
746 SCIP_Real nodeselprio /**< node selection priority of child node */
747 )
748{
749 assert(tree != NULL);
750 assert(child != NULL);
751 assert(SCIPnodeGetType(child) == SCIP_NODETYPE_CHILD);
752 assert(child->data.child.arraypos == -1);
753
754 SCIP_CALL( treeEnsureChildrenMem(tree, set, tree->nchildren+1) );
755 tree->children[tree->nchildren] = child;
756 tree->childrenprio[tree->nchildren] = nodeselprio;
757 child->data.child.arraypos = tree->nchildren;
758 tree->nchildren++;
759
760 return SCIP_OKAY;
761}
762
763/** removes given child node from the children array */
764static
766 SCIP_TREE* tree, /**< branch and bound tree */
767 SCIP_NODE* child /**< child node to remove */
768 )
769{
770 int delpos;
771
772 assert(tree != NULL);
773 assert(child != NULL);
774 assert(SCIPnodeGetType(child) == SCIP_NODETYPE_CHILD);
775 assert(child->data.child.arraypos >= 0 && child->data.child.arraypos < tree->nchildren);
776 assert(tree->children[child->data.child.arraypos] == child);
777 assert(SCIPnodeGetType(tree->children[tree->nchildren-1]) == SCIP_NODETYPE_CHILD);
778
779 delpos = child->data.child.arraypos;
780
781 /* move last child in array to position of removed child */
782 tree->children[delpos] = tree->children[tree->nchildren-1];
783 tree->childrenprio[delpos] = tree->childrenprio[tree->nchildren-1];
784 tree->children[delpos]->data.child.arraypos = delpos;
785 child->data.child.arraypos = -1;
786 tree->nchildren--;
787}
788
789/** makes node a child of the given parent node, which must be the focus node; if the child is a probing node,
790 * the parent node can also be a refocused node or a probing node
791 */
792static
794 SCIP_NODE* node, /**< child node */
795 BMS_BLKMEM* blkmem, /**< block memory buffers */
796 SCIP_SET* set, /**< global SCIP settings */
797 SCIP_TREE* tree, /**< branch and bound tree */
798 SCIP_NODE* parent, /**< parent (= focus) node (or NULL, if node is root) */
799 SCIP_Real nodeselprio /**< node selection priority of child node */
800 )
801{
802 assert(node != NULL);
803 assert(node->parent == NULL);
805 assert(node->conssetchg == NULL);
806 assert(node->domchg == NULL);
807 assert(SCIPsetIsInfinity(set, -node->lowerbound)); /* node was just created */
808 assert(blkmem != NULL);
809 assert(set != NULL);
810 assert(tree != NULL);
811 assert(SCIPtreeIsPathComplete(tree));
812 assert(tree->pathlen == 0 || tree->path[tree->pathlen-1] == parent);
813 assert(parent == tree->focusnode || SCIPnodeGetType(parent) == SCIP_NODETYPE_PROBINGNODE);
814 assert(parent == NULL || SCIPnodeGetType(parent) == SCIP_NODETYPE_FOCUSNODE
818
819 /* link node to parent */
820 node->parent = parent;
821 if( parent != NULL )
822 {
823 assert(parent->lowerbound <= parent->estimate);
824 node->lowerbound = parent->lowerbound;
825 node->estimate = parent->estimate;
826 node->depth = parent->depth+1; /*lint !e732*/
827 if( parent->depth >= SCIP_MAXTREEDEPTH )
828 {
829 SCIPerrorMessage("maximal depth level exceeded\n");
830 return SCIP_MAXDEPTHLEVEL;
831 }
832 }
833 SCIPsetDebugMsg(set, "assigning parent #%" SCIP_LONGINT_FORMAT " to node #%" SCIP_LONGINT_FORMAT " at depth %d\n",
834 parent != NULL ? SCIPnodeGetNumber(parent) : -1, SCIPnodeGetNumber(node), SCIPnodeGetDepth(node));
835
836 /* register node in the childlist of the focus (the parent) node */
838 {
839 assert(parent == NULL || SCIPnodeGetType(parent) == SCIP_NODETYPE_FOCUSNODE);
840 SCIP_CALL( treeAddChild(tree, set, node, nodeselprio) );
841 }
842
843 return SCIP_OKAY;
844}
845
846/** decreases number of children of the parent, frees it if no children are left */
847static
849 SCIP_NODE* node, /**< child node */
850 BMS_BLKMEM* blkmem, /**< block memory buffer */
851 SCIP_SET* set, /**< global SCIP settings */
852 SCIP_STAT* stat, /**< problem statistics */
853 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
854 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
855 SCIP_TREE* tree, /**< branch and bound tree */
856 SCIP_LP* lp /**< current LP data */
857 )
858{
859 SCIP_NODE* parent;
860
861 assert(node != NULL);
862 assert(blkmem != NULL);
863 assert(tree != NULL);
864
865 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",
867 node->parent != NULL ? SCIPnodeGetNumber(node->parent) : -1,
868 node->parent != NULL ? (int)SCIPnodeGetType(node->parent) : -1);
869 parent = node->parent;
870 if( parent != NULL )
871 {
872 SCIP_Bool freeParent = FALSE;
873
874 switch( SCIPnodeGetType(parent) )
875 {
877 assert(parent->active);
881 treeRemoveChild(tree, node);
882 /* don't kill the focus node at this point => freeParent = FALSE */
883 break;
885 assert(SCIPtreeProbing(tree));
886 /* probing nodes have to be freed individually => freeParent = FALSE */
887 break;
889 SCIPerrorMessage("sibling cannot be a parent node\n");
890 return SCIP_INVALIDDATA;
892 SCIPerrorMessage("child cannot be a parent node\n");
893 return SCIP_INVALIDDATA;
895 SCIPerrorMessage("leaf cannot be a parent node\n");
896 return SCIP_INVALIDDATA;
898 SCIPerrorMessage("dead-end cannot be a parent node\n");
899 return SCIP_INVALIDDATA;
901 assert(parent->data.junction.nchildren > 0);
902 parent->data.junction.nchildren--;
903 freeParent = (parent->data.junction.nchildren == 0); /* free parent if it has no more children */
904 break;
906 assert(parent->data.pseudofork != NULL);
907 assert(parent->data.pseudofork->nchildren > 0);
908 parent->data.pseudofork->nchildren--;
909 freeParent = (parent->data.pseudofork->nchildren == 0); /* free parent if it has no more children */
910 break;
912 assert(parent->data.fork != NULL);
913 assert(parent->data.fork->nchildren > 0);
914 parent->data.fork->nchildren--;
915 freeParent = (parent->data.fork->nchildren == 0); /* free parent if it has no more children */
916 break;
918 assert(parent->data.subroot != NULL);
919 assert(parent->data.subroot->nchildren > 0);
920 parent->data.subroot->nchildren--;
921 freeParent = (parent->data.subroot->nchildren == 0); /* free parent if it has no more children */
922 break;
924 /* the only possible child a refocused node can have in its refocus state is the probing root node;
925 * we don't want to free the refocused node, because we first have to convert it back to its original
926 * type (where it possibly has children) => freeParent = FALSE
927 */
929 assert(!SCIPtreeProbing(tree));
930 break;
931 default:
932 SCIPerrorMessage("unknown node type %d\n", SCIPnodeGetType(parent));
933 return SCIP_INVALIDDATA;
934 }
935
936 /* free parent if it is not on the current active path */
937 if( freeParent && !parent->active )
938 {
939 SCIP_CALL( SCIPnodeFree(&node->parent, blkmem, set, stat, eventfilter, eventqueue, tree, lp) );
940 }
941 /* update the effective root depth if not in reoptimization and active parent has children */
942 else if( !set->reopt_enable && freeParent == !parent->active )
943 {
944 SCIP_Bool singleChild = FALSE;
945 int focusdepth = SCIPtreeGetFocusDepth(tree);
946
947 assert(tree->effectiverootdepth >= 0);
948
949 while( tree->effectiverootdepth < focusdepth )
950 {
951 SCIP_NODE* effectiveroot = tree->path[tree->effectiverootdepth];
952
953 switch( SCIPnodeGetType(effectiveroot) )
954 {
956 SCIPerrorMessage("focus shallower than focus depth\n");
957 return SCIP_INVALIDDATA;
959 SCIPerrorMessage("probing shallower than focus depth\n");
960 return SCIP_INVALIDDATA;
962 SCIPerrorMessage("sibling shallower than focus depth\n");
963 return SCIP_INVALIDDATA;
965 SCIPerrorMessage("child shallower than focus depth\n");
966 return SCIP_INVALIDDATA;
968 SCIPerrorMessage("leaf on focus path\n");
969 return SCIP_INVALIDDATA;
971 SCIPerrorMessage("dead-end on focus path\n");
972 return SCIP_INVALIDDATA;
974 singleChild = (effectiveroot->data.junction.nchildren == 1);
975 break;
977 singleChild = (effectiveroot->data.pseudofork->nchildren == 1);
978 break;
980 singleChild = (effectiveroot->data.fork->nchildren == 1);
981 break;
983 singleChild = (effectiveroot->data.subroot->nchildren == 1);
984 break;
986 singleChild = FALSE;
987 break;
988 default:
989 SCIPerrorMessage("unknown node type %d\n", SCIPnodeGetType(effectiveroot));
990 return SCIP_INVALIDDATA;
991 }
992
993 if( !singleChild )
994 break;
995
996 ++tree->effectiverootdepth;
997
999 "unlinked node #%" SCIP_LONGINT_FORMAT " in depth %d -> new effective root depth: %d\n",
1001 }
1002
1003 assert(!singleChild || SCIPtreeGetEffectiveRootDepth(tree) == SCIPtreeGetFocusDepth(tree));
1004 }
1005 }
1006
1007 return SCIP_OKAY;
1008}
1009
1010/** creates a node data structure */
1011static
1013 SCIP_NODE** node, /**< pointer to node data structure */
1014 BMS_BLKMEM* blkmem, /**< block memory */
1015 SCIP_SET* set /**< global SCIP settings */
1016 )
1017{
1018 assert(node != NULL);
1019
1020 SCIP_ALLOC( BMSallocBlockMemory(blkmem, node) );
1021 (*node)->parent = NULL;
1022 (*node)->conssetchg = NULL;
1023 (*node)->domchg = NULL;
1024 (*node)->number = 0;
1025 (*node)->lowerbound = -SCIPsetInfinity(set);
1026 (*node)->estimate = -SCIPsetInfinity(set);
1027 (*node)->reoptid = 0;
1028 (*node)->reopttype = (unsigned int) SCIP_REOPTTYPE_NONE;
1029 (*node)->depth = 0;
1030 (*node)->active = FALSE;
1031 (*node)->cutoff = FALSE;
1032 (*node)->reprop = FALSE;
1033 (*node)->repropsubtreemark = 0;
1034
1035 return SCIP_OKAY;
1036}
1037
1038/** creates a child node of the focus node */
1040 SCIP_NODE** node, /**< pointer to node data structure */
1041 BMS_BLKMEM* blkmem, /**< block memory */
1042 SCIP_SET* set, /**< global SCIP settings */
1043 SCIP_STAT* stat, /**< problem statistics */
1044 SCIP_TREE* tree, /**< branch and bound tree */
1045 SCIP_Real nodeselprio, /**< node selection priority of new node */
1046 SCIP_Real estimate /**< estimate for (transformed) objective value of best feasible solution in subtree */
1047 )
1048{
1049 assert(node != NULL);
1050 assert(blkmem != NULL);
1051 assert(set != NULL);
1052 assert(stat != NULL);
1053 assert(tree != NULL);
1054 assert(SCIPtreeIsPathComplete(tree));
1055 assert(tree->pathlen == 0 || tree->path != NULL);
1056 assert((tree->pathlen == 0) == (tree->focusnode == NULL));
1057 assert(tree->focusnode == NULL || tree->focusnode == tree->path[tree->pathlen-1]);
1058 assert(tree->focusnode == NULL || SCIPnodeGetType(tree->focusnode) == SCIP_NODETYPE_FOCUSNODE);
1059
1060 stat->ncreatednodes++;
1061 stat->ncreatednodesrun++;
1062
1063 /* create the node data structure */
1064 SCIP_CALL( nodeCreate(node, blkmem, set) );
1065 (*node)->number = stat->ncreatednodesrun;
1066
1067 /* mark node to be a child node */
1068 (*node)->nodetype = SCIP_NODETYPE_CHILD; /*lint !e641*/
1069 (*node)->data.child.arraypos = -1;
1070
1071 /* make focus node the parent of the new child */
1072 SCIP_CALL( nodeAssignParent(*node, blkmem, set, tree, tree->focusnode, nodeselprio) );
1073
1074 /* update the estimate of the child */
1075 SCIPnodeSetEstimate(*node, set, estimate);
1076
1077 tree->lastbranchparentid = tree->focusnode == NULL ? -1L : SCIPnodeGetNumber(tree->focusnode);
1078
1079 /* output node creation to visualization file */
1080 SCIP_CALL( SCIPvisualNewChild(stat->visual, set, stat, *node) );
1081
1082 SCIPsetDebugMsg(set, "created child node #%" SCIP_LONGINT_FORMAT " at depth %u (prio: %g)\n", SCIPnodeGetNumber(*node), (*node)->depth, nodeselprio);
1083
1084 return SCIP_OKAY;
1085}
1086
1087/** query if focus node was already branched on */
1089 SCIP_TREE* tree, /**< branch and bound tree */
1090 SCIP_NODE* node /**< tree node, or NULL to check focus node */
1091 )
1092{
1093 node = node == NULL ? tree->focusnode : node;
1094 if( node != NULL && node->number == tree->lastbranchparentid )
1095 return TRUE;
1096
1097 return FALSE;
1098}
1099
1100/** frees node */
1102 SCIP_NODE** node, /**< node data */
1103 BMS_BLKMEM* blkmem, /**< block memory buffer */
1104 SCIP_SET* set, /**< global SCIP settings */
1105 SCIP_STAT* stat, /**< problem statistics */
1106 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
1107 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1108 SCIP_TREE* tree, /**< branch and bound tree */
1109 SCIP_LP* lp /**< current LP data */
1110 )
1111{
1112 SCIP_Bool isroot;
1113
1114 assert(node != NULL);
1115 assert(*node != NULL);
1116 assert(!(*node)->active);
1117 assert(blkmem != NULL);
1118 assert(tree != NULL);
1119
1120 SCIPsetDebugMsg(set, "free node #%" SCIP_LONGINT_FORMAT " at depth %d of type %d\n", SCIPnodeGetNumber(*node), SCIPnodeGetDepth(*node), SCIPnodeGetType(*node));
1121
1122 /* check lower bound w.r.t. debugging solution */
1124
1126 {
1127 SCIP_EVENT event;
1128
1129 /* trigger a node deletion event */
1131 SCIP_CALL( SCIPeventChgNode(&event, *node) );
1132 SCIP_CALL( SCIPeventProcess(&event, set, NULL, NULL, NULL, eventfilter) );
1133 }
1134
1135 /* inform solution debugger, that the node has been freed */
1136 SCIP_CALL( SCIPdebugRemoveNode(blkmem, set, *node) );
1137
1138 /* check, if the node to be freed is the root node */
1139 isroot = (SCIPnodeGetDepth(*node) == 0);
1140
1141 /* free nodetype specific data, and release no longer needed LPI states */
1142 switch( SCIPnodeGetType(*node) )
1143 {
1145 assert(tree->focusnode == *node);
1146 assert(!SCIPtreeProbing(tree));
1147 SCIPerrorMessage("cannot free focus node - has to be converted into a dead end first\n");
1148 return SCIP_INVALIDDATA;
1150 assert(SCIPtreeProbing(tree));
1151 assert(SCIPnodeGetDepth(tree->probingroot) <= SCIPnodeGetDepth(*node));
1152 assert(SCIPnodeGetDepth(*node) > 0);
1153 SCIP_CALL( probingnodeFree(&((*node)->data.probingnode), blkmem, lp) );
1154 break;
1156 assert((*node)->data.sibling.arraypos >= 0);
1157 assert((*node)->data.sibling.arraypos < tree->nsiblings);
1158 assert(tree->siblings[(*node)->data.sibling.arraypos] == *node);
1159 if( tree->focuslpstatefork != NULL )
1160 {
1164 }
1165 treeRemoveSibling(tree, *node);
1166 break;
1168 assert((*node)->data.child.arraypos >= 0);
1169 assert((*node)->data.child.arraypos < tree->nchildren);
1170 assert(tree->children[(*node)->data.child.arraypos] == *node);
1171 /* The children capture the LPI state at the moment, where the focus node is
1172 * converted into a junction, pseudofork, fork, or subroot, and a new node is focused.
1173 * At the same time, they become siblings or leaves, such that freeing a child
1174 * of the focus node doesn't require to release the LPI state;
1175 * we don't need to call treeRemoveChild(), because this is done in nodeReleaseParent()
1176 */
1177 break;
1178 case SCIP_NODETYPE_LEAF:
1179 if( (*node)->data.leaf.lpstatefork != NULL )
1180 {
1181 SCIP_CALL( SCIPnodeReleaseLPIState((*node)->data.leaf.lpstatefork, blkmem, lp) );
1182 }
1183 break;
1186 break;
1188 SCIP_CALL( pseudoforkFree(&((*node)->data.pseudofork), blkmem, set, lp) );
1189 break;
1190 case SCIP_NODETYPE_FORK:
1191
1192 /* release special root LPI state capture which is used to keep the root LPI state over the whole solving
1193 * process
1194 */
1195 if( isroot )
1196 {
1197 SCIP_CALL( SCIPnodeReleaseLPIState(*node, blkmem, lp) );
1198 }
1199 SCIP_CALL( forkFree(&((*node)->data.fork), blkmem, set, lp) );
1200 break;
1202 SCIP_CALL( subrootFree(&((*node)->data.subroot), blkmem, set, lp) );
1203 break;
1205 SCIPerrorMessage("cannot free node as long it is refocused\n");
1206 return SCIP_INVALIDDATA;
1207 default:
1208 SCIPerrorMessage("unknown node type %d\n", SCIPnodeGetType(*node));
1209 return SCIP_INVALIDDATA;
1210 }
1211
1212 /* free common data */
1213 SCIP_CALL( SCIPconssetchgFree(&(*node)->conssetchg, blkmem, set) );
1214 SCIP_CALL( SCIPdomchgFree(&(*node)->domchg, blkmem, set, eventqueue, lp) );
1215 SCIP_CALL( nodeReleaseParent(*node, blkmem, set, stat, eventfilter, eventqueue, tree, lp) );
1216
1217 /* check, if the node is the current probing root */
1218 if( *node == tree->probingroot )
1219 {
1221 tree->probingroot = NULL;
1222 }
1223
1224 BMSfreeBlockMemory(blkmem, node);
1225
1226 /* delete the tree's root node pointer, if the freed node was the root */
1227 if( isroot )
1228 tree->root = NULL;
1229
1230 return SCIP_OKAY;
1231}
1232
1233/** cuts off node and whole sub tree from branch and bound tree */
1235 SCIP_NODE* node, /**< node that should be cut off */
1236 SCIP_SET* set, /**< global SCIP settings */
1237 SCIP_STAT* stat, /**< problem statistics */
1238 SCIP_TREE* tree, /**< branch and bound tree */
1239 SCIP_PROB* transprob, /**< transformed problem after presolve */
1240 SCIP_PROB* origprob, /**< original problem */
1241 SCIP_REOPT* reopt, /**< reoptimization data structure */
1242 SCIP_LP* lp, /**< current LP */
1243 BMS_BLKMEM* blkmem /**< block memory */
1244 )
1245{
1246 SCIP_Real oldbound;
1247
1248 assert(node != NULL);
1249 assert(set != NULL);
1250 assert(stat != NULL);
1251 assert(tree != NULL);
1252
1253 if( set->reopt_enable )
1254 {
1255 assert(reopt != NULL);
1256 /* check if the node should be stored for reoptimization */
1258 tree->root == node, tree->focusnode == node, node->lowerbound, tree->effectiverootdepth) );
1259 }
1260
1261 oldbound = node->lowerbound;
1262 node->cutoff = TRUE;
1264 node->estimate = SCIPsetInfinity(set);
1265 if( node->active )
1266 tree->cutoffdepth = MIN(tree->cutoffdepth, (int)node->depth);
1267
1268 /* update primal integral */
1269 if( node->depth == 0 )
1270 {
1272 if( set->misc_calcintegral )
1274 }
1275 else if( set->misc_calcintegral && SCIPsetIsEQ(set, oldbound, stat->lastlowerbound) )
1276 {
1277 SCIP_Real lowerbound;
1278 lowerbound = SCIPtreeGetLowerbound(tree, set);
1279
1280 /* updating the primal integral is only necessary if dual bound has increased since last evaluation */
1281 if( lowerbound > stat->lastlowerbound )
1283 }
1284
1285 SCIPvisualCutoffNode(stat->visual, set, stat, node, TRUE);
1286
1287 SCIPsetDebugMsg(set, "cutting off %s node #%" SCIP_LONGINT_FORMAT " at depth %d (cutoffdepth: %d)\n",
1288 node->active ? "active" : "inactive", SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), tree->cutoffdepth);
1289
1290 return SCIP_OKAY;
1291}
1292
1293/** marks node, that propagation should be applied again the next time, a node of its subtree is focused */
1295 SCIP_NODE* node, /**< node that should be propagated again */
1296 SCIP_SET* set, /**< global SCIP settings */
1297 SCIP_STAT* stat, /**< problem statistics */
1298 SCIP_TREE* tree /**< branch and bound tree */
1299 )
1300{
1301 assert(node != NULL);
1302 assert(set != NULL);
1303 assert(stat != NULL);
1304 assert(tree != NULL);
1305
1306 if( !node->reprop )
1307 {
1308 node->reprop = TRUE;
1309 if( node->active )
1310 tree->repropdepth = MIN(tree->repropdepth, (int)node->depth);
1311
1312 SCIPvisualMarkedRepropagateNode(stat->visual, stat, node);
1313
1314 SCIPsetDebugMsg(set, "marked %s node #%" SCIP_LONGINT_FORMAT " at depth %d to be propagated again (repropdepth: %d)\n",
1315 node->active ? "active" : "inactive", SCIPnodeGetNumber(node), SCIPnodeGetDepth(node), tree->repropdepth);
1316 }
1317}
1318
1319/** marks node, that it is completely propagated in the current repropagation subtree level */
1321 SCIP_NODE* node, /**< node that should be marked to be propagated */
1322 SCIP_TREE* tree /**< branch and bound tree */
1323 )
1324{
1325 assert(node != NULL);
1326 assert(tree != NULL);
1327
1328 if( node->parent != NULL )
1329 node->repropsubtreemark = node->parent->repropsubtreemark; /*lint !e732*/
1330 node->reprop = FALSE;
1331
1332 /* if the node was the highest repropagation node in the path, update the repropdepth in the tree data */
1333 if( node->active && node->depth == tree->repropdepth )
1334 {
1335 do
1336 {
1337 assert(tree->repropdepth < tree->pathlen);
1338 assert(tree->path[tree->repropdepth]->active);
1339 assert(!tree->path[tree->repropdepth]->reprop);
1340 tree->repropdepth++;
1341 }
1342 while( tree->repropdepth < tree->pathlen && !tree->path[tree->repropdepth]->reprop );
1343 if( tree->repropdepth == tree->pathlen )
1344 tree->repropdepth = INT_MAX;
1345 }
1346}
1347
1348/** moves the subtree repropagation counter to the next value */
1349static
1351 SCIP_TREE* tree /**< branch and bound tree */
1352 )
1353{
1354 assert(tree != NULL);
1355
1356 tree->repropsubtreecount++;
1357 tree->repropsubtreecount %= (MAXREPROPMARK+1);
1358}
1359
1360/** applies propagation on the node, that was marked to be propagated again */
1361static
1363 SCIP_NODE* node, /**< node to apply propagation on */
1364 BMS_BLKMEM* blkmem, /**< block memory buffers */
1365 SCIP_SET* set, /**< global SCIP settings */
1366 SCIP_STAT* stat, /**< dynamic problem statistics */
1367 SCIP_PROB* transprob, /**< transformed problem */
1368 SCIP_PROB* origprob, /**< original problem */
1369 SCIP_PRIMAL* primal, /**< primal data */
1370 SCIP_TREE* tree, /**< branch and bound tree */
1371 SCIP_REOPT* reopt, /**< reoptimization data structure */
1372 SCIP_LP* lp, /**< current LP data */
1373 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1374 SCIP_CONFLICT* conflict, /**< conflict analysis data */
1375 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
1376 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1377 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1378 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
1379 )
1380{
1381 SCIP_NODETYPE oldtype;
1382 SCIP_NODE* oldfocusnode;
1383 SCIP_NODE* oldfocuslpfork;
1384 SCIP_NODE* oldfocuslpstatefork;
1385 SCIP_NODE* oldfocussubroot;
1386 SCIP_Longint oldfocuslpstateforklpcount;
1387 int oldnchildren;
1388 int oldnsiblings;
1389 SCIP_Bool oldfocusnodehaslp;
1390 SCIP_Longint oldnboundchgs;
1391 SCIP_Bool initialreprop;
1392 SCIP_Bool clockisrunning;
1393
1394 assert(node != NULL);
1400 assert(node->active);
1401 assert(node->reprop || node->repropsubtreemark != node->parent->repropsubtreemark);
1402 assert(stat != NULL);
1403 assert(tree != NULL);
1404 assert(SCIPeventqueueIsDelayed(eventqueue));
1405 assert(cutoff != NULL);
1406
1407 SCIPsetDebugMsg(set, "propagating again node #%" SCIP_LONGINT_FORMAT " at depth %d\n", SCIPnodeGetNumber(node), SCIPnodeGetDepth(node));
1408 initialreprop = node->reprop;
1409
1410 SCIPvisualRepropagatedNode(stat->visual, stat, node);
1411
1412 /* process the delayed events in order to flush the problem changes */
1413 SCIP_CALL( SCIPeventqueueProcess(eventqueue, blkmem, set, primal, lp, branchcand, eventfilter) );
1414
1415 /* stop node activation timer */
1416 clockisrunning = SCIPclockIsRunning(stat->nodeactivationtime);
1417 if( clockisrunning )
1419
1420 /* mark the node refocused and temporarily install it as focus node */
1421 oldtype = (SCIP_NODETYPE)node->nodetype;
1422 oldfocusnode = tree->focusnode;
1423 oldfocuslpfork = tree->focuslpfork;
1424 oldfocuslpstatefork = tree->focuslpstatefork;
1425 oldfocussubroot = tree->focussubroot;
1426 oldfocuslpstateforklpcount = tree->focuslpstateforklpcount;
1427 oldnchildren = tree->nchildren;
1428 oldnsiblings = tree->nsiblings;
1429 oldfocusnodehaslp = tree->focusnodehaslp;
1430 node->nodetype = SCIP_NODETYPE_REFOCUSNODE; /*lint !e641*/
1431 tree->focusnode = node;
1432 tree->focuslpfork = NULL;
1433 tree->focuslpstatefork = NULL;
1434 tree->focussubroot = NULL;
1435 tree->focuslpstateforklpcount = -1;
1436 tree->nchildren = 0;
1437 tree->nsiblings = 0;
1438 tree->focusnodehaslp = FALSE;
1439
1440 /* propagate the domains again */
1441 oldnboundchgs = stat->nboundchgs;
1442 SCIP_CALL( SCIPpropagateDomains(blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
1443 eventqueue, conflict, cliquetable, SCIPnodeGetDepth(node), 0, SCIP_PROPTIMING_ALWAYS, cutoff) );
1444 assert(!node->reprop || *cutoff);
1445 assert(node->parent == NULL || node->repropsubtreemark == node->parent->repropsubtreemark);
1447 assert(tree->focusnode == node);
1448 assert(tree->focuslpfork == NULL);
1449 assert(tree->focuslpstatefork == NULL);
1450 assert(tree->focussubroot == NULL);
1451 assert(tree->focuslpstateforklpcount == -1);
1452 assert(tree->nchildren == 0);
1453 assert(tree->nsiblings == 0);
1454 assert(tree->focusnodehaslp == FALSE);
1455 assert(stat->nboundchgs >= oldnboundchgs);
1456 stat->nreprops++;
1457 stat->nrepropboundchgs += stat->nboundchgs - oldnboundchgs;
1458 if( *cutoff )
1459 stat->nrepropcutoffs++;
1460
1461 SCIPsetDebugMsg(set, "repropagation %" SCIP_LONGINT_FORMAT " at depth %u changed %" SCIP_LONGINT_FORMAT " bounds (total reprop bound changes: %" SCIP_LONGINT_FORMAT "), cutoff: %u\n",
1462 stat->nreprops, node->depth, stat->nboundchgs - oldnboundchgs, stat->nrepropboundchgs, *cutoff);
1463
1464 /* if a propagation marked with the reprop flag was successful, we want to repropagate the whole subtree */
1465 /**@todo because repropsubtree is only a bit flag, we cannot mark a whole subtree a second time for
1466 * repropagation; use a (small) part of the node's bits to be able to store larger numbers,
1467 * and update tree->repropsubtreelevel with this number
1468 */
1469 if( initialreprop && !(*cutoff) && stat->nboundchgs > oldnboundchgs )
1470 {
1472 node->repropsubtreemark = tree->repropsubtreecount; /*lint !e732*/
1473 SCIPsetDebugMsg(set, "initial repropagation at depth %u changed %" SCIP_LONGINT_FORMAT " bounds -> repropagating subtree (new mark: %d)\n",
1474 node->depth, stat->nboundchgs - oldnboundchgs, tree->repropsubtreecount);
1475 assert((int)(node->repropsubtreemark) == tree->repropsubtreecount); /* bitfield must be large enough */
1476 }
1477
1478 /* reset the node's type and reinstall the old focus node */
1479 node->nodetype = oldtype; /*lint !e641*/
1480 tree->focusnode = oldfocusnode;
1481 tree->focuslpfork = oldfocuslpfork;
1482 tree->focuslpstatefork = oldfocuslpstatefork;
1483 tree->focussubroot = oldfocussubroot;
1484 tree->focuslpstateforklpcount = oldfocuslpstateforklpcount;
1485 tree->nchildren = oldnchildren;
1486 tree->nsiblings = oldnsiblings;
1487 tree->focusnodehaslp = oldfocusnodehaslp;
1488
1489 /* make the domain change data static again to save memory */
1491 {
1492 SCIP_CALL( SCIPdomchgMakeStatic(&node->domchg, blkmem, set, eventqueue, lp) );
1493 }
1494
1495 /* start node activation timer again */
1496 if( clockisrunning )
1498
1499 /* delay events in path switching */
1500 SCIP_CALL( SCIPeventqueueDelay(eventqueue) );
1501
1502 /* mark the node to be cut off if a cutoff was detected */
1503 if( *cutoff )
1504 {
1505 SCIP_CALL( SCIPnodeCutoff(node, set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
1506 }
1507
1508 return SCIP_OKAY;
1509}
1510
1511/** informs node, that it is now on the active path and applies any domain and constraint set changes */
1512static
1514 SCIP_NODE* node, /**< node to activate */
1515 BMS_BLKMEM* blkmem, /**< block memory buffers */
1516 SCIP_SET* set, /**< global SCIP settings */
1517 SCIP_STAT* stat, /**< problem statistics */
1518 SCIP_PROB* transprob, /**< transformed problem */
1519 SCIP_PROB* origprob, /**< original problem */
1520 SCIP_PRIMAL* primal, /**< primal data */
1521 SCIP_TREE* tree, /**< branch and bound tree */
1522 SCIP_REOPT* reopt, /**< reotimization data structure */
1523 SCIP_LP* lp, /**< current LP data */
1524 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1525 SCIP_CONFLICT* conflict, /**< conflict analysis data */
1526 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
1527 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1528 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1529 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
1530 )
1531{
1532 assert(node != NULL);
1533 assert(!node->active);
1534 assert(stat != NULL);
1535 assert(tree != NULL);
1536 assert(!SCIPtreeProbing(tree));
1537 assert(cutoff != NULL);
1538
1539 SCIPsetDebugMsg(set, "activate node #%" SCIP_LONGINT_FORMAT " at depth %d of type %d (reprop subtree mark: %u)\n",
1541
1542 /* apply domain and constraint set changes */
1543 SCIP_CALL( SCIPconssetchgApply(node->conssetchg, blkmem, set, stat, (int) node->depth,
1545 SCIP_CALL( SCIPdomchgApply(node->domchg, blkmem, set, stat, lp, branchcand, eventqueue, (int) node->depth, cutoff) );
1546
1547 /* mark node active */
1548 node->active = TRUE;
1549 stat->nactivatednodes++;
1550
1551 /* check if the domain change produced a cutoff */
1552 if( *cutoff )
1553 {
1554 /* try to repropagate the node to see, if the propagation also leads to a conflict and a conflict constraint
1555 * could be generated; if propagation conflict analysis is turned off, repropagating the node makes no
1556 * sense, since it is already cut off
1557 */
1558 node->reprop = set->conf_enable && set->conf_useprop;
1559
1560 /* mark the node to be cut off */
1561 SCIP_CALL( SCIPnodeCutoff(node, set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
1562 }
1563
1564 /* propagate node again, if the reprop flag is set; in the new focus node, no repropagation is necessary, because
1565 * the focus node is propagated anyways
1566 */
1568 && (node->reprop || (node->parent != NULL && node->repropsubtreemark != node->parent->repropsubtreemark)) )
1569 {
1570 SCIP_Bool propcutoff;
1571
1572 SCIP_CALL( nodeRepropagate(node, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, conflict,
1573 eventfilter, eventqueue, cliquetable, &propcutoff) );
1574 *cutoff = *cutoff || propcutoff;
1575 }
1576
1577 return SCIP_OKAY;
1578}
1579
1580/** informs node, that it is no longer on the active path and undoes any domain and constraint set changes */
1581static
1583 SCIP_NODE* node, /**< node to deactivate */
1584 BMS_BLKMEM* blkmem, /**< block memory buffers */
1585 SCIP_SET* set, /**< global SCIP settings */
1586 SCIP_STAT* stat, /**< problem statistics */
1587 SCIP_TREE* tree, /**< branch and bound tree */
1588 SCIP_LP* lp, /**< current LP data */
1589 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1590 SCIP_EVENTQUEUE* eventqueue /**< event queue */
1591 )
1592{
1593 assert(node != NULL);
1594 assert(node->active);
1595 assert(tree != NULL);
1597
1598 SCIPsetDebugMsg(set, "deactivate node #%" SCIP_LONGINT_FORMAT " at depth %d of type %d (reprop subtree mark: %u)\n",
1600
1601 /* undo domain and constraint set changes */
1602 SCIP_CALL( SCIPdomchgUndo(node->domchg, blkmem, set, stat, lp, branchcand, eventqueue) );
1603 SCIP_CALL( SCIPconssetchgUndo(node->conssetchg, blkmem, set, stat) );
1604
1605 /* mark node inactive */
1606 node->active = FALSE;
1607
1608 /* count number of deactivated nodes (ignoring probing switches) */
1609 if( !SCIPtreeProbing(tree) )
1610 stat->ndeactivatednodes++;
1611
1612 return SCIP_OKAY;
1613}
1614
1615/** adds constraint locally to the node and captures it; activates constraint, if node is active;
1616 * if a local constraint is added to the root node, it is automatically upgraded into a global constraint
1617 */
1619 SCIP_NODE* node, /**< node to add constraint to */
1620 BMS_BLKMEM* blkmem, /**< block memory */
1621 SCIP_SET* set, /**< global SCIP settings */
1622 SCIP_STAT* stat, /**< problem statistics */
1623 SCIP_TREE* tree, /**< branch and bound tree */
1624 SCIP_CONS* cons /**< constraint to add */
1625 )
1626{
1627 assert(node != NULL);
1628 assert(cons != NULL);
1629 assert(cons->validdepth <= SCIPnodeGetDepth(node));
1630 assert(tree != NULL);
1631 assert(tree->effectiverootdepth >= 0);
1632 assert(tree->root != NULL);
1633 assert(SCIPconsIsGlobal(cons) || SCIPnodeGetDepth(node) > tree->effectiverootdepth);
1634
1635#ifndef NDEBUG
1636 /* check if we add this constraint to the same scip, where we create the constraint */
1637 if( cons->scip != set->scip )
1638 {
1639 SCIPerrorMessage("try to add a constraint of another scip instance\n");
1640 return SCIP_INVALIDDATA;
1641 }
1642#endif
1643
1644 /* add constraint addition to the node's constraint set change data, and activate constraint if node is active */
1645 SCIP_CALL( SCIPconssetchgAddAddedCons(&node->conssetchg, blkmem, set, stat, cons, (int) node->depth,
1646 (SCIPnodeGetType(node) == SCIP_NODETYPE_FOCUSNODE), node->active) );
1647 assert(node->conssetchg != NULL);
1648 assert(node->conssetchg->addedconss != NULL);
1649 assert(!node->active || SCIPconsIsActive(cons));
1650
1651 /* if the constraint is added to an active node which is not a probing node, increment the corresponding counter */
1652 if( node->active && SCIPnodeGetType(node) != SCIP_NODETYPE_PROBINGNODE )
1653 stat->nactiveconssadded++;
1654
1655 return SCIP_OKAY;
1656}
1657
1658/** locally deletes constraint at the given node by disabling its separation, enforcing, and propagation capabilities
1659 * at the node; captures constraint; disables constraint, if node is active
1660 */
1662 SCIP_NODE* node, /**< node to add constraint to */
1663 BMS_BLKMEM* blkmem, /**< block memory */
1664 SCIP_SET* set, /**< global SCIP settings */
1665 SCIP_STAT* stat, /**< problem statistics */
1666 SCIP_TREE* tree, /**< branch and bound tree */
1667 SCIP_CONS* cons /**< constraint to locally delete */
1668 )
1669{
1670 assert(node != NULL);
1671 assert(tree != NULL);
1672 assert(cons != NULL);
1673
1674 SCIPsetDebugMsg(set, "disabling constraint <%s> at node at depth %u\n", cons->name, node->depth);
1675
1676 /* add constraint disabling to the node's constraint set change data */
1677 SCIP_CALL( SCIPconssetchgAddDisabledCons(&node->conssetchg, blkmem, set, cons) );
1678 assert(node->conssetchg != NULL);
1679 assert(node->conssetchg->disabledconss != NULL);
1680
1681 /* disable constraint, if node is active */
1682 if( node->active && cons->enabled && !cons->updatedisable )
1683 {
1684 SCIP_CALL( SCIPconsDisable(cons, set, stat) );
1685 }
1686
1687 return SCIP_OKAY;
1688}
1689
1690/** returns all constraints added to a given node */
1692 SCIP_NODE* node, /**< node */
1693 SCIP_CONS** addedconss, /**< array to store the constraints */
1694 int* naddedconss, /**< number of added constraints */
1695 int addedconsssize /**< size of the constraint array */
1696 )
1697{
1698 int cons;
1699
1700 assert(node != NULL );
1701 assert(node->conssetchg != NULL);
1702 assert(node->conssetchg->addedconss != NULL);
1703 assert(node->conssetchg->naddedconss >= 1);
1704
1705 *naddedconss = node->conssetchg->naddedconss;
1706
1707 /* check the size and return if the array is not large enough */
1708 if( addedconsssize < *naddedconss )
1709 return;
1710
1711 /* fill the array */
1712 for( cons = 0; cons < *naddedconss; cons++ )
1713 {
1714 addedconss[cons] = node->conssetchg->addedconss[cons];
1715 }
1716
1717 return;
1718}
1719
1720/** returns the number of added constraints to the given node */
1722 SCIP_NODE* node /**< node */
1723 )
1724{
1725 assert(node != NULL);
1726
1727 if( node->conssetchg == NULL )
1728 return 0;
1729 else
1730 return node->conssetchg->naddedconss;
1731}
1732
1733/** adds the given bound change to the list of pending bound changes */
1734static
1736 SCIP_TREE* tree, /**< branch and bound tree */
1737 SCIP_SET* set, /**< global SCIP settings */
1738 SCIP_NODE* node, /**< node to add bound change to */
1739 SCIP_VAR* var, /**< variable to change the bounds for */
1740 SCIP_Real newbound, /**< new value for bound */
1741 SCIP_BOUNDTYPE boundtype, /**< type of bound: lower or upper bound */
1742 SCIP_CONS* infercons, /**< constraint that deduced the bound change, or NULL */
1743 SCIP_PROP* inferprop, /**< propagator that deduced the bound change, or NULL */
1744 int inferinfo, /**< user information for inference to help resolving the conflict */
1745 SCIP_Bool probingchange /**< is the bound change a temporary setting due to probing? */
1746 )
1747{
1748 assert(tree != NULL);
1749
1750 /* make sure that enough memory is allocated for the pendingbdchgs array */
1752
1753 /* capture the variable */
1754 SCIPvarCapture(var);
1755
1756 /* add the bound change to the pending list */
1757 tree->pendingbdchgs[tree->npendingbdchgs].node = node;
1758 tree->pendingbdchgs[tree->npendingbdchgs].var = var;
1759 tree->pendingbdchgs[tree->npendingbdchgs].newbound = newbound;
1760 tree->pendingbdchgs[tree->npendingbdchgs].boundtype = boundtype;
1761 tree->pendingbdchgs[tree->npendingbdchgs].infercons = infercons;
1762 tree->pendingbdchgs[tree->npendingbdchgs].inferprop = inferprop;
1763 tree->pendingbdchgs[tree->npendingbdchgs].inferinfo = inferinfo;
1764 tree->pendingbdchgs[tree->npendingbdchgs].probingchange = probingchange;
1765 tree->npendingbdchgs++;
1766
1767 /* check global pending boundchanges against debug solution */
1768 if( node->depth == 0 )
1769 {
1770#ifndef NDEBUG
1771 SCIP_Real bound = newbound;
1772
1773 /* get bound adjusted for integrality(, this should already be done) */
1774 SCIPvarAdjustBd(var, set, boundtype, &bound);
1775
1776 if( boundtype == SCIP_BOUNDTYPE_LOWER )
1777 {
1778 /* check that the bound is feasible */
1779 if( bound > SCIPvarGetUbGlobal(var) )
1780 {
1781 /* due to numerics we only want to be feasible in feasibility tolerance */
1784 }
1785 }
1786 else
1787 {
1788 assert(boundtype == SCIP_BOUNDTYPE_UPPER);
1789
1790 /* check that the bound is feasible */
1791 if( bound < SCIPvarGetLbGlobal(var) )
1792 {
1793 /* due to numerics we only want to be feasible in feasibility tolerance */
1796 }
1797 }
1798 /* check that the given bound was already adjusted for integrality */
1799 assert(SCIPsetIsEQ(set, newbound, bound));
1800#endif
1801 if( boundtype == SCIP_BOUNDTYPE_LOWER )
1802 {
1803 /* check bound on debugging solution */
1804 SCIP_CALL( SCIPdebugCheckLbGlobal(set->scip, var, newbound) ); /*lint !e506 !e774*/
1805 }
1806 else
1807 {
1808 assert(boundtype == SCIP_BOUNDTYPE_UPPER);
1809
1810 /* check bound on debugging solution */
1811 SCIP_CALL( SCIPdebugCheckUbGlobal(set->scip, var, newbound) ); /*lint !e506 !e774*/
1812 }
1813 }
1814
1815 return SCIP_OKAY;
1816}
1817
1818/** adds bound change with inference information to focus node, child of focus node, or probing node;
1819 * if possible, adjusts bound to integral value;
1820 * at most one of infercons and inferprop may be non-NULL
1821 */
1823 SCIP_NODE* node, /**< node to add bound change to */
1824 BMS_BLKMEM* blkmem, /**< block memory */
1825 SCIP_SET* set, /**< global SCIP settings */
1826 SCIP_STAT* stat, /**< problem statistics */
1827 SCIP_PROB* transprob, /**< transformed problem after presolve */
1828 SCIP_PROB* origprob, /**< original problem */
1829 SCIP_TREE* tree, /**< branch and bound tree */
1830 SCIP_REOPT* reopt, /**< reoptimization data structure */
1831 SCIP_LP* lp, /**< current LP data */
1832 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1833 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1834 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1835 SCIP_VAR* var, /**< variable to change the bounds for */
1836 SCIP_Real newbound, /**< new value for bound */
1837 SCIP_BOUNDTYPE boundtype, /**< type of bound: lower or upper bound */
1838 SCIP_CONS* infercons, /**< constraint that deduced the bound change, or NULL */
1839 SCIP_PROP* inferprop, /**< propagator that deduced the bound change, or NULL */
1840 int inferinfo, /**< user information for inference to help resolving the conflict */
1841 SCIP_Bool probingchange /**< is the bound change a temporary setting due to probing? */
1842 )
1843{
1844 SCIP_VAR* infervar;
1845 SCIP_BOUNDTYPE inferboundtype;
1846 SCIP_Real oldlb;
1847 SCIP_Real oldub;
1848 SCIP_Real oldbound;
1849 SCIP_Bool useglobal;
1850
1851 useglobal = (int) node->depth <= tree->effectiverootdepth;
1852 if( useglobal )
1853 {
1854 oldlb = SCIPvarGetLbGlobal(var);
1855 oldub = SCIPvarGetUbGlobal(var);
1856 }
1857 else
1858 {
1859 oldlb = SCIPvarGetLbLocal(var);
1860 oldub = SCIPvarGetUbLocal(var);
1861 }
1862
1863 assert(node != NULL);
1868 || node->depth == 0);
1869 assert(set != NULL);
1870 assert(tree != NULL);
1871 assert(tree->effectiverootdepth >= 0);
1872 assert(tree->root != NULL);
1873 assert(var != NULL);
1874 assert(node->active || (infercons == NULL && inferprop == NULL));
1875 assert((SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_PROBINGNODE || !probingchange);
1876 assert((boundtype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsGT(set, newbound, oldlb))
1877 || (boundtype == SCIP_BOUNDTYPE_LOWER && newbound > oldlb && newbound * oldlb <= 0.0)
1878 || (boundtype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsLT(set, newbound, oldub))
1879 || (boundtype == SCIP_BOUNDTYPE_UPPER && newbound < oldub && newbound * oldub <= 0.0));
1880
1881 SCIPsetDebugMsg(set, "adding boundchange at node %" SCIP_LONGINT_FORMAT " at depth %u to variable <%s>: old bounds=[%g,%g], new %s bound: %g (infer%s=<%s>, inferinfo=%d)\n",
1882 node->number, node->depth, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
1883 boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper", newbound, infercons != NULL ? "cons" : "prop",
1884 infercons != NULL ? SCIPconsGetName(infercons) : (inferprop != NULL ? SCIPpropGetName(inferprop) : "-"), inferinfo);
1885
1886 /* remember variable as inference variable, and get corresponding active variable, bound and bound type */
1887 infervar = var;
1888 inferboundtype = boundtype;
1889
1890 SCIP_CALL( SCIPvarGetProbvarBound(&var, &newbound, &boundtype) );
1891
1893 {
1894 SCIPerrorMessage("cannot change bounds of multi-aggregated variable <%s>\n", SCIPvarGetName(var));
1895 SCIPABORT();
1896 return SCIP_INVALIDDATA; /*lint !e527*/
1897 }
1899
1900 /* the variable may have changed, make sure we have the correct bounds */
1901 if( useglobal )
1902 {
1903 oldlb = SCIPvarGetLbGlobal(var);
1904 oldub = SCIPvarGetUbGlobal(var);
1905 }
1906 else
1907 {
1908 oldlb = SCIPvarGetLbLocal(var);
1909 oldub = SCIPvarGetUbLocal(var);
1910 }
1911 assert(SCIPsetIsLE(set, oldlb, oldub));
1912
1913 if( boundtype == SCIP_BOUNDTYPE_LOWER )
1914 {
1915 /* adjust lower bound w.r.t. to integrality */
1916 SCIPvarAdjustLb(var, set, &newbound);
1917 assert(SCIPsetIsFeasLE(set, newbound, oldub));
1918 oldbound = oldlb;
1919 newbound = MIN(newbound, oldub);
1920
1921 if ( set->stage == SCIP_STAGE_SOLVING && SCIPsetIsInfinity(set, newbound) )
1922 {
1923 SCIPerrorMessage("cannot change lower bound of variable <%s> to infinity.\n", SCIPvarGetName(var));
1924 SCIPABORT();
1925 return SCIP_INVALIDDATA; /*lint !e527*/
1926 }
1927 }
1928 else
1929 {
1930 assert(boundtype == SCIP_BOUNDTYPE_UPPER);
1931
1932 /* adjust the new upper bound */
1933 SCIPvarAdjustUb(var, set, &newbound);
1934 assert(SCIPsetIsFeasGE(set, newbound, oldlb));
1935 oldbound = oldub;
1936 newbound = MAX(newbound, oldlb);
1937
1938 if ( set->stage == SCIP_STAGE_SOLVING && SCIPsetIsInfinity(set, -newbound) )
1939 {
1940 SCIPerrorMessage("cannot change upper bound of variable <%s> to minus infinity.\n", SCIPvarGetName(var));
1941 SCIPABORT();
1942 return SCIP_INVALIDDATA; /*lint !e527*/
1943 }
1944 }
1945
1946 /* after switching to the active variable, the bounds might become redundant
1947 * if this happens, ignore the bound change
1948 */
1949 if( (boundtype == SCIP_BOUNDTYPE_LOWER && !SCIPsetIsGT(set, newbound, oldlb))
1950 || (boundtype == SCIP_BOUNDTYPE_UPPER && !SCIPsetIsLT(set, newbound, oldub)) )
1951 return SCIP_OKAY;
1952
1953 SCIPsetDebugMsg(set, " -> transformed to active variable <%s>: old bounds=[%g,%g], new %s bound: %g, obj: %g\n",
1954 SCIPvarGetName(var), oldlb, oldub, boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper", newbound,
1955 SCIPvarGetObj(var));
1956
1957 /* if the bound change takes place at an active node but is conflicting with the current local bounds,
1958 * we cannot apply it immediately because this would introduce inconsistencies to the bound change data structures
1959 * in the tree and to the bound change information data in the variable;
1960 * instead we have to remember the bound change as a pending bound change and mark the affected nodes on the active
1961 * path to be infeasible
1962 */
1963 if( node->active )
1964 {
1965 int conflictingdepth;
1966
1967 conflictingdepth = SCIPvarGetConflictingBdchgDepth(var, set, boundtype, newbound);
1968
1969 if( conflictingdepth >= 0 )
1970 {
1971 /* 0 would mean the bound change conflicts with a global bound */
1972 assert(conflictingdepth > 0);
1973 assert(conflictingdepth < tree->pathlen);
1974
1975 SCIPsetDebugMsg(set, " -> bound change <%s> %s %g violates current local bounds [%g,%g] since depth %d: remember for later application\n",
1976 SCIPvarGetName(var), boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", newbound,
1977 SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), conflictingdepth);
1978
1979 /* remember the pending bound change */
1980 SCIP_CALL( treeAddPendingBdchg(tree, set, node, var, newbound, boundtype, infercons, inferprop, inferinfo,
1981 probingchange) );
1982
1983 /* mark the node with the conflicting bound change to be cut off */
1984 SCIP_CALL( SCIPnodeCutoff(tree->path[conflictingdepth], set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
1985
1986 return SCIP_OKAY;
1987 }
1988 }
1989
1990 SCIPstatIncrement(stat, set, nboundchgs);
1991
1992 /* if we are in probing mode we have to additionally count the bound changes for the probing statistic */
1993 if( tree->probingroot != NULL )
1994 SCIPstatIncrement(stat, set, nprobboundchgs);
1995
1996 /* if the node is the root node: change local and global bound immediately */
1997 if( SCIPnodeGetDepth(node) <= tree->effectiverootdepth )
1998 {
1999 assert(node->active || tree->focusnode == NULL );
2001 assert(!probingchange);
2002
2003 SCIPsetDebugMsg(set, " -> bound change in root node: perform global bound change\n");
2004 SCIP_CALL( SCIPvarChgBdGlobal(var, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, newbound, boundtype) );
2005
2006 if( set->stage == SCIP_STAGE_SOLVING )
2007 {
2008 /* the root should be repropagated due to the bound change */
2009 SCIPnodePropagateAgain(tree->root, set, stat, tree);
2010 SCIPsetDebugMsg(set, "marked root node to be repropagated due to global bound change <%s>:[%g,%g] -> [%g,%g] found in depth %u\n",
2011 SCIPvarGetName(var), oldlb, oldub, boundtype == SCIP_BOUNDTYPE_LOWER ? newbound : oldlb,
2012 boundtype == SCIP_BOUNDTYPE_LOWER ? oldub : newbound, node->depth);
2013 }
2014
2015 return SCIP_OKAY;
2016 }
2017
2018 /* if the node is a child, or the bound is a temporary probing bound
2019 * - the bound change is a branching decision
2020 * - the child's lower bound can be updated due to the changed pseudo solution
2021 * otherwise:
2022 * - the bound change is an inference
2023 */
2024 if( SCIPnodeGetType(node) == SCIP_NODETYPE_CHILD || probingchange )
2025 {
2026 SCIP_Real newpseudoobjval;
2027 SCIP_Real lpsolval;
2028
2029 assert(!node->active || SCIPnodeGetType(node) == SCIP_NODETYPE_PROBINGNODE);
2030
2031 /* get the solution value of variable in last solved LP on the active path:
2032 * - if the LP was solved at the current node, the LP values of the columns are valid
2033 * - if the last solved LP was the one in the current lpstatefork, the LP value in the columns are still valid
2034 * - otherwise, the LP values are invalid
2035 */
2036 if( SCIPtreeHasCurrentNodeLP(tree)
2038 {
2039 lpsolval = SCIPvarGetLPSol(var);
2040 }
2041 else
2042 lpsolval = SCIP_INVALID;
2043
2044 /* remember the bound change as branching decision (infervar/infercons/inferprop are not important: use NULL) */
2045 SCIP_CALL( SCIPdomchgAddBoundchg(&node->domchg, blkmem, set, var, newbound, boundtype, SCIP_BOUNDCHGTYPE_BRANCHING,
2046 lpsolval, NULL, NULL, NULL, 0, inferboundtype) );
2047
2048 /* update the child's lower bound */
2049 if( set->misc_exactsolve )
2050 newpseudoobjval = SCIPlpGetModifiedProvedPseudoObjval(lp, set, var, oldbound, newbound, boundtype);
2051 else
2052 newpseudoobjval = SCIPlpGetModifiedPseudoObjval(lp, set, transprob, var, oldbound, newbound, boundtype);
2053 SCIPnodeUpdateLowerbound(node, stat, set, tree, transprob, origprob, newpseudoobjval);
2054 }
2055 else
2056 {
2057 /* check the inferred bound change on the debugging solution */
2058 SCIP_CALL( SCIPdebugCheckInference(blkmem, set, node, var, newbound, boundtype) ); /*lint !e506 !e774*/
2059
2060 /* remember the bound change as inference (lpsolval is not important: use 0.0) */
2061 SCIP_CALL( SCIPdomchgAddBoundchg(&node->domchg, blkmem, set, var, newbound, boundtype,
2063 0.0, infervar, infercons, inferprop, inferinfo, inferboundtype) );
2064 }
2065
2066 assert(node->domchg != NULL);
2067 assert(node->domchg->domchgdyn.domchgtype == SCIP_DOMCHGTYPE_DYNAMIC); /*lint !e641*/
2068 assert(node->domchg->domchgdyn.boundchgs != NULL);
2069 assert(node->domchg->domchgdyn.nboundchgs > 0);
2070 assert(node->domchg->domchgdyn.boundchgs[node->domchg->domchgdyn.nboundchgs-1].var == var);
2071 assert(node->domchg->domchgdyn.boundchgs[node->domchg->domchgdyn.nboundchgs-1].newbound == newbound); /*lint !e777*/
2072
2073 /* if node is active, apply the bound change immediately */
2074 if( node->active )
2075 {
2076 SCIP_Bool cutoff;
2077
2078 /**@todo if the node is active, it currently must either be the effective root (see above) or the current node;
2079 * if a bound change to an intermediate active node should be added, we must make sure, the bound change
2080 * information array of the variable stays sorted (new info must be sorted in instead of putting it to
2081 * the end of the array), and we should identify now redundant bound changes that are applied at a
2082 * later node on the active path
2083 */
2084 assert(SCIPtreeGetCurrentNode(tree) == node);
2086 blkmem, set, stat, lp, branchcand, eventqueue, (int) node->depth, node->domchg->domchgdyn.nboundchgs-1, &cutoff) );
2087 assert(node->domchg->domchgdyn.boundchgs[node->domchg->domchgdyn.nboundchgs-1].var == var);
2088 assert(!cutoff);
2089 }
2090
2091 return SCIP_OKAY;
2092}
2093
2094/** adds bound change to focus node, or child of focus node, or probing node;
2095 * if possible, adjusts bound to integral value
2096 */
2098 SCIP_NODE* node, /**< node to add bound change to */
2099 BMS_BLKMEM* blkmem, /**< block memory */
2100 SCIP_SET* set, /**< global SCIP settings */
2101 SCIP_STAT* stat, /**< problem statistics */
2102 SCIP_PROB* transprob, /**< transformed problem after presolve */
2103 SCIP_PROB* origprob, /**< original problem */
2104 SCIP_TREE* tree, /**< branch and bound tree */
2105 SCIP_REOPT* reopt, /**< reoptimization data structure */
2106 SCIP_LP* lp, /**< current LP data */
2107 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
2108 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2109 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
2110 SCIP_VAR* var, /**< variable to change the bounds for */
2111 SCIP_Real newbound, /**< new value for bound */
2112 SCIP_BOUNDTYPE boundtype, /**< type of bound: lower or upper bound */
2113 SCIP_Bool probingchange /**< is the bound change a temporary setting due to probing? */
2114 )
2115{
2116 SCIP_CALL( SCIPnodeAddBoundinfer(node, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
2117 cliquetable, var, newbound, boundtype, NULL, NULL, 0, probingchange) );
2118
2119 return SCIP_OKAY;
2120}
2121
2122/** adds hole with inference information to focus node, child of focus node, or probing node;
2123 * if possible, adjusts bound to integral value;
2124 * at most one of infercons and inferprop may be non-NULL
2125 */
2127 SCIP_NODE* node, /**< node to add bound change to */
2128 BMS_BLKMEM* blkmem, /**< block memory */
2129 SCIP_SET* set, /**< global SCIP settings */
2130 SCIP_STAT* stat, /**< problem statistics */
2131 SCIP_TREE* tree, /**< branch and bound tree */
2132 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2133 SCIP_VAR* var, /**< variable to change the bounds for */
2134 SCIP_Real left, /**< left bound of open interval defining the hole (left,right) */
2135 SCIP_Real right, /**< right bound of open interval defining the hole (left,right) */
2136 SCIP_CONS* infercons, /**< constraint that deduced the bound change, or NULL */
2137 SCIP_PROP* inferprop, /**< propagator that deduced the bound change, or NULL */
2138 int inferinfo, /**< user information for inference to help resolving the conflict */
2139 SCIP_Bool probingchange, /**< is the bound change a temporary setting due to probing? */
2140 SCIP_Bool* added /**< pointer to store whether the hole was added, or NULL */
2141 )
2142{
2143#if 0
2144 SCIP_VAR* infervar;
2145#endif
2146
2147 assert(node != NULL);
2152 || node->depth == 0);
2153 assert(blkmem != NULL);
2154 assert(set != NULL);
2155 assert(tree != NULL);
2156 assert(tree->effectiverootdepth >= 0);
2157 assert(tree->root != NULL);
2158 assert(var != NULL);
2159 assert(node->active || (infercons == NULL && inferprop == NULL));
2160 assert((SCIP_NODETYPE)node->nodetype == SCIP_NODETYPE_PROBINGNODE || !probingchange);
2161
2162 /* the interval should not be empty */
2163 assert(SCIPsetIsLT(set, left, right));
2164
2165#ifndef NDEBUG
2166 {
2167 SCIP_Real adjustedleft;
2168 SCIP_Real adjustedright;
2169
2170 adjustedleft = left;
2171 adjustedright = right;
2172
2173 SCIPvarAdjustUb(var, set, &adjustedleft);
2174 SCIPvarAdjustLb(var, set, &adjustedright);
2175
2176 assert(SCIPsetIsEQ(set, left, adjustedleft));
2177 assert(SCIPsetIsEQ(set, right, adjustedright));
2178 }
2179#endif
2180
2181 /* the hole should lay within the lower and upper bounds */
2182 assert(SCIPsetIsGE(set, left, SCIPvarGetLbLocal(var)));
2183 assert(SCIPsetIsLE(set, right, SCIPvarGetUbLocal(var)));
2184
2185 SCIPsetDebugMsg(set, "adding hole (%g,%g) at node at depth %u to variable <%s>: bounds=[%g,%g], (infer%s=<%s>, inferinfo=%d)\n",
2186 left, right, node->depth, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), infercons != NULL ? "cons" : "prop",
2187 infercons != NULL ? SCIPconsGetName(infercons) : (inferprop != NULL ? SCIPpropGetName(inferprop) : "-"), inferinfo);
2188
2189#if 0
2190 /* remember variable as inference variable, and get corresponding active variable, bound and bound type */
2191 infervar = var;
2192#endif
2193 SCIP_CALL( SCIPvarGetProbvarHole(&var, &left, &right) );
2194
2196 {
2197 SCIPerrorMessage("cannot change bounds of multi-aggregated variable <%s>\n", SCIPvarGetName(var));
2198 SCIPABORT();
2199 return SCIP_INVALIDDATA; /*lint !e527*/
2200 }
2202
2203 SCIPsetDebugMsg(set, " -> transformed to active variable <%s>: hole (%g,%g), obj: %g\n", SCIPvarGetName(var), left, right, SCIPvarGetObj(var));
2204
2205 stat->nholechgs++;
2206
2207 /* if we are in probing mode we have to additionally count the bound changes for the probing statistic */
2208 if( tree->probingroot != NULL )
2209 stat->nprobholechgs++;
2210
2211 /* if the node is the root node: change local and global bound immediately */
2212 if( SCIPnodeGetDepth(node) <= tree->effectiverootdepth )
2213 {
2214 assert(node->active || tree->focusnode == NULL );
2216 assert(!probingchange);
2217
2218 SCIPsetDebugMsg(set, " -> hole added in root node: perform global domain change\n");
2219 SCIP_CALL( SCIPvarAddHoleGlobal(var, blkmem, set, stat, eventqueue, left, right, added) );
2220
2221 if( set->stage == SCIP_STAGE_SOLVING && (*added) )
2222 {
2223 /* the root should be repropagated due to the bound change */
2224 SCIPnodePropagateAgain(tree->root, set, stat, tree);
2225 SCIPsetDebugMsg(set, "marked root node to be repropagated due to global added hole <%s>: (%g,%g) found in depth %u\n",
2226 SCIPvarGetName(var), left, right, node->depth);
2227 }
2228
2229 return SCIP_OKAY;
2230 }
2231
2232 /**@todo add adding of local domain holes */
2233
2234 (*added) = FALSE;
2235 SCIPerrorMessage("WARNING: currently domain holes can only be handled globally!\n");
2236
2237 stat->nholechgs--;
2238
2239 /* if we are in probing mode we have to additionally count the bound changes for the probing statistic */
2240 if( tree->probingroot != NULL )
2241 stat->nprobholechgs--;
2242
2243 return SCIP_OKAY;
2244}
2245
2246/** adds hole change to focus node, or child of focus node */
2248 SCIP_NODE* node, /**< node to add bound change to */
2249 BMS_BLKMEM* blkmem, /**< block memory */
2250 SCIP_SET* set, /**< global SCIP settings */
2251 SCIP_STAT* stat, /**< problem statistics */
2252 SCIP_TREE* tree, /**< branch and bound tree */
2253 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2254 SCIP_VAR* var, /**< variable to change the bounds for */
2255 SCIP_Real left, /**< left bound of open interval defining the hole (left,right) */
2256 SCIP_Real right, /**< right bound of open interval defining the hole (left,right) */
2257 SCIP_Bool probingchange, /**< is the bound change a temporary setting due to probing? */
2258 SCIP_Bool* added /**< pointer to store whether the hole was added, or NULL */
2259 )
2260{
2261 assert(node != NULL);
2265 assert(blkmem != NULL);
2266
2267 SCIPsetDebugMsg(set, "adding hole (%g,%g) at node at depth %u of variable <%s>\n",
2268 left, right, node->depth, SCIPvarGetName(var));
2269
2270 SCIP_CALL( SCIPnodeAddHoleinfer(node, blkmem, set, stat, tree, eventqueue, var, left, right,
2271 NULL, NULL, 0, probingchange, added) );
2272
2273 /**@todo apply hole change on active nodes and issue event */
2274
2275 return SCIP_OKAY;
2276}
2277
2278/** applies the pending bound changes */
2279static
2281 SCIP_TREE* tree, /**< branch and bound tree */
2282 SCIP_REOPT* reopt, /**< reoptimization data structure */
2283 BMS_BLKMEM* blkmem, /**< block memory */
2284 SCIP_SET* set, /**< global SCIP settings */
2285 SCIP_STAT* stat, /**< problem statistics */
2286 SCIP_PROB* transprob, /**< transformed problem after presolve */
2287 SCIP_PROB* origprob, /**< original problem */
2288 SCIP_LP* lp, /**< current LP data */
2289 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
2290 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2291 SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
2292 )
2293{
2294 SCIP_VAR* var;
2295 int npendingbdchgs;
2296 int conflictdepth;
2297 int i;
2298
2299 assert(tree != NULL);
2300
2301 npendingbdchgs = tree->npendingbdchgs;
2302 for( i = 0; i < npendingbdchgs; ++i )
2303 {
2304 var = tree->pendingbdchgs[i].var;
2305 assert(SCIPnodeGetDepth(tree->pendingbdchgs[i].node) < tree->cutoffdepth);
2306
2307 conflictdepth = SCIPvarGetConflictingBdchgDepth(var, set, tree->pendingbdchgs[i].boundtype,
2308 tree->pendingbdchgs[i].newbound);
2309
2310 /* It can happen, that a pending bound change conflicts with the global bounds, because when it was collected, it
2311 * just conflicted with the local bounds, but a conflicting global bound change was applied afterwards. In this
2312 * case, we can cut off the node where the pending bound change should be applied.
2313 */
2314 if( conflictdepth == 0 )
2315 {
2316 SCIP_CALL( SCIPnodeCutoff(tree->pendingbdchgs[i].node, set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
2317
2318 if( ((int) tree->pendingbdchgs[i].node->depth) <= tree->effectiverootdepth )
2319 break; /* break here to clear all pending bound changes */
2320 else
2321 continue;
2322 }
2323
2324 assert(conflictdepth == -1);
2325
2326 SCIPsetDebugMsg(set, "applying pending bound change <%s>[%g,%g] %s %g\n", SCIPvarGetName(var),
2328 tree->pendingbdchgs[i].boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=",
2329 tree->pendingbdchgs[i].newbound);
2330
2331 /* ignore bounds that are now redundant (for example, multiple entries in the pendingbdchgs for the same
2332 * variable)
2333 */
2335 {
2336 SCIP_Real lb;
2337
2338 lb = SCIPvarGetLbLocal(var);
2339 if( !SCIPsetIsGT(set, tree->pendingbdchgs[i].newbound, lb) )
2340 continue;
2341 }
2342 else
2343 {
2344 SCIP_Real ub;
2345
2346 assert(tree->pendingbdchgs[i].boundtype == SCIP_BOUNDTYPE_UPPER);
2347 ub = SCIPvarGetUbLocal(var);
2348 if( !SCIPsetIsLT(set, tree->pendingbdchgs[i].newbound, ub) )
2349 continue;
2350 }
2351
2352 SCIP_CALL( SCIPnodeAddBoundinfer(tree->pendingbdchgs[i].node, blkmem, set, stat, transprob, origprob, tree, reopt,
2353 lp, branchcand, eventqueue, cliquetable, var, tree->pendingbdchgs[i].newbound, tree->pendingbdchgs[i].boundtype,
2355 tree->pendingbdchgs[i].probingchange) );
2356 assert(tree->npendingbdchgs == npendingbdchgs); /* this time, the bound change can be applied! */
2357 }
2358
2359 /* clear pending bound changes */
2360 for( i = 0; i < tree->npendingbdchgs; ++i )
2361 {
2362 var = tree->pendingbdchgs[i].var;
2363 assert(var != NULL);
2364
2365 /* release the variable */
2366 SCIP_CALL( SCIPvarRelease(&var, blkmem, set, eventqueue, lp) );
2367 }
2368
2369 tree->npendingbdchgs = 0;
2370
2371 return SCIP_OKAY;
2372}
2373
2374/** if given value is larger than the node's lower bound, sets the node's lower bound to the new value */
2376 SCIP_NODE* node, /**< node to update lower bound for */
2377 SCIP_STAT* stat, /**< problem statistics */
2378 SCIP_SET* set, /**< global SCIP settings */
2379 SCIP_TREE* tree, /**< branch and bound tree */
2380 SCIP_PROB* transprob, /**< transformed problem after presolve */
2381 SCIP_PROB* origprob, /**< original problem */
2382 SCIP_Real newbound /**< new lower bound for the node (if it's larger than the old one) */
2383 )
2384{
2385 assert(node != NULL);
2386 assert(stat != NULL);
2387
2388 if( newbound > node->lowerbound )
2389 {
2390 SCIP_Real oldbound;
2391
2392 oldbound = node->lowerbound;
2393 node->lowerbound = newbound;
2394 node->estimate = MAX(node->estimate, newbound);
2395
2396 if( node->depth == 0 )
2397 {
2398 stat->rootlowerbound = newbound;
2399 if( set->misc_calcintegral )
2400 SCIPstatUpdatePrimalDualIntegrals(stat, set, transprob, origprob, SCIPsetInfinity(set), newbound);
2401 SCIPvisualLowerbound(stat->visual, set, stat, newbound);
2402 }
2403 else if ( SCIPnodeGetType(node) != SCIP_NODETYPE_PROBINGNODE )
2404 {
2405 SCIP_Real lowerbound;
2406
2407 lowerbound = SCIPtreeGetLowerbound(tree, set);
2408 assert(newbound >= lowerbound);
2409 SCIPvisualLowerbound(stat->visual, set, stat, lowerbound);
2410
2411 /* updating the primal integral is only necessary if dual bound has increased since last evaluation */
2412 if( set->misc_calcintegral && SCIPsetIsEQ(set, oldbound, stat->lastlowerbound) && lowerbound > stat->lastlowerbound )
2413 SCIPstatUpdatePrimalDualIntegrals(stat, set, transprob, origprob, SCIPsetInfinity(set), lowerbound);
2414 }
2415 }
2416}
2417
2418/** updates lower bound of node using lower bound of LP */
2420 SCIP_NODE* node, /**< node to set lower bound for */
2421 SCIP_SET* set, /**< global SCIP settings */
2422 SCIP_STAT* stat, /**< problem statistics */
2423 SCIP_TREE* tree, /**< branch and bound tree */
2424 SCIP_PROB* transprob, /**< transformed problem after presolve */
2425 SCIP_PROB* origprob, /**< original problem */
2426 SCIP_LP* lp /**< LP data */
2427 )
2428{
2429 SCIP_Real lpobjval;
2430
2431 assert(set != NULL);
2432 assert(lp->flushed);
2433
2434 /* in case of iteration or time limit, the LP value may not be a valid dual bound */
2435 /* @todo check for dual feasibility of LP solution and use sub-optimal solution if they are dual feasible */
2437 return SCIP_OKAY;
2438
2439 if( set->misc_exactsolve )
2440 {
2441 SCIP_CALL( SCIPlpGetProvedLowerbound(lp, set, &lpobjval) );
2442 }
2443 else
2444 lpobjval = SCIPlpGetObjval(lp, set, transprob);
2445
2446 SCIPnodeUpdateLowerbound(node, stat, set, tree, transprob, origprob, lpobjval);
2447
2448 return SCIP_OKAY;
2449}
2450
2451
2452/** change the node selection priority of the given child */
2454 SCIP_TREE* tree, /**< branch and bound tree */
2455 SCIP_NODE* child, /**< child to update the node selection priority */
2456 SCIP_Real priority /**< node selection priority value */
2457 )
2458{
2459 int pos;
2460
2461 assert( SCIPnodeGetType(child) == SCIP_NODETYPE_CHILD );
2462
2463 pos = child->data.child.arraypos;
2464 assert( pos >= 0 );
2465
2466 tree->childrenprio[pos] = priority;
2467}
2468
2469
2470/** sets the node's estimated bound to the new value */
2472 SCIP_NODE* node, /**< node to update lower bound for */
2473 SCIP_SET* set, /**< global SCIP settings */
2474 SCIP_Real newestimate /**< new estimated bound for the node */
2475 )
2476{
2477 assert(node != NULL);
2478 assert(set != NULL);
2479 assert(SCIPsetIsRelGE(set, newestimate, node->lowerbound));
2480
2481 /* due to numerical reasons we need this check, see https://git.zib.de/integer/scip/issues/2866 */
2482 if( node->lowerbound <= newestimate )
2483 node->estimate = newestimate;
2484}
2485
2486/** propagates implications of binary fixings at the given node triggered by the implication graph and the clique table */
2488 SCIP_NODE* node, /**< node to propagate implications on */
2489 BMS_BLKMEM* blkmem, /**< block memory */
2490 SCIP_SET* set, /**< global SCIP settings */
2491 SCIP_STAT* stat, /**< problem statistics */
2492 SCIP_PROB* transprob, /**< transformed problem after presolve */
2493 SCIP_PROB* origprob, /**< original problem */
2494 SCIP_TREE* tree, /**< branch and bound tree */
2495 SCIP_REOPT* reopt, /**< reoptimization data structure */
2496 SCIP_LP* lp, /**< current LP data */
2497 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
2498 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2499 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
2500 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
2501 )
2502{
2503 int nboundchgs;
2504 int i;
2505
2506 assert(node != NULL);
2507 assert(SCIPnodeIsActive(node));
2511 assert(cutoff != NULL);
2512
2513 SCIPsetDebugMsg(set, "implication graph propagation of node #%" SCIP_LONGINT_FORMAT " in depth %d\n",
2514 SCIPnodeGetNumber(node), SCIPnodeGetDepth(node));
2515
2516 *cutoff = FALSE;
2517
2518 /* propagate all fixings of binary variables performed at this node */
2519 nboundchgs = SCIPdomchgGetNBoundchgs(node->domchg);
2520 for( i = 0; i < nboundchgs && !(*cutoff); ++i )
2521 {
2522 SCIP_BOUNDCHG* boundchg;
2523 SCIP_VAR* var;
2524
2525 boundchg = SCIPdomchgGetBoundchg(node->domchg, i);
2526
2527 /* ignore redundant bound changes */
2528 if( SCIPboundchgIsRedundant(boundchg) )
2529 continue;
2530
2531 var = SCIPboundchgGetVar(boundchg);
2532 if( SCIPvarIsBinary(var) )
2533 {
2534 SCIP_Bool varfixing;
2535 int nimpls;
2536 SCIP_VAR** implvars;
2537 SCIP_BOUNDTYPE* impltypes;
2538 SCIP_Real* implbounds;
2539 SCIP_CLIQUE** cliques;
2540 int ncliques;
2541 int j;
2542
2543 varfixing = (SCIPboundchgGetBoundtype(boundchg) == SCIP_BOUNDTYPE_LOWER);
2544 nimpls = SCIPvarGetNImpls(var, varfixing);
2545 implvars = SCIPvarGetImplVars(var, varfixing);
2546 impltypes = SCIPvarGetImplTypes(var, varfixing);
2547 implbounds = SCIPvarGetImplBounds(var, varfixing);
2548
2549 /* apply implications */
2550 for( j = 0; j < nimpls; ++j )
2551 {
2552 SCIP_Real lb;
2553 SCIP_Real ub;
2554
2555 /* @note should this be checked here (because SCIPnodeAddBoundinfer fails for multi-aggregated variables)
2556 * or should SCIPnodeAddBoundinfer() just return for multi-aggregated variables?
2557 */
2558 if( SCIPvarGetStatus(implvars[j]) == SCIP_VARSTATUS_MULTAGGR ||
2560 continue;
2561
2562 /* check for infeasibility */
2563 lb = SCIPvarGetLbLocal(implvars[j]);
2564 ub = SCIPvarGetUbLocal(implvars[j]);
2565 if( impltypes[j] == SCIP_BOUNDTYPE_LOWER )
2566 {
2567 if( SCIPsetIsFeasGT(set, implbounds[j], ub) )
2568 {
2569 *cutoff = TRUE;
2570 return SCIP_OKAY;
2571 }
2572 if( SCIPsetIsFeasLE(set, implbounds[j], lb) )
2573 continue;
2574 }
2575 else
2576 {
2577 if( SCIPsetIsFeasLT(set, implbounds[j], lb) )
2578 {
2579 *cutoff = TRUE;
2580 return SCIP_OKAY;
2581 }
2582 if( SCIPsetIsFeasGE(set, implbounds[j], ub) )
2583 continue;
2584 }
2585
2586 /* @note the implication might affect a fixed variable (after resolving (multi-)aggregations);
2587 * normally, the implication should have been deleted in that case, but this is only possible
2588 * if the implied variable has the reverse implication stored as a variable bound;
2589 * due to numerics, the variable bound may not be present and so the implication is not deleted
2590 */
2592 continue;
2593
2594 /* apply the implication */
2595 SCIP_CALL( SCIPnodeAddBoundinfer(node, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
2596 eventqueue, cliquetable, implvars[j], implbounds[j], impltypes[j], NULL, NULL, 0, FALSE) );
2597 }
2598
2599 /* apply cliques */
2600 ncliques = SCIPvarGetNCliques(var, varfixing);
2601 cliques = SCIPvarGetCliques(var, varfixing);
2602 for( j = 0; j < ncliques; ++j )
2603 {
2604 SCIP_VAR** vars;
2605 SCIP_Bool* values;
2606 int nvars;
2607 int k;
2608
2609 nvars = SCIPcliqueGetNVars(cliques[j]);
2610 vars = SCIPcliqueGetVars(cliques[j]);
2611 values = SCIPcliqueGetValues(cliques[j]);
2612 for( k = 0; k < nvars; ++k )
2613 {
2614 SCIP_Real lb;
2615 SCIP_Real ub;
2616
2617 assert(SCIPvarIsBinary(vars[k]));
2618
2619 if( SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_MULTAGGR ||
2621 continue;
2622
2623 if( vars[k] == var && values[k] == varfixing )
2624 continue;
2625
2626 /* check for infeasibility */
2627 lb = SCIPvarGetLbLocal(vars[k]);
2628 ub = SCIPvarGetUbLocal(vars[k]);
2629 if( values[k] == FALSE )
2630 {
2631 if( ub < 0.5 )
2632 {
2633 *cutoff = TRUE;
2634 return SCIP_OKAY;
2635 }
2636 if( lb > 0.5 )
2637 continue;
2638 }
2639 else
2640 {
2641 if( lb > 0.5 )
2642 {
2643 *cutoff = TRUE;
2644 return SCIP_OKAY;
2645 }
2646 if( ub < 0.5 )
2647 continue;
2648 }
2649
2651 continue;
2652
2653 /* apply the clique implication */
2654 SCIP_CALL( SCIPnodeAddBoundinfer(node, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
2655 eventqueue, cliquetable, vars[k], (SCIP_Real)(!values[k]), values[k] ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER,
2656 NULL, NULL, 0, FALSE) );
2657 }
2658 }
2659 }
2660 }
2661
2662 return SCIP_OKAY;
2663}
2664
2665
2666
2667
2668/*
2669 * Path Switching
2670 */
2671
2672/** updates the LP sizes of the active path starting at the given depth */
2673static
2675 SCIP_TREE* tree, /**< branch and bound tree */
2676 int startdepth /**< depth to start counting */
2677 )
2678{
2679 SCIP_NODE* node;
2680 int ncols;
2681 int nrows;
2682 int i;
2683
2684 assert(tree != NULL);
2685 assert(startdepth >= 0);
2686 assert(startdepth <= tree->pathlen);
2687
2688 if( startdepth == 0 )
2689 {
2690 ncols = 0;
2691 nrows = 0;
2692 }
2693 else
2694 {
2695 ncols = tree->pathnlpcols[startdepth-1];
2696 nrows = tree->pathnlprows[startdepth-1];
2697 }
2698
2699 for( i = startdepth; i < tree->pathlen; ++i )
2700 {
2701 node = tree->path[i];
2702 assert(node != NULL);
2703 assert(node->active);
2704 assert((int)(node->depth) == i);
2705
2706 switch( SCIPnodeGetType(node) )
2707 {
2709 assert(i == tree->pathlen-1 || SCIPtreeProbing(tree));
2710 break;
2712 assert(SCIPtreeProbing(tree));
2713 assert(i >= 1);
2714 assert(SCIPnodeGetType(tree->path[i-1]) == SCIP_NODETYPE_FOCUSNODE
2715 || (ncols == node->data.probingnode->ninitialcols && nrows == node->data.probingnode->ninitialrows));
2716 assert(ncols <= node->data.probingnode->ncols || !tree->focuslpconstructed);
2717 assert(nrows <= node->data.probingnode->nrows || !tree->focuslpconstructed);
2718 if( i < tree->pathlen-1 )
2719 {
2720 ncols = node->data.probingnode->ncols;
2721 nrows = node->data.probingnode->nrows;
2722 }
2723 else
2724 {
2725 /* for the current probing node, the initial LP size is stored in the path */
2726 ncols = node->data.probingnode->ninitialcols;
2727 nrows = node->data.probingnode->ninitialrows;
2728 }
2729 break;
2731 SCIPerrorMessage("sibling cannot be in the active path\n");
2732 SCIPABORT();
2733 return SCIP_INVALIDDATA; /*lint !e527*/
2735 SCIPerrorMessage("child cannot be in the active path\n");
2736 SCIPABORT();
2737 return SCIP_INVALIDDATA; /*lint !e527*/
2738 case SCIP_NODETYPE_LEAF:
2739 SCIPerrorMessage("leaf cannot be in the active path\n");
2740 SCIPABORT();
2741 return SCIP_INVALIDDATA; /*lint !e527*/
2743 SCIPerrorMessage("dead-end cannot be in the active path\n");
2744 SCIPABORT();
2745 return SCIP_INVALIDDATA; /*lint !e527*/
2747 break;
2749 assert(node->data.pseudofork != NULL);
2750 ncols += node->data.pseudofork->naddedcols;
2751 nrows += node->data.pseudofork->naddedrows;
2752 break;
2753 case SCIP_NODETYPE_FORK:
2754 assert(node->data.fork != NULL);
2755 ncols += node->data.fork->naddedcols;
2756 nrows += node->data.fork->naddedrows;
2757 break;
2759 assert(node->data.subroot != NULL);
2760 ncols = node->data.subroot->ncols;
2761 nrows = node->data.subroot->nrows;
2762 break;
2764 SCIPerrorMessage("node cannot be of type REFOCUSNODE at this point\n");
2765 SCIPABORT();
2766 return SCIP_INVALIDDATA; /*lint !e527*/
2767 default:
2768 SCIPerrorMessage("unknown node type %d\n", SCIPnodeGetType(node));
2769 SCIPABORT();
2770 return SCIP_INVALIDDATA; /*lint !e527*/
2771 }
2772 tree->pathnlpcols[i] = ncols;
2773 tree->pathnlprows[i] = nrows;
2774 }
2775 return SCIP_OKAY;
2776}
2777
2778/** finds the common fork node, the new LP state defining fork, and the new focus subroot, if the path is switched to
2779 * the given node
2780 */
2781static
2783 SCIP_TREE* tree, /**< branch and bound tree */
2784 SCIP_NODE* node, /**< new focus node, or NULL */
2785 SCIP_NODE** commonfork, /**< pointer to store common fork node of old and new focus node */
2786 SCIP_NODE** newlpfork, /**< pointer to store the new LP defining fork node */
2787 SCIP_NODE** newlpstatefork, /**< pointer to store the new LP state defining fork node */
2788 SCIP_NODE** newsubroot, /**< pointer to store the new subroot node */
2789 SCIP_Bool* cutoff /**< pointer to store whether the given node can be cut off and no path switching
2790 * should be performed */
2791 )
2792{
2793 SCIP_NODE* fork;
2794 SCIP_NODE* lpfork;
2795 SCIP_NODE* lpstatefork;
2796 SCIP_NODE* subroot;
2797
2798 assert(tree != NULL);
2799 assert(tree->root != NULL);
2800 assert((tree->focusnode == NULL) == !tree->root->active);
2801 assert(tree->focuslpfork == NULL || tree->focusnode != NULL);
2802 assert(tree->focuslpfork == NULL || tree->focuslpfork->depth < tree->focusnode->depth);
2803 assert(tree->focuslpstatefork == NULL || tree->focuslpfork != NULL);
2804 assert(tree->focuslpstatefork == NULL || tree->focuslpstatefork->depth <= tree->focuslpfork->depth);
2805 assert(tree->focussubroot == NULL || tree->focuslpstatefork != NULL);
2806 assert(tree->focussubroot == NULL || tree->focussubroot->depth <= tree->focuslpstatefork->depth);
2807 assert(tree->cutoffdepth >= 0);
2808 assert(tree->cutoffdepth == INT_MAX || tree->cutoffdepth < tree->pathlen);
2809 assert(tree->cutoffdepth == INT_MAX || tree->path[tree->cutoffdepth]->cutoff);
2810 assert(tree->repropdepth >= 0);
2811 assert(tree->repropdepth == INT_MAX || tree->repropdepth < tree->pathlen);
2812 assert(tree->repropdepth == INT_MAX || tree->path[tree->repropdepth]->reprop);
2813 assert(commonfork != NULL);
2814 assert(newlpfork != NULL);
2815 assert(newlpstatefork != NULL);
2816 assert(newsubroot != NULL);
2817 assert(cutoff != NULL);
2818
2819 *commonfork = NULL;
2820 *newlpfork = NULL;
2821 *newlpstatefork = NULL;
2822 *newsubroot = NULL;
2823 *cutoff = FALSE;
2824
2825 /* if the new focus node is NULL, there is no common fork node, and the new LP fork, LP state fork, and subroot
2826 * are NULL
2827 */
2828 if( node == NULL )
2829 {
2830 tree->cutoffdepth = INT_MAX;
2831 tree->repropdepth = INT_MAX;
2832 return;
2833 }
2834
2835 /* check if the new node is marked to be cut off */
2836 if( node->cutoff )
2837 {
2838 *cutoff = TRUE;
2839 return;
2840 }
2841
2842 /* 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
2843 * and subroot
2844 */
2845 if( tree->focusnode == NULL )
2846 {
2847 assert(!tree->root->active);
2848 assert(tree->pathlen == 0);
2849 assert(tree->cutoffdepth == INT_MAX);
2850 assert(tree->repropdepth == INT_MAX);
2851
2852 lpfork = node;
2855 {
2856 lpfork = lpfork->parent;
2857 if( lpfork == NULL )
2858 return;
2859 if( lpfork->cutoff )
2860 {
2861 *cutoff = TRUE;
2862 return;
2863 }
2864 }
2865 *newlpfork = lpfork;
2866
2867 lpstatefork = lpfork;
2868 while( SCIPnodeGetType(lpstatefork) != SCIP_NODETYPE_FORK && SCIPnodeGetType(lpstatefork) != SCIP_NODETYPE_SUBROOT )
2869 {
2870 lpstatefork = lpstatefork->parent;
2871 if( lpstatefork == NULL )
2872 return;
2873 if( lpstatefork->cutoff )
2874 {
2875 *cutoff = TRUE;
2876 return;
2877 }
2878 }
2879 *newlpstatefork = lpstatefork;
2880
2881 subroot = lpstatefork;
2882 while( SCIPnodeGetType(subroot) != SCIP_NODETYPE_SUBROOT )
2883 {
2884 subroot = subroot->parent;
2885 if( subroot == NULL )
2886 return;
2887 if( subroot->cutoff )
2888 {
2889 *cutoff = TRUE;
2890 return;
2891 }
2892 }
2893 *newsubroot = subroot;
2894
2895 fork = subroot;
2896 while( fork->parent != NULL )
2897 {
2898 fork = fork->parent;
2899 if( fork->cutoff )
2900 {
2901 *cutoff = TRUE;
2902 return;
2903 }
2904 }
2905 return;
2906 }
2907
2908 /* find the common fork node, the new LP defining fork, the new LP state defining fork, and the new focus subroot */
2909 fork = node;
2910 lpfork = NULL;
2911 lpstatefork = NULL;
2912 subroot = NULL;
2913 assert(fork != NULL);
2914
2915 while( !fork->active )
2916 {
2917 fork = fork->parent;
2918 assert(fork != NULL); /* because the root is active, there must be a common fork node */
2919
2920 if( fork->cutoff )
2921 {
2922 *cutoff = TRUE;
2923 return;
2924 }
2925 if( lpfork == NULL
2928 lpfork = fork;
2929 if( lpstatefork == NULL
2931 lpstatefork = fork;
2932 if( subroot == NULL && SCIPnodeGetType(fork) == SCIP_NODETYPE_SUBROOT )
2933 subroot = fork;
2934 }
2935 assert(lpfork == NULL || !lpfork->active || lpfork == fork);
2936 assert(lpstatefork == NULL || !lpstatefork->active || lpstatefork == fork);
2937 assert(subroot == NULL || !subroot->active || subroot == fork);
2938 SCIPdebugMessage("find switch forks: forkdepth=%u\n", fork->depth);
2939
2940 /* if the common fork node is below the current cutoff depth, the cutoff node is an ancestor of the common fork
2941 * and thus an ancestor of the new focus node, s.t. the new node can also be cut off
2942 */
2943 assert((int)fork->depth != tree->cutoffdepth);
2944 if( (int)fork->depth > tree->cutoffdepth )
2945 {
2946#ifndef NDEBUG
2947 while( !fork->cutoff )
2948 {
2949 fork = fork->parent;
2950 assert(fork != NULL);
2951 }
2952 assert((int)fork->depth >= tree->cutoffdepth);
2953#endif
2954 *cutoff = TRUE;
2955 return;
2956 }
2957 tree->cutoffdepth = INT_MAX;
2958
2959 /* if not already found, continue searching the LP defining fork; it cannot be deeper than the common fork */
2960 if( lpfork == NULL )
2961 {
2962 if( tree->focuslpfork != NULL && tree->focuslpfork->depth > fork->depth )
2963 {
2964 /* focuslpfork is not on the same active path as the new node: we have to continue searching */
2965 lpfork = fork;
2966 while( lpfork != NULL
2970 {
2971 assert(lpfork->active);
2972 lpfork = lpfork->parent;
2973 }
2974 }
2975 else
2976 {
2977 /* focuslpfork is on the same active path as the new node: old and new node have the same lpfork */
2978 lpfork = tree->focuslpfork;
2979 }
2980 assert(lpfork == NULL || lpfork->depth <= fork->depth);
2981 assert(lpfork == NULL || lpfork->active);
2982 }
2983 assert(lpfork == NULL
2987 SCIPdebugMessage("find switch forks: lpforkdepth=%d\n", lpfork == NULL ? -1 : (int)(lpfork->depth));
2988
2989 /* if not already found, continue searching the LP state defining fork; it cannot be deeper than the
2990 * LP defining fork and the common fork
2991 */
2992 if( lpstatefork == NULL )
2993 {
2994 if( tree->focuslpstatefork != NULL && tree->focuslpstatefork->depth > fork->depth )
2995 {
2996 /* focuslpstatefork is not on the same active path as the new node: we have to continue searching */
2997 if( lpfork != NULL && lpfork->depth < fork->depth )
2998 lpstatefork = lpfork;
2999 else
3000 lpstatefork = fork;
3001 while( lpstatefork != NULL
3002 && SCIPnodeGetType(lpstatefork) != SCIP_NODETYPE_FORK
3003 && SCIPnodeGetType(lpstatefork) != SCIP_NODETYPE_SUBROOT )
3004 {
3005 assert(lpstatefork->active);
3006 lpstatefork = lpstatefork->parent;
3007 }
3008 }
3009 else
3010 {
3011 /* focuslpstatefork is on the same active path as the new node: old and new node have the same lpstatefork */
3012 lpstatefork = tree->focuslpstatefork;
3013 }
3014 assert(lpstatefork == NULL || lpstatefork->depth <= fork->depth);
3015 assert(lpstatefork == NULL || lpstatefork->active);
3016 }
3017 assert(lpstatefork == NULL
3018 || SCIPnodeGetType(lpstatefork) == SCIP_NODETYPE_FORK
3019 || SCIPnodeGetType(lpstatefork) == SCIP_NODETYPE_SUBROOT);
3020 assert(lpstatefork == NULL || (lpfork != NULL && lpstatefork->depth <= lpfork->depth));
3021 SCIPdebugMessage("find switch forks: lpstateforkdepth=%d\n", lpstatefork == NULL ? -1 : (int)(lpstatefork->depth));
3022
3023 /* if not already found, continue searching the subroot; it cannot be deeper than the LP defining fork, the
3024 * LP state fork and the common fork
3025 */
3026 if( subroot == NULL )
3027 {
3028 if( tree->focussubroot != NULL && tree->focussubroot->depth > fork->depth )
3029 {
3030 /* focussubroot is not on the same active path as the new node: we have to continue searching */
3031 if( lpstatefork != NULL && lpstatefork->depth < fork->depth )
3032 subroot = lpstatefork;
3033 else if( lpfork != NULL && lpfork->depth < fork->depth )
3034 subroot = lpfork;
3035 else
3036 subroot = fork;
3037 while( subroot != NULL && SCIPnodeGetType(subroot) != SCIP_NODETYPE_SUBROOT )
3038 {
3039 assert(subroot->active);
3040 subroot = subroot->parent;
3041 }
3042 }
3043 else
3044 subroot = tree->focussubroot;
3045 assert(subroot == NULL || subroot->depth <= fork->depth);
3046 assert(subroot == NULL || subroot->active);
3047 }
3048 assert(subroot == NULL || SCIPnodeGetType(subroot) == SCIP_NODETYPE_SUBROOT);
3049 assert(subroot == NULL || (lpstatefork != NULL && subroot->depth <= lpstatefork->depth));
3050 SCIPdebugMessage("find switch forks: subrootdepth=%d\n", subroot == NULL ? -1 : (int)(subroot->depth));
3051
3052 /* if a node prior to the common fork should be repropagated, we select the node to be repropagated as common
3053 * fork in order to undo all bound changes up to this node, repropagate the node, and redo the bound changes
3054 * afterwards
3055 */
3056 if( (int)fork->depth > tree->repropdepth )
3057 {
3058 fork = tree->path[tree->repropdepth];
3059 assert(fork->active);
3060 assert(fork->reprop);
3061 }
3062
3063 *commonfork = fork;
3064 *newlpfork = lpfork;
3065 *newlpstatefork = lpstatefork;
3066 *newsubroot = subroot;
3067
3068#ifndef NDEBUG
3069 while( fork != NULL )
3070 {
3071 assert(fork->active);
3072 assert(!fork->cutoff);
3073 assert(fork->parent == NULL || !fork->parent->reprop);
3074 fork = fork->parent;
3075 }
3076#endif
3077 tree->repropdepth = INT_MAX;
3078}
3079
3080/** switches the active path to the new focus node, frees dead end, applies domain and constraint set changes */
3081static
3083 SCIP_TREE* tree, /**< branch and bound tree */
3084 SCIP_REOPT* reopt, /**< reoptimization data structure */
3085 BMS_BLKMEM* blkmem, /**< block memory buffers */
3086 SCIP_SET* set, /**< global SCIP settings */
3087 SCIP_STAT* stat, /**< problem statistics */
3088 SCIP_PROB* transprob, /**< transformed problem after presolve */
3089 SCIP_PROB* origprob, /**< original problem */
3090 SCIP_PRIMAL* primal, /**< primal data */
3091 SCIP_LP* lp, /**< current LP data */
3092 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
3093 SCIP_CONFLICT* conflict, /**< conflict analysis data */
3094 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
3095 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3096 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
3097 SCIP_NODE* fork, /**< common fork node of old and new focus node, or NULL */
3098 SCIP_NODE* focusnode, /**< new focus node, or NULL */
3099 SCIP_Bool* cutoff /**< pointer to store whether the new focus node can be cut off */
3100 )
3101{
3102 int newappliedeffectiverootdepth;
3103 int focusnodedepth; /* depth of the new focus node, or -1 if focusnode == NULL */
3104 int forkdepth; /* depth of the common subroot/fork/pseudofork/junction node, or -1 if no common fork exists */
3105 int i;
3106 SCIP_NODE* oldfocusnode;
3107
3108 assert(tree != NULL);
3109 assert(fork == NULL || (fork->active && !fork->cutoff));
3110 assert(fork == NULL || focusnode != NULL);
3111 assert(focusnode == NULL || (!focusnode->active && !focusnode->cutoff));
3112 assert(focusnode == NULL || SCIPnodeGetType(focusnode) == SCIP_NODETYPE_FOCUSNODE);
3113 assert(cutoff != NULL);
3114
3115 /* set new focus node */
3116 oldfocusnode = tree->focusnode;
3117 tree->focusnode = focusnode;
3118
3119 SCIPsetDebugMsg(set, "switch path: old pathlen=%d\n", tree->pathlen);
3120
3121 /* get the nodes' depths */
3122 focusnodedepth = (focusnode != NULL ? (int)focusnode->depth : -1);
3123 forkdepth = (fork != NULL ? (int)fork->depth : -1);
3124 assert(forkdepth <= focusnodedepth);
3125 assert(forkdepth < tree->pathlen);
3126
3127 /* delay events in node deactivations to fork and node activations to parent of new focus node */
3128 SCIP_CALL( SCIPeventqueueDelay(eventqueue) );
3129
3130 /* undo the domain and constraint set changes of the old active path by deactivating the path's nodes */
3131 for( i = tree->pathlen-1; i > forkdepth; --i )
3132 {
3133 SCIP_CALL( nodeDeactivate(tree->path[i], blkmem, set, stat, tree, lp, branchcand, eventqueue) );
3134 }
3135 tree->pathlen = forkdepth+1;
3136
3137 /* apply the pending bound changes */
3138 SCIP_CALL( treeApplyPendingBdchgs(tree, reopt, blkmem, set, stat, transprob, origprob, lp, branchcand, eventqueue, cliquetable) );
3139
3140 /* create the new active path */
3141 SCIP_CALL( treeEnsurePathMem(tree, set, focusnodedepth+1) );
3142
3143 while( focusnode != fork )
3144 {
3145 assert(focusnode != NULL);
3146 assert(!focusnode->active);
3147 assert(!focusnode->cutoff);
3148 /* coverity[var_deref_op] */
3149 tree->path[focusnode->depth] = focusnode;
3150 focusnode = focusnode->parent;
3151 }
3152
3153 /* if the old focus node is a dead end (has no children), delete it */
3154 if( oldfocusnode != NULL )
3155 {
3156 SCIP_Bool freeNode;
3157
3158 switch( SCIPnodeGetType(oldfocusnode) )
3159 {
3163 case SCIP_NODETYPE_LEAF:
3165 freeNode = FALSE;
3166 break;
3168 freeNode = TRUE;
3169 break;
3171 freeNode = (oldfocusnode->data.junction.nchildren == 0);
3172 break;
3174 freeNode = (oldfocusnode->data.pseudofork->nchildren == 0);
3175 break;
3176 case SCIP_NODETYPE_FORK:
3177 freeNode = (oldfocusnode->data.fork->nchildren == 0);
3178 break;
3180 freeNode = (oldfocusnode->data.subroot->nchildren == 0);
3181 break;
3183 SCIPerrorMessage("probing node could not be the focus node\n");
3184 return SCIP_INVALIDDATA;
3185 default:
3186 SCIPerrorMessage("unknown node type %d\n", SCIPnodeGetType(oldfocusnode));
3187 return SCIP_INVALIDDATA;
3188 }
3189
3190 if( freeNode )
3191 {
3192 assert(tree->appliedeffectiverootdepth <= tree->effectiverootdepth);
3193 SCIP_CALL( SCIPnodeFree(&oldfocusnode, blkmem, set, stat, eventfilter, eventqueue, tree, lp) );
3194 assert(tree->effectiverootdepth <= focusnodedepth || tree->focusnode == NULL);
3195 }
3196 }
3197
3198 /* apply effective root shift up to the new focus node */
3199 *cutoff = FALSE;
3200 newappliedeffectiverootdepth = MIN(tree->effectiverootdepth, focusnodedepth);
3201
3202 /* promote the constraint set and bound changes up to the new effective root to be global changes */
3203 if( tree->appliedeffectiverootdepth < newappliedeffectiverootdepth )
3204 {
3206 "shift effective root from depth %d to %d: applying constraint set and bound changes to global problem\n",
3207 tree->appliedeffectiverootdepth, newappliedeffectiverootdepth);
3208
3209 /* at first globalize constraint changes to update constraint handlers before changing bounds */
3210 for( i = tree->appliedeffectiverootdepth + 1; i <= newappliedeffectiverootdepth; ++i )
3211 {
3212 SCIPsetDebugMsg(set, " -> applying constraint set changes of depth %d\n", i);
3213
3214 SCIP_CALL( SCIPconssetchgMakeGlobal(&tree->path[i]->conssetchg, blkmem, set, stat, transprob, reopt) );
3215 }
3216
3217 /* at last globalize bound changes triggering delayed events processed after the path switch */
3218 for( i = tree->appliedeffectiverootdepth + 1; i <= newappliedeffectiverootdepth && !(*cutoff); ++i )
3219 {
3220 SCIPsetDebugMsg(set, " -> applying bound changes of depth %d\n", i);
3221
3222 SCIP_CALL( SCIPdomchgApplyGlobal(tree->path[i]->domchg, blkmem, set, stat, lp, branchcand, eventqueue, cliquetable, cutoff) );
3223 }
3224
3225 /* update applied effective root depth */
3226 tree->appliedeffectiverootdepth = newappliedeffectiverootdepth;
3227 }
3228
3229 /* fork might be cut off when applying the pending bound changes */
3230 if( fork != NULL && fork->cutoff )
3231 *cutoff = TRUE;
3232 else if( fork != NULL && fork->reprop && !(*cutoff) )
3233 {
3234 /* propagate common fork again, if the reprop flag is set */
3235 assert(tree->path[forkdepth] == fork);
3236 assert(fork->active);
3237 assert(!fork->cutoff);
3238
3239 SCIP_CALL( nodeRepropagate(fork, blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, conflict,
3240 eventfilter, eventqueue, cliquetable, cutoff) );
3241 }
3242 assert(fork != NULL || !(*cutoff));
3243
3244 /* Apply domain and constraint set changes of the new path by activating the path's nodes;
3245 * on the way, domain propagation might be applied again to the path's nodes, which can result in the cutoff of
3246 * the node (and its subtree).
3247 * We only activate all nodes down to the parent of the new focus node, because the events in this process are
3248 * delayed, which means that multiple changes of a bound of a variable are merged (and might even be cancelled out,
3249 * if the bound is first relaxed when deactivating a node on the old path and then tightened to the same value
3250 * when activating a node on the new path).
3251 * This is valid for all nodes down to the parent of the new focus node, since they have already been propagated.
3252 * Bound change events on the new focus node, however, must not be cancelled out, since they need to be propagated
3253 * and thus, the event must be thrown and catched by the constraint handlers to mark constraints for propagation.
3254 */
3255 for( i = forkdepth+1; i < focusnodedepth && !(*cutoff); ++i )
3256 {
3257 assert(!tree->path[i]->cutoff);
3258 assert(tree->pathlen == i);
3259
3260 /* activate the node, and apply domain propagation if the reprop flag is set */
3261 tree->pathlen++;
3262 SCIP_CALL( nodeActivate(tree->path[i], blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
3263 conflict, eventfilter, eventqueue, cliquetable, cutoff) );
3264 }
3265
3266 /* process the delayed events */
3267 SCIP_CALL( SCIPeventqueueProcess(eventqueue, blkmem, set, primal, lp, branchcand, eventfilter) );
3268
3269 /* activate the new focus node; there is no need to delay these events */
3270 if( !(*cutoff) && (i == focusnodedepth) )
3271 {
3272 assert(!tree->path[focusnodedepth]->cutoff);
3273 assert(tree->pathlen == focusnodedepth);
3274
3275 /* activate the node, and apply domain propagation if the reprop flag is set */
3276 tree->pathlen++;
3277 SCIP_CALL( nodeActivate(tree->path[focusnodedepth], blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand,
3278 conflict, eventfilter, eventqueue, cliquetable, cutoff) );
3279 }
3280
3281 /* mark last node of path to be cut off, if a cutoff was found */
3282 if( *cutoff )
3283 {
3284 assert(tree->pathlen > 0);
3285 assert(tree->path[tree->pathlen-1]->active);
3286 SCIP_CALL( SCIPnodeCutoff(tree->path[tree->pathlen-1], set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
3287 }
3288
3289 /* count the new LP sizes of the path */
3290 SCIP_CALL( treeUpdatePathLPSize(tree, forkdepth+1) );
3291
3292 SCIPsetDebugMsg(set, "switch path: new pathlen=%d\n", tree->pathlen);
3293
3294 return SCIP_OKAY;
3295}
3296
3297/** loads the subroot's LP data */
3298static
3300 SCIP_NODE* subroot, /**< subroot node to construct LP for */
3301 BMS_BLKMEM* blkmem, /**< block memory buffers */
3302 SCIP_SET* set, /**< global SCIP settings */
3303 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3304 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
3305 SCIP_LP* lp /**< current LP data */
3306 )
3307{
3308 SCIP_COL** cols;
3309 SCIP_ROW** rows;
3310 int ncols;
3311 int nrows;
3312 int c;
3313 int r;
3314
3315 assert(subroot != NULL);
3316 assert(SCIPnodeGetType(subroot) == SCIP_NODETYPE_SUBROOT);
3317 assert(subroot->data.subroot != NULL);
3318 assert(blkmem != NULL);
3319 assert(set != NULL);
3320 assert(lp != NULL);
3321
3322 cols = subroot->data.subroot->cols;
3323 rows = subroot->data.subroot->rows;
3324 ncols = subroot->data.subroot->ncols;
3325 nrows = subroot->data.subroot->nrows;
3326
3327 assert(ncols == 0 || cols != NULL);
3328 assert(nrows == 0 || rows != NULL);
3329
3330 for( c = 0; c < ncols; ++c )
3331 {
3332 SCIP_CALL( SCIPlpAddCol(lp, set, cols[c], (int) subroot->depth) );
3333 }
3334 for( r = 0; r < nrows; ++r )
3335 {
3336 SCIP_CALL( SCIPlpAddRow(lp, blkmem, set, eventqueue, eventfilter, rows[r], (int) subroot->depth) );
3337 }
3338
3339 return SCIP_OKAY;
3340}
3341
3342/** loads the fork's additional LP data */
3343static
3345 SCIP_NODE* fork, /**< fork node to construct additional LP for */
3346 BMS_BLKMEM* blkmem, /**< block memory buffers */
3347 SCIP_SET* set, /**< global SCIP settings */
3348 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3349 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
3350 SCIP_LP* lp /**< current LP data */
3351 )
3352{
3353 SCIP_COL** cols;
3354 SCIP_ROW** rows;
3355 int ncols;
3356 int nrows;
3357 int c;
3358 int r;
3359
3360 assert(fork != NULL);
3361 assert(SCIPnodeGetType(fork) == SCIP_NODETYPE_FORK);
3362 assert(fork->data.fork != NULL);
3363 assert(blkmem != NULL);
3364 assert(set != NULL);
3365 assert(lp != NULL);
3366
3367 cols = fork->data.fork->addedcols;
3368 rows = fork->data.fork->addedrows;
3369 ncols = fork->data.fork->naddedcols;
3370 nrows = fork->data.fork->naddedrows;
3371
3372 assert(ncols == 0 || cols != NULL);
3373 assert(nrows == 0 || rows != NULL);
3374
3375 for( c = 0; c < ncols; ++c )
3376 {
3377 SCIP_CALL( SCIPlpAddCol(lp, set, cols[c], (int) fork->depth) );
3378 }
3379 for( r = 0; r < nrows; ++r )
3380 {
3381 SCIP_CALL( SCIPlpAddRow(lp, blkmem, set, eventqueue, eventfilter, rows[r], (int) fork->depth) );
3382 }
3383
3384 return SCIP_OKAY;
3385}
3386
3387/** loads the pseudofork's additional LP data */
3388static
3390 SCIP_NODE* pseudofork, /**< pseudofork node to construct additional LP for */
3391 BMS_BLKMEM* blkmem, /**< block memory buffers */
3392 SCIP_SET* set, /**< global SCIP settings */
3393 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3394 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
3395 SCIP_LP* lp /**< current LP data */
3396 )
3397{
3398 SCIP_COL** cols;
3399 SCIP_ROW** rows;
3400 int ncols;
3401 int nrows;
3402 int c;
3403 int r;
3404
3405 assert(pseudofork != NULL);
3406 assert(SCIPnodeGetType(pseudofork) == SCIP_NODETYPE_PSEUDOFORK);
3407 assert(pseudofork->data.pseudofork != NULL);
3408 assert(blkmem != NULL);
3409 assert(set != NULL);
3410 assert(lp != NULL);
3411
3412 cols = pseudofork->data.pseudofork->addedcols;
3413 rows = pseudofork->data.pseudofork->addedrows;
3414 ncols = pseudofork->data.pseudofork->naddedcols;
3415 nrows = pseudofork->data.pseudofork->naddedrows;
3416
3417 assert(ncols == 0 || cols != NULL);
3418 assert(nrows == 0 || rows != NULL);
3419
3420 for( c = 0; c < ncols; ++c )
3421 {
3422 SCIP_CALL( SCIPlpAddCol(lp, set, cols[c], (int) pseudofork->depth) );
3423 }
3424 for( r = 0; r < nrows; ++r )
3425 {
3426 SCIP_CALL( SCIPlpAddRow(lp, blkmem, set, eventqueue, eventfilter, rows[r], (int) pseudofork->depth) );
3427 }
3428
3429 return SCIP_OKAY;
3430}
3431
3432#ifndef NDEBUG
3433/** checks validity of active path */
3434static
3436 SCIP_TREE* tree /**< branch and bound tree */
3437 )
3438{
3439 SCIP_NODE* node;
3440 int ncols;
3441 int nrows;
3442 int d;
3443
3444 assert(tree != NULL);
3445 assert(tree->path != NULL);
3446
3447 ncols = 0;
3448 nrows = 0;
3449 for( d = 0; d < tree->pathlen; ++d )
3450 {
3451 node = tree->path[d];
3452 assert(node != NULL);
3453 assert((int)(node->depth) == d);
3454 switch( SCIPnodeGetType(node) )
3455 {
3457 assert(SCIPtreeProbing(tree));
3458 assert(d >= 1);
3459 assert(SCIPnodeGetType(tree->path[d-1]) == SCIP_NODETYPE_FOCUSNODE
3460 || (ncols == node->data.probingnode->ninitialcols && nrows == node->data.probingnode->ninitialrows));
3461 assert(ncols <= node->data.probingnode->ncols || !tree->focuslpconstructed);
3462 assert(nrows <= node->data.probingnode->nrows || !tree->focuslpconstructed);
3463 if( d < tree->pathlen-1 )
3464 {
3465 ncols = node->data.probingnode->ncols;
3466 nrows = node->data.probingnode->nrows;
3467 }
3468 else
3469 {
3470 /* for the current probing node, the initial LP size is stored in the path */
3471 ncols = node->data.probingnode->ninitialcols;
3472 nrows = node->data.probingnode->ninitialrows;
3473 }
3474 break;
3476 break;
3478 ncols += node->data.pseudofork->naddedcols;
3479 nrows += node->data.pseudofork->naddedrows;
3480 break;
3481 case SCIP_NODETYPE_FORK:
3482 ncols += node->data.fork->naddedcols;
3483 nrows += node->data.fork->naddedrows;
3484 break;
3486 ncols = node->data.subroot->ncols;
3487 nrows = node->data.subroot->nrows;
3488 break;
3491 assert(d == tree->pathlen-1 || SCIPtreeProbing(tree));
3492 break;
3493 default:
3494 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",
3495 d, SCIPnodeGetType(node));
3496 SCIPABORT();
3497 } /*lint !e788*/
3498 assert(tree->pathnlpcols[d] == ncols);
3499 assert(tree->pathnlprows[d] == nrows);
3500 }
3501}
3502#else
3503#define treeCheckPath(tree) /**/
3504#endif
3505
3506/** constructs the LP relaxation of the focus node */
3508 SCIP_TREE* tree, /**< branch and bound tree */
3509 BMS_BLKMEM* blkmem, /**< block memory buffers */
3510 SCIP_SET* set, /**< global SCIP settings */
3511 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3512 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
3513 SCIP_LP* lp, /**< current LP data */
3514 SCIP_Bool* initroot /**< pointer to store whether the root LP relaxation has to be initialized */
3515 )
3516{
3517 SCIP_NODE* lpfork;
3518 int lpforkdepth;
3519 int d;
3520
3521 assert(tree != NULL);
3522 assert(!tree->focuslpconstructed);
3523 assert(tree->path != NULL);
3524 assert(tree->pathlen > 0);
3525 assert(tree->focusnode != NULL);
3527 assert(SCIPnodeGetDepth(tree->focusnode) == tree->pathlen-1);
3528 assert(!SCIPtreeProbing(tree));
3529 assert(tree->focusnode == tree->path[tree->pathlen-1]);
3530 assert(blkmem != NULL);
3531 assert(set != NULL);
3532 assert(lp != NULL);
3533 assert(initroot != NULL);
3534
3535 SCIPsetDebugMsg(set, "load LP for current fork node #%" SCIP_LONGINT_FORMAT " at depth %d\n",
3536 tree->focuslpfork == NULL ? -1 : SCIPnodeGetNumber(tree->focuslpfork),
3537 tree->focuslpfork == NULL ? -1 : SCIPnodeGetDepth(tree->focuslpfork));
3538 SCIPsetDebugMsg(set, "-> old LP has %d cols and %d rows\n", SCIPlpGetNCols(lp), SCIPlpGetNRows(lp));
3539 SCIPsetDebugMsg(set, "-> correct LP has %d cols and %d rows\n",
3540 tree->correctlpdepth >= 0 ? tree->pathnlpcols[tree->correctlpdepth] : 0,
3541 tree->correctlpdepth >= 0 ? tree->pathnlprows[tree->correctlpdepth] : 0);
3542 SCIPsetDebugMsg(set, "-> old correctlpdepth: %d\n", tree->correctlpdepth);
3543
3544 treeCheckPath(tree);
3545
3546 lpfork = tree->focuslpfork;
3547
3548 /* find out the lpfork's depth (or -1, if lpfork is NULL) */
3549 if( lpfork == NULL )
3550 {
3551 assert(tree->correctlpdepth == -1 || tree->pathnlpcols[tree->correctlpdepth] == 0);
3552 assert(tree->correctlpdepth == -1 || tree->pathnlprows[tree->correctlpdepth] == 0);
3553 assert(tree->focuslpstatefork == NULL);
3554 assert(tree->focussubroot == NULL);
3555 lpforkdepth = -1;
3556 }
3557 else
3558 {
3561 assert(lpfork->active);
3562 assert(tree->path[lpfork->depth] == lpfork);
3563 lpforkdepth = (int) lpfork->depth;
3564 }
3565 assert(lpforkdepth < tree->pathlen-1); /* lpfork must not be the last (the focus) node of the active path */
3566
3567 /* find out, if we are in the same subtree */
3568 if( tree->correctlpdepth >= 0 )
3569 {
3570 /* same subtree: shrink LP to the deepest node with correct LP */
3571 assert(lpforkdepth == -1 || tree->pathnlpcols[tree->correctlpdepth] <= tree->pathnlpcols[lpforkdepth]);
3572 assert(lpforkdepth == -1 || tree->pathnlprows[tree->correctlpdepth] <= tree->pathnlprows[lpforkdepth]);
3573 assert(lpforkdepth >= 0 || tree->pathnlpcols[tree->correctlpdepth] == 0);
3574 assert(lpforkdepth >= 0 || tree->pathnlprows[tree->correctlpdepth] == 0);
3576 SCIP_CALL( SCIPlpShrinkRows(lp, blkmem, set, eventqueue, eventfilter, tree->pathnlprows[tree->correctlpdepth]) );
3577 }
3578 else
3579 {
3580 /* other subtree: fill LP with the subroot LP data */
3581 SCIP_CALL( SCIPlpClear(lp, blkmem, set, eventqueue, eventfilter) );
3582 if( tree->focussubroot != NULL )
3583 {
3584 SCIP_CALL( subrootConstructLP(tree->focussubroot, blkmem, set, eventqueue, eventfilter, lp) );
3585 tree->correctlpdepth = (int) tree->focussubroot->depth;
3586 }
3587 }
3588
3589 assert(lpforkdepth < tree->pathlen);
3590
3591 /* add the missing columns and rows */
3592 for( d = tree->correctlpdepth+1; d <= lpforkdepth; ++d )
3593 {
3594 SCIP_NODE* pathnode;
3595
3596 pathnode = tree->path[d];
3597 assert(pathnode != NULL);
3598 assert((int)(pathnode->depth) == d);
3599 assert(SCIPnodeGetType(pathnode) == SCIP_NODETYPE_JUNCTION
3601 || SCIPnodeGetType(pathnode) == SCIP_NODETYPE_FORK);
3602 if( SCIPnodeGetType(pathnode) == SCIP_NODETYPE_FORK )
3603 {
3604 SCIP_CALL( forkAddLP(pathnode, blkmem, set, eventqueue, eventfilter, lp) );
3605 }
3606 else if( SCIPnodeGetType(pathnode) == SCIP_NODETYPE_PSEUDOFORK )
3607 {
3608 SCIP_CALL( pseudoforkAddLP(pathnode, blkmem, set, eventqueue, eventfilter, lp) );
3609 }
3610 }
3611 tree->correctlpdepth = MAX(tree->correctlpdepth, lpforkdepth);
3612 assert(lpforkdepth == -1 || tree->pathnlpcols[tree->correctlpdepth] == tree->pathnlpcols[lpforkdepth]);
3613 assert(lpforkdepth == -1 || tree->pathnlprows[tree->correctlpdepth] == tree->pathnlprows[lpforkdepth]);
3614 assert(lpforkdepth == -1 || SCIPlpGetNCols(lp) == tree->pathnlpcols[lpforkdepth]);
3615 assert(lpforkdepth == -1 || SCIPlpGetNRows(lp) == tree->pathnlprows[lpforkdepth]);
3616 assert(lpforkdepth >= 0 || SCIPlpGetNCols(lp) == 0);
3617 assert(lpforkdepth >= 0 || SCIPlpGetNRows(lp) == 0);
3618
3619 /* mark the LP's size, such that we know which rows and columns were added in the new node */
3620 SCIPlpMarkSize(lp);
3621
3622 SCIPsetDebugMsg(set, "-> new correctlpdepth: %d\n", tree->correctlpdepth);
3623 SCIPsetDebugMsg(set, "-> new LP has %d cols and %d rows\n", SCIPlpGetNCols(lp), SCIPlpGetNRows(lp));
3624
3625 /* if the correct LP depth is still -1, the root LP relaxation has to be initialized */
3626 *initroot = (tree->correctlpdepth == -1);
3627
3628 /* mark the LP of the focus node constructed */
3629 tree->focuslpconstructed = TRUE;
3630
3631 return SCIP_OKAY;
3632}
3633
3634/** loads LP state for fork/subroot of the focus node */
3636 SCIP_TREE* tree, /**< branch and bound tree */
3637 BMS_BLKMEM* blkmem, /**< block memory buffers */
3638 SCIP_SET* set, /**< global SCIP settings */
3639 SCIP_PROB* prob, /**< problem data */
3640 SCIP_STAT* stat, /**< dynamic problem statistics */
3641 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3642 SCIP_LP* lp /**< current LP data */
3643 )
3644{
3645 SCIP_NODE* lpstatefork;
3646 SCIP_Bool updatefeas;
3647 SCIP_Bool checkbdchgs;
3648 int lpstateforkdepth;
3649 int d;
3650
3651 assert(tree != NULL);
3652 assert(tree->focuslpconstructed);
3653 assert(tree->path != NULL);
3654 assert(tree->pathlen > 0);
3655 assert(tree->focusnode != NULL);
3656 assert(tree->correctlpdepth < tree->pathlen);
3658 assert(SCIPnodeGetDepth(tree->focusnode) == tree->pathlen-1);
3659 assert(!SCIPtreeProbing(tree));
3660 assert(tree->focusnode == tree->path[tree->pathlen-1]);
3661 assert(blkmem != NULL);
3662 assert(set != NULL);
3663 assert(lp != NULL);
3664
3665 SCIPsetDebugMsg(set, "load LP state for current fork node #%" SCIP_LONGINT_FORMAT " at depth %d\n",
3668
3669 lpstatefork = tree->focuslpstatefork;
3670
3671 /* if there is no LP state defining fork, nothing can be done */
3672 if( lpstatefork == NULL )
3673 return SCIP_OKAY;
3674
3675 /* get the lpstatefork's depth */
3676 assert(SCIPnodeGetType(lpstatefork) == SCIP_NODETYPE_FORK || SCIPnodeGetType(lpstatefork) == SCIP_NODETYPE_SUBROOT);
3677 assert(lpstatefork->active);
3678 assert(tree->path[lpstatefork->depth] == lpstatefork);
3679 lpstateforkdepth = (int) lpstatefork->depth;
3680 assert(lpstateforkdepth < tree->pathlen-1); /* lpstatefork must not be the last (the focus) node of the active path */
3681 assert(lpstateforkdepth <= tree->correctlpdepth); /* LP must have been constructed at least up to the fork depth */
3682 assert(tree->pathnlpcols[tree->correctlpdepth] >= tree->pathnlpcols[lpstateforkdepth]); /* LP can only grow */
3683 assert(tree->pathnlprows[tree->correctlpdepth] >= tree->pathnlprows[lpstateforkdepth]); /* LP can only grow */
3684
3685 /* load LP state */
3686 if( tree->focuslpstateforklpcount != stat->lpcount )
3687 {
3688 if( SCIPnodeGetType(lpstatefork) == SCIP_NODETYPE_FORK )
3689 {
3690 assert(lpstatefork->data.fork != NULL);
3691 SCIP_CALL( SCIPlpSetState(lp, blkmem, set, prob, eventqueue, lpstatefork->data.fork->lpistate,
3692 lpstatefork->data.fork->lpwasprimfeas, lpstatefork->data.fork->lpwasprimchecked,
3693 lpstatefork->data.fork->lpwasdualfeas, lpstatefork->data.fork->lpwasdualchecked) );
3694 }
3695 else
3696 {
3697 assert(SCIPnodeGetType(lpstatefork) == SCIP_NODETYPE_SUBROOT);
3698 assert(lpstatefork->data.subroot != NULL);
3699 SCIP_CALL( SCIPlpSetState(lp, blkmem, set, prob, eventqueue, lpstatefork->data.subroot->lpistate,
3700 lpstatefork->data.subroot->lpwasprimfeas, lpstatefork->data.subroot->lpwasprimchecked,
3701 lpstatefork->data.subroot->lpwasdualfeas, lpstatefork->data.subroot->lpwasdualchecked) );
3702 }
3703 updatefeas = !lp->solved || !lp->solisbasic;
3704 checkbdchgs = TRUE;
3705 }
3706 else
3707 {
3708 updatefeas = TRUE;
3709
3710 /* we do not need to check the bounds, since primalfeasible is updated anyway when flushing the LP */
3711 checkbdchgs = FALSE;
3712 }
3713
3714 if( updatefeas )
3715 {
3716 /* check whether the size of the LP increased (destroying primal/dual feasibility) */
3718 && (tree->pathnlprows[tree->correctlpdepth] == tree->pathnlprows[lpstateforkdepth]);
3720 && (tree->pathnlprows[tree->correctlpdepth] == tree->pathnlprows[lpstateforkdepth]);
3721 lp->dualfeasible = lp->dualfeasible
3722 && (tree->pathnlpcols[tree->correctlpdepth] == tree->pathnlpcols[lpstateforkdepth]);
3723 lp->dualchecked = lp->dualchecked
3724 && (tree->pathnlpcols[tree->correctlpdepth] == tree->pathnlpcols[lpstateforkdepth]);
3725
3726 /* check the path from LP fork to focus node for domain changes (destroying primal feasibility of LP basis) */
3727 if( checkbdchgs )
3728 {
3729 for( d = lpstateforkdepth; d < (int)(tree->focusnode->depth) && lp->primalfeasible; ++d )
3730 {
3731 assert(d < tree->pathlen);
3732 lp->primalfeasible = (tree->path[d]->domchg == NULL || tree->path[d]->domchg->domchgbound.nboundchgs == 0);
3733 lp->primalchecked = lp->primalfeasible;
3734 }
3735 }
3736 }
3737
3738 SCIPsetDebugMsg(set, "-> primalfeasible=%u, dualfeasible=%u\n", lp->primalfeasible, lp->dualfeasible);
3739
3740 return SCIP_OKAY;
3741}
3742
3743
3744
3745
3746/*
3747 * Node Conversion
3748 */
3749
3750/** converts node into LEAF and moves it into the array of the node queue
3751 * if node's lower bound is greater or equal than the given upper bound, the node is deleted;
3752 * otherwise, it is moved to the node queue; anyways, the given pointer is NULL after the call
3753 */
3754static
3756 SCIP_NODE** node, /**< pointer to child or sibling node to convert */
3757 BMS_BLKMEM* blkmem, /**< block memory buffers */
3758 SCIP_SET* set, /**< global SCIP settings */
3759 SCIP_STAT* stat, /**< dynamic problem statistics */
3760 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
3761 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3762 SCIP_TREE* tree, /**< branch and bound tree */
3763 SCIP_REOPT* reopt, /**< reoptimization data structure */
3764 SCIP_LP* lp, /**< current LP data */
3765 SCIP_NODE* lpstatefork, /**< LP state defining fork of the node */
3766 SCIP_Real cutoffbound /**< cutoff bound: all nodes with lowerbound >= cutoffbound are cut off */
3767 )
3768{
3771 assert(stat != NULL);
3772 assert(lpstatefork == NULL || lpstatefork->depth < (*node)->depth);
3773 assert(lpstatefork == NULL || lpstatefork->active || SCIPsetIsGE(set, (*node)->lowerbound, cutoffbound));
3774 assert(lpstatefork == NULL
3775 || SCIPnodeGetType(lpstatefork) == SCIP_NODETYPE_FORK
3776 || SCIPnodeGetType(lpstatefork) == SCIP_NODETYPE_SUBROOT);
3777
3778 /* convert node into leaf */
3779 SCIPsetDebugMsg(set, "convert node #%" SCIP_LONGINT_FORMAT " at depth %d to leaf with lpstatefork #%" SCIP_LONGINT_FORMAT " at depth %d\n",
3780 SCIPnodeGetNumber(*node), SCIPnodeGetDepth(*node),
3781 lpstatefork == NULL ? -1 : SCIPnodeGetNumber(lpstatefork),
3782 lpstatefork == NULL ? -1 : SCIPnodeGetDepth(lpstatefork));
3783 (*node)->nodetype = SCIP_NODETYPE_LEAF; /*lint !e641*/
3784 (*node)->data.leaf.lpstatefork = lpstatefork;
3785
3786#ifndef NDEBUG
3787 /* check, if the LP state fork is the first node with LP state information on the path back to the root */
3788 if( !SCIPsetIsInfinity(set, -cutoffbound) ) /* if the node was cut off in SCIPnodeFocus(), the lpstatefork is invalid */
3789 {
3790 SCIP_NODE* pathnode;
3791 pathnode = (*node)->parent;
3792 while( pathnode != NULL && pathnode != lpstatefork )
3793 {
3794 assert(SCIPnodeGetType(pathnode) == SCIP_NODETYPE_JUNCTION
3796 pathnode = pathnode->parent;
3797 }
3798 assert(pathnode == lpstatefork);
3799 }
3800#endif
3801
3802 /* if node is good enough to keep, put it on the node queue */
3803 if( !SCIPsetIsInfinity(set, (*node)->lowerbound) && SCIPsetIsLT(set, (*node)->lowerbound, cutoffbound) )
3804 {
3805 /* insert leaf in node queue */
3806 SCIP_CALL( SCIPnodepqInsert(tree->leaves, set, *node) );
3807
3808 /* make the domain change data static to save memory */
3809 SCIP_CALL( SCIPdomchgMakeStatic(&(*node)->domchg, blkmem, set, eventqueue, lp) );
3810
3811 /* node is now member of the node queue: delete the pointer to forbid further access */
3812 *node = NULL;
3813 }
3814 else
3815 {
3816 if( set->reopt_enable )
3817 {
3818 assert(reopt != NULL);
3819 /* check if the node should be stored for reoptimization */
3821 tree->root == *node, tree->focusnode == *node, (*node)->lowerbound, tree->effectiverootdepth) );
3822 }
3823
3824 /* delete node due to bound cut off */
3825 SCIPvisualCutoffNode(stat->visual, set, stat, *node, FALSE);
3826 SCIP_CALL( SCIPnodeFree(node, blkmem, set, stat, eventfilter, eventqueue, tree, lp) );
3827 }
3828 assert(*node == NULL);
3829
3830 return SCIP_OKAY;
3831}
3832
3833/** removes variables from the problem, that are marked to be deletable, and were created at the focusnode;
3834 * only removes variables that were created at the focusnode, unless inlp is TRUE (e.g., when the node is cut off, anyway)
3835 */
3836static
3838 BMS_BLKMEM* blkmem, /**< block memory buffers */
3839 SCIP_SET* set, /**< global SCIP settings */
3840 SCIP_STAT* stat, /**< dynamic problem statistics */
3841 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3842 SCIP_PROB* transprob, /**< transformed problem after presolve */
3843 SCIP_PROB* origprob, /**< original problem */
3844 SCIP_TREE* tree, /**< branch and bound tree */
3845 SCIP_REOPT* reopt, /**< reoptimization data structure */
3846 SCIP_LP* lp, /**< current LP data */
3847 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
3848 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
3849 SCIP_Bool inlp /**< should variables in the LP be deleted, too?*/
3850 )
3851{
3852 SCIP_VAR* var;
3853 int i;
3854 int ndelvars;
3855 SCIP_Bool needdel;
3856 SCIP_Bool deleted;
3857
3858 assert(blkmem != NULL);
3859 assert(set != NULL);
3860 assert(stat != NULL);
3861 assert(tree != NULL);
3862 assert(!SCIPtreeProbing(tree));
3863 assert(tree->focusnode != NULL);
3865 assert(lp != NULL);
3866
3867 /* check the settings, whether variables should be deleted */
3868 needdel = (tree->focusnode == tree->root ? set->price_delvarsroot : set->price_delvars);
3869
3870 if( !needdel )
3871 return SCIP_OKAY;
3872
3873 ndelvars = 0;
3874
3875 /* also delete variables currently in the LP, thus remove all new variables from the LP, first */
3876 if( inlp )
3877 {
3878 /* remove all additions to the LP at this node */
3880
3881 SCIP_CALL( SCIPlpFlush(lp, blkmem, set, transprob, eventqueue) );
3882 }
3883
3884 /* mark variables as deleted */
3885 for( i = 0; i < transprob->nvars; i++ )
3886 {
3887 var = transprob->vars[i];
3888 assert(var != NULL);
3889
3890 /* check whether variable is deletable */
3891 if( SCIPvarIsDeletable(var) )
3892 {
3893 if( !SCIPvarIsInLP(var) )
3894 {
3895 /* fix the variable to 0, first */
3898
3900 {
3901 SCIP_CALL( SCIPnodeAddBoundchg(tree->root, blkmem, set, stat, transprob, origprob,
3902 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 0.0, SCIP_BOUNDTYPE_LOWER, FALSE) );
3903 }
3905 {
3906 SCIP_CALL( SCIPnodeAddBoundchg(tree->root, blkmem, set, stat, transprob, origprob,
3907 tree, reopt, lp, branchcand, eventqueue, cliquetable, var, 0.0, SCIP_BOUNDTYPE_UPPER, FALSE) );
3908 }
3909
3910 SCIP_CALL( SCIPprobDelVar(transprob, blkmem, set, eventqueue, var, &deleted) );
3911
3912 if( deleted )
3913 ndelvars++;
3914 }
3915 else
3916 {
3917 /* mark variable to be non-deletable, because it will be contained in the basis information
3918 * at this node and must not be deleted from now on
3919 */
3921 }
3922 }
3923 }
3924
3925 SCIPsetDebugMsg(set, "delvars at node %" SCIP_LONGINT_FORMAT ", deleted %d vars\n", stat->nnodes, ndelvars);
3926
3927 if( ndelvars > 0 )
3928 {
3929 /* perform the variable deletions from the problem */
3930 SCIP_CALL( SCIPprobPerformVarDeletions(transprob, blkmem, set, stat, eventqueue, cliquetable, lp, branchcand) );
3931 }
3932
3933 return SCIP_OKAY;
3934}
3935
3936/** converts the focus node into a dead-end node */
3937static
3939 BMS_BLKMEM* blkmem, /**< block memory buffers */
3940 SCIP_SET* set, /**< global SCIP settings */
3941 SCIP_STAT* stat, /**< dynamic problem statistics */
3942 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3943 SCIP_PROB* transprob, /**< transformed problem after presolve */
3944 SCIP_PROB* origprob, /**< original problem */
3945 SCIP_TREE* tree, /**< branch and bound tree */
3946 SCIP_REOPT* reopt, /**< reoptimization data structure */
3947 SCIP_LP* lp, /**< current LP data */
3948 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
3949 SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
3950 )
3951{
3952 assert(blkmem != NULL);
3953 assert(tree != NULL);
3954 assert(!SCIPtreeProbing(tree));
3955 assert(tree->focusnode != NULL);
3957 assert(tree->nchildren == 0);
3958
3959 SCIPsetDebugMsg(set, "focusnode #%" SCIP_LONGINT_FORMAT " to dead-end at depth %d\n",
3961
3962 /* remove variables from the problem that are marked as deletable and were created at this node */
3963 SCIP_CALL( focusnodeCleanupVars(blkmem, set, stat, eventqueue, transprob, origprob, tree, reopt, lp, branchcand, cliquetable, TRUE) );
3964
3965 tree->focusnode->nodetype = SCIP_NODETYPE_DEADEND; /*lint !e641*/
3966
3967 /* release LPI state */
3968 if( tree->focuslpstatefork != NULL )
3969 {
3971 }
3972
3973 return SCIP_OKAY;
3974}
3975
3976/** converts the focus node into a leaf node (if it was postponed) */
3977static
3979 BMS_BLKMEM* blkmem, /**< block memory buffers */
3980 SCIP_SET* set, /**< global SCIP settings */
3981 SCIP_STAT* stat, /**< dynamic problem statistics */
3982 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
3983 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3984 SCIP_TREE* tree, /**< branch and bound tree */
3985 SCIP_REOPT* reopt, /**< reoptimization data structure */
3986 SCIP_LP* lp, /**< current LP data */
3987 SCIP_NODE* lpstatefork, /**< LP state defining fork of the node */
3988 SCIP_Real cutoffbound /**< cutoff bound: all nodes with lowerbound >= cutoffbound are cut off */
3989
3990 )
3991{
3992 assert(tree != NULL);
3993 assert(!SCIPtreeProbing(tree));
3994 assert(tree->focusnode != NULL);
3995 assert(tree->focusnode->active);
3997
3998 SCIPsetDebugMsg(set, "focusnode #%" SCIP_LONGINT_FORMAT " to leaf at depth %d\n",
4000
4001 SCIP_CALL( nodeToLeaf(&tree->focusnode, blkmem, set, stat, eventfilter, eventqueue, tree, reopt, lp, lpstatefork, cutoffbound));
4002
4003 return SCIP_OKAY;
4004}
4005
4006/** converts the focus node into a junction node */
4007static
4009 BMS_BLKMEM* blkmem, /**< block memory buffers */
4010 SCIP_SET* set, /**< global SCIP settings */
4011 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
4012 SCIP_TREE* tree, /**< branch and bound tree */
4013 SCIP_LP* lp /**< current LP data */
4014 )
4015{
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 */
4021 assert(SCIPlpGetNNewcols(lp) == 0);
4022
4023 SCIPsetDebugMsg(set, "focusnode #%" SCIP_LONGINT_FORMAT " to junction at depth %d\n",
4025
4026 /* convert node into junction */
4027 tree->focusnode->nodetype = SCIP_NODETYPE_JUNCTION; /*lint !e641*/
4028
4029 SCIP_CALL( junctionInit(&tree->focusnode->data.junction, tree) );
4030
4031 /* release LPI state */
4032 if( tree->focuslpstatefork != NULL )
4033 {
4035 }
4036
4037 /* make the domain change data static to save memory */
4038 SCIP_CALL( SCIPdomchgMakeStatic(&tree->focusnode->domchg, blkmem, set, eventqueue, lp) );
4039
4040 return SCIP_OKAY;
4041}
4042
4043/** converts the focus node into a pseudofork node */
4044static
4046 BMS_BLKMEM* blkmem, /**< block memory buffers */
4047 SCIP_SET* set, /**< global SCIP settings */
4048 SCIP_STAT* stat, /**< dynamic problem statistics */
4049 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
4050 SCIP_PROB* transprob, /**< transformed problem after presolve */
4051 SCIP_PROB* origprob, /**< original problem */
4052 SCIP_TREE* tree, /**< branch and bound tree */
4053 SCIP_REOPT* reopt, /**< reoptimization data structure */
4054 SCIP_LP* lp, /**< current LP data */
4055 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
4056 SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
4057 )
4058{
4059 SCIP_PSEUDOFORK* pseudofork;
4060
4061 assert(blkmem != NULL);
4062 assert(tree != NULL);
4063 assert(!SCIPtreeProbing(tree));
4064 assert(tree->focusnode != NULL);
4065 assert(tree->focusnode->active); /* otherwise, no children could be created at the focus node */
4067 assert(tree->nchildren > 0);
4068 assert(lp != NULL);
4069
4070 SCIPsetDebugMsg(set, "focusnode #%" SCIP_LONGINT_FORMAT " to pseudofork at depth %d\n",
4072
4073 /* remove variables from the problem that are marked as deletable and were created at this node */
4074 SCIP_CALL( focusnodeCleanupVars(blkmem, set, stat, eventqueue, transprob, origprob, tree, reopt, lp, branchcand, cliquetable, FALSE) );
4075
4076 /* create pseudofork data */
4077 SCIP_CALL( pseudoforkCreate(&pseudofork, blkmem, tree, lp) );
4078
4079 tree->focusnode->nodetype = SCIP_NODETYPE_PSEUDOFORK; /*lint !e641*/
4080 tree->focusnode->data.pseudofork = pseudofork;
4081
4082 /* release LPI state */
4083 if( tree->focuslpstatefork != NULL )
4084 {
4086 }
4087
4088 /* make the domain change data static to save memory */
4089 SCIP_CALL( SCIPdomchgMakeStatic(&tree->focusnode->domchg, blkmem, set, eventqueue, lp) );
4090
4091 return SCIP_OKAY;
4092}
4093
4094/** converts the focus node into a fork node */
4095static
4097 BMS_BLKMEM* blkmem, /**< block memory buffers */
4098 SCIP_SET* set, /**< global SCIP settings */
4099 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
4100 SCIP_STAT* stat, /**< dynamic problem statistics */
4101 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
4102 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
4103 SCIP_PROB* transprob, /**< transformed problem after presolve */
4104 SCIP_PROB* origprob, /**< original problem */
4105 SCIP_TREE* tree, /**< branch and bound tree */
4106 SCIP_REOPT* reopt, /**< reoptimization data structure */
4107 SCIP_LP* lp, /**< current LP data */
4108 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
4109 SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
4110 )
4111{
4112 SCIP_FORK* fork;
4113 SCIP_Bool lperror;
4114
4115 assert(blkmem != NULL);
4116 assert(tree != NULL);
4117 assert(!SCIPtreeProbing(tree));
4118 assert(tree->focusnode != NULL);
4119 assert(tree->focusnode->active); /* otherwise, no children could be created at the focus node */
4121 assert(tree->nchildren > 0);
4122 assert(lp != NULL);
4123 assert(lp->flushed);
4124 assert(lp->solved || lp->resolvelperror);
4125
4126 SCIPsetDebugMsg(set, "focusnode #%" SCIP_LONGINT_FORMAT " to fork at depth %d\n",
4128
4129 /* usually, the LP should be solved to optimality; otherwise, numerical troubles occured,
4130 * and we have to forget about the LP and transform the node into a junction (see below)
4131 */
4132 lperror = FALSE;
4134 {
4135 /* clean up newly created part of LP to keep only necessary columns and rows */
4136 SCIP_CALL( SCIPlpCleanupNew(lp, blkmem, set, stat, eventqueue, eventfilter, (tree->focusnode->depth == 0)) );
4137
4138 /* resolve LP after cleaning up */
4139 SCIPsetDebugMsg(set, "resolving LP after cleanup\n");
4140 SCIP_CALL( SCIPlpSolveAndEval(lp, set, messagehdlr, blkmem, stat, eventqueue, eventfilter, transprob, -1LL, FALSE, FALSE, TRUE, &lperror) );
4141 }
4142 assert(lp->flushed);
4143 assert(lp->solved || lperror || lp->resolvelperror);
4144
4145 /* There are two reasons, that the (reduced) LP is not solved to optimality:
4146 * - The primal heuristics (called after the current node's LP was solved) found a new
4147 * solution, that is better than the current node's lower bound.
4148 * (But in this case, all children should be cut off and the node should be converted
4149 * into a dead-end instead of a fork.)
4150 * - Something numerically weird happened after cleaning up or after resolving a diving or probing LP.
4151 * The only thing we can do, is to completely forget about the LP and treat the node as
4152 * if it was only a pseudo-solution node. Therefore we have to remove all additional
4153 * columns and rows from the LP and convert the node into a junction.
4154 * However, the node's lower bound is kept, thus automatically throwing away nodes that
4155 * were cut off due to a primal solution.
4156 */
4157 if( lperror || lp->resolvelperror || SCIPlpGetSolstat(lp) != SCIP_LPSOLSTAT_OPTIMAL )
4158 {
4159 SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
4160 "(node %" SCIP_LONGINT_FORMAT ") numerical troubles: LP %" SCIP_LONGINT_FORMAT " not optimal -- convert node into junction instead of fork\n",
4161 stat->nnodes, stat->nlps);
4162
4163 /* remove all additions to the LP at this node */
4165 SCIP_CALL( SCIPlpShrinkRows(lp, blkmem, set, eventqueue, eventfilter, SCIPlpGetNRows(lp) - SCIPlpGetNNewrows(lp)) );
4166
4167 /* convert node into a junction */
4168 SCIP_CALL( focusnodeToJunction(blkmem, set, eventqueue, tree, lp) );
4169
4170 return SCIP_OKAY;
4171 }
4172 assert(lp->flushed);
4173 assert(lp->solved);
4175
4176 /* remove variables from the problem that are marked as deletable, were created at this node and are not contained in the LP */
4177 SCIP_CALL( focusnodeCleanupVars(blkmem, set, stat, eventqueue, transprob, origprob, tree, reopt, lp, branchcand, cliquetable, FALSE) );
4178
4179 assert(lp->flushed);
4180 assert(lp->solved);
4181
4182 /* create fork data */
4183 SCIP_CALL( forkCreate(&fork, blkmem, set, transprob, tree, lp) );
4184
4185 tree->focusnode->nodetype = SCIP_NODETYPE_FORK; /*lint !e641*/
4186 tree->focusnode->data.fork = fork;
4187
4188 /* capture the LPI state of the root node to ensure that the LPI state of the root stays for the whole solving
4189 * process
4190 */
4191 if( tree->focusnode == tree->root )
4192 forkCaptureLPIState(fork, 1);
4193
4194 /* release LPI state */
4195 if( tree->focuslpstatefork != NULL )
4196 {
4198 }
4199
4200 /* make the domain change data static to save memory */
4201 SCIP_CALL( SCIPdomchgMakeStatic(&tree->focusnode->domchg, blkmem, set, eventqueue, lp) );
4202
4203 return SCIP_OKAY;
4204}
4205
4206#ifdef WITHSUBROOTS /** @todo test whether subroots should be created */
4207/** converts the focus node into a subroot node */
4208static
4209SCIP_RETCODE focusnodeToSubroot(
4210 BMS_BLKMEM* blkmem, /**< block memory buffers */
4211 SCIP_SET* set, /**< global SCIP settings */
4212 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
4213 SCIP_STAT* stat, /**< dynamic problem statistics */
4214 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
4215 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
4216 SCIP_PROB* transprob, /**< transformed problem after presolve */
4217 SCIP_PROB* origprob, /**< original problem */
4218 SCIP_TREE* tree, /**< branch and bound tree */
4219 SCIP_LP* lp, /**< current LP data */
4220 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
4221 SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
4222 )
4223{
4224 SCIP_SUBROOT* subroot;
4225 SCIP_Bool lperror;
4226
4227 assert(blkmem != NULL);
4228 assert(tree != NULL);
4229 assert(!SCIPtreeProbing(tree));
4230 assert(tree->focusnode != NULL);
4232 assert(tree->focusnode->active); /* otherwise, no children could be created at the focus node */
4233 assert(tree->nchildren > 0);
4234 assert(lp != NULL);
4235 assert(lp->flushed);
4236 assert(lp->solved);
4237
4238 SCIPsetDebugMsg(set, "focusnode #%" SCIP_LONGINT_FORMAT " to subroot at depth %d\n",
4240
4241 /* usually, the LP should be solved to optimality; otherwise, numerical troubles occured,
4242 * and we have to forget about the LP and transform the node into a junction (see below)
4243 */
4244 lperror = FALSE;
4246 {
4247 /* clean up whole LP to keep only necessary columns and rows */
4248#ifdef SCIP_DISABLED_CODE
4249 if( tree->focusnode->depth == 0 )
4250 {
4251 SCIP_CALL( SCIPlpCleanupAll(lp, blkmem, set, stat, eventqueue, eventfilter, (tree->focusnode->depth == 0)) );
4252 }
4253 else
4254#endif
4255 {
4256 SCIP_CALL( SCIPlpRemoveAllObsoletes(lp, blkmem, set, stat, eventqueue, eventfilter) );
4257 }
4258
4259 /* resolve LP after cleaning up */
4260 SCIPsetDebugMsg(set, "resolving LP after cleanup\n");
4261 SCIP_CALL( SCIPlpSolveAndEval(lp, set, messagehdlr, blkmem, stat, eventqueue, eventfilter, transprob, -1LL, FALSE, FALSE, TRUE, &lperror) );
4262 }
4263 assert(lp->flushed);
4264 assert(lp->solved || lperror);
4265
4266 /* There are two reasons, that the (reduced) LP is not solved to optimality:
4267 * - The primal heuristics (called after the current node's LP was solved) found a new
4268 * solution, that is better than the current node's lower bound.
4269 * (But in this case, all children should be cut off and the node should be converted
4270 * into a dead-end instead of a subroot.)
4271 * - Something numerically weird happened after cleaning up.
4272 * The only thing we can do, is to completely forget about the LP and treat the node as
4273 * if it was only a pseudo-solution node. Therefore we have to remove all additional
4274 * columns and rows from the LP and convert the node into a junction.
4275 * However, the node's lower bound is kept, thus automatically throwing away nodes that
4276 * were cut off due to a primal solution.
4277 */
4278 if( lperror || SCIPlpGetSolstat(lp) != SCIP_LPSOLSTAT_OPTIMAL )
4279 {
4280 SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
4281 "(node %" SCIP_LONGINT_FORMAT ") numerical troubles: LP %" SCIP_LONGINT_FORMAT " not optimal -- convert node into junction instead of subroot\n",
4282 stat->nnodes, stat->nlps);
4283
4284 /* remove all additions to the LP at this node */
4286 SCIP_CALL( SCIPlpShrinkRows(lp, blkmem, set, eventqueue, eventfilter, SCIPlpGetNRows(lp) - SCIPlpGetNNewrows(lp)) );
4287
4288 /* convert node into a junction */
4289 SCIP_CALL( focusnodeToJunction(blkmem, set, eventqueue, tree, lp) );
4290
4291 return SCIP_OKAY;
4292 }
4293 assert(lp->flushed);
4294 assert(lp->solved);
4296
4297 /* remove variables from the problem that are marked as deletable, were created at this node and are not contained in the LP */
4298 SCIP_CALL( focusnodeCleanupVars(blkmem, set, stat, eventqueue, transprob, origprob, tree, lp, branchcand, cliquetable, FALSE) );
4299
4300 assert(lp->flushed);
4301 assert(lp->solved);
4302
4303 /* create subroot data */
4304 SCIP_CALL( subrootCreate(&subroot, blkmem, set, transprob, tree, lp) );
4305
4306 tree->focusnode->nodetype = SCIP_NODETYPE_SUBROOT; /*lint !e641*/
4307 tree->focusnode->data.subroot = subroot;
4308
4309 /* update the LP column and row counter for the converted node */
4311
4312 /* release LPI state */
4313 if( tree->focuslpstatefork != NULL )
4314 {
4316 }
4317
4318 /* make the domain change data static to save memory */
4319 SCIP_CALL( SCIPdomchgMakeStatic(&tree->focusnode->domchg, blkmem, set, eventqueue, lp) );
4320
4321 return SCIP_OKAY;
4322}
4323#endif
4324
4325/** puts all nodes in the array on the node queue and makes them LEAFs */
4326static
4328 SCIP_TREE* tree, /**< branch and bound tree */
4329 SCIP_REOPT* reopt, /**< reoptimization data structure */
4330 BMS_BLKMEM* blkmem, /**< block memory buffers */
4331 SCIP_SET* set, /**< global SCIP settings */
4332 SCIP_STAT* stat, /**< dynamic problem statistics */
4333 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
4334 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
4335 SCIP_LP* lp, /**< current LP data */
4336 SCIP_NODE** nodes, /**< array of nodes to put on the queue */
4337 int* nnodes, /**< pointer to number of nodes in the array */
4338 SCIP_NODE* lpstatefork, /**< LP state defining fork of the nodes */
4339 SCIP_Real cutoffbound /**< cutoff bound: all nodes with lowerbound >= cutoffbound are cut off */
4340 )
4341{
4342 int i;
4343
4344 assert(tree != NULL);
4345 assert(set != NULL);
4346 assert(nnodes != NULL);
4347 assert(*nnodes == 0 || nodes != NULL);
4348
4349 for( i = *nnodes; --i >= 0; )
4350 {
4351 /* convert node to LEAF and put it into leaves queue, or delete it if it's lower bound exceeds the cutoff bound */
4352 SCIP_CALL( nodeToLeaf(&nodes[i], blkmem, set, stat, eventfilter, eventqueue, tree, reopt, lp, lpstatefork, cutoffbound) );
4353 assert(nodes[i] == NULL);
4354 --(*nnodes);
4355 }
4356
4357 return SCIP_OKAY;
4358}
4359
4360/** converts children into siblings, clears children array */
4361static
4363 SCIP_TREE* tree /**< branch and bound tree */
4364 )
4365{
4366 SCIP_NODE** tmpnodes;
4367 SCIP_Real* tmpprios;
4368 int tmpnodessize;
4369 int i;
4370
4371 assert(tree != NULL);
4372 assert(tree->nsiblings == 0);
4373
4374 tmpnodes = tree->siblings;
4375 tmpprios = tree->siblingsprio;
4376 tmpnodessize = tree->siblingssize;
4377
4378 tree->siblings = tree->children;
4379 tree->siblingsprio = tree->childrenprio;
4380 tree->nsiblings = tree->nchildren;
4381 tree->siblingssize = tree->childrensize;
4382
4383 tree->children = tmpnodes;
4384 tree->childrenprio = tmpprios;
4385 tree->nchildren = 0;
4386 tree->childrensize = tmpnodessize;
4387
4388 for( i = 0; i < tree->nsiblings; ++i )
4389 {
4390 assert(SCIPnodeGetType(tree->siblings[i]) == SCIP_NODETYPE_CHILD);
4391 tree->siblings[i]->nodetype = SCIP_NODETYPE_SIBLING; /*lint !e641*/
4392
4393 /* because CHILD and SIBLING structs contain the same data in the same order, we do not have to copy it */
4394 assert(&(tree->siblings[i]->data.sibling.arraypos) == &(tree->siblings[i]->data.child.arraypos));
4395 }
4396}
4397
4398/** installs a child, a sibling, or a leaf node as the new focus node */
4400 SCIP_NODE** node, /**< pointer to node to focus (or NULL to remove focus); the node
4401 * is freed, if it was cut off due to a cut off subtree */
4402 BMS_BLKMEM* blkmem, /**< block memory buffers */
4403 SCIP_SET* set, /**< global SCIP settings */
4404 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
4405 SCIP_STAT* stat, /**< problem statistics */
4406 SCIP_PROB* transprob, /**< transformed problem */
4407 SCIP_PROB* origprob, /**< original problem */
4408 SCIP_PRIMAL* primal, /**< primal data */
4409 SCIP_TREE* tree, /**< branch and bound tree */
4410 SCIP_REOPT* reopt, /**< reoptimization data structure */
4411 SCIP_LP* lp, /**< current LP data */
4412 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
4413 SCIP_CONFLICT* conflict, /**< conflict analysis data */
4414 SCIP_CONFLICTSTORE* conflictstore, /**< conflict store */
4415 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
4416 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
4417 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
4418 SCIP_Bool* cutoff, /**< pointer to store whether the given node can be cut off */
4419 SCIP_Bool postponed, /**< was the current focus node postponed? */
4420 SCIP_Bool exitsolve /**< are we in exitsolve stage, so we only need to loose the children */
4421 )
4422{ /*lint --e{715}*/
4423 SCIP_NODE* fork;
4424 SCIP_NODE* lpfork;
4425 SCIP_NODE* lpstatefork;
4426 SCIP_NODE* subroot;
4427 SCIP_NODE* childrenlpstatefork;
4428 int oldcutoffdepth;
4429
4430 assert(node != NULL);
4431 assert(*node == NULL
4434 || SCIPnodeGetType(*node) == SCIP_NODETYPE_LEAF);
4435 assert(*node == NULL || !(*node)->active);
4436 assert(stat != NULL);
4437 assert(tree != NULL);
4438 assert(!SCIPtreeProbing(tree));
4439 assert(lp != NULL);
4440 assert(conflictstore != NULL);
4441 assert(cutoff != NULL);
4442
4443 /* check global lower bound w.r.t. debugging solution */
4445
4446 /* check local lower bound w.r.t. debugging solution */
4447 SCIP_CALL( SCIPdebugCheckLocalLowerbound(blkmem, set, *node) );
4448
4449 SCIPsetDebugMsg(set, "focusing node #%" SCIP_LONGINT_FORMAT " of type %d in depth %d\n",
4450 *node != NULL ? SCIPnodeGetNumber(*node) : -1, *node != NULL ? (int)SCIPnodeGetType(*node) : 0,
4451 *node != NULL ? SCIPnodeGetDepth(*node) : -1);
4452
4453 /* remember old cutoff depth in order to know, whether the children and siblings can be deleted */
4454 oldcutoffdepth = tree->cutoffdepth;
4455
4456 /* find the common fork node, the new LP defining fork, and the new focus subroot,
4457 * thereby checking, if the new node can be cut off
4458 */
4459 treeFindSwitchForks(tree, *node, &fork, &lpfork, &lpstatefork, &subroot, cutoff);
4460 SCIPsetDebugMsg(set, "focus node: focusnodedepth=%ld, forkdepth=%ld, lpforkdepth=%ld, lpstateforkdepth=%ld, subrootdepth=%ld, cutoff=%u\n",
4461 *node != NULL ? (long)((*node)->depth) : -1, fork != NULL ? (long)(fork->depth) : -1, /*lint !e705 */
4462 lpfork != NULL ? (long)(lpfork->depth) : -1, lpstatefork != NULL ? (long)(lpstatefork->depth) : -1, /*lint !e705 */
4463 subroot != NULL ? (long)(subroot->depth) : -1, *cutoff); /*lint !e705 */
4464
4465 /* free the new node, if it is located in a cut off subtree */
4466 if( *cutoff )
4467 {
4468 assert(*node != NULL);
4469 assert(tree->cutoffdepth == oldcutoffdepth);
4470 if( SCIPnodeGetType(*node) == SCIP_NODETYPE_LEAF )
4471 {
4472 SCIP_CALL( SCIPnodepqRemove(tree->leaves, set, *node) );
4473 }
4474 SCIPvisualCutoffNode(stat->visual, set, stat, *node, FALSE);
4475
4476 if( set->reopt_enable )
4477 {
4478 assert(reopt != NULL);
4479 /* check if the node should be stored for reoptimization */
4481 tree->root == (*node), tree->focusnode == (*node), (*node)->lowerbound, tree->effectiverootdepth) );
4482 }
4483
4484 SCIP_CALL( SCIPnodeFree(node, blkmem, set, stat, eventfilter, eventqueue, tree, lp) );
4485
4486 return SCIP_OKAY;
4487 }
4488
4489 assert(tree->cutoffdepth == INT_MAX);
4490 assert(fork == NULL || fork->active);
4491 assert(lpstatefork == NULL || lpfork != NULL);
4492 assert(subroot == NULL || lpstatefork != NULL);
4493
4494 /* remember the depth of the common fork node for LP updates */
4495 SCIPsetDebugMsg(set, "focus node: old correctlpdepth=%d\n", tree->correctlpdepth);
4496 if( subroot == tree->focussubroot && fork != NULL && lpfork != NULL )
4497 {
4498 /* we are in the same subtree with valid LP fork: the LP is correct at most upto the common fork depth */
4499 assert(subroot == NULL || subroot->active);
4500 tree->correctlpdepth = MIN(tree->correctlpdepth, (int)fork->depth);
4501 }
4502 else
4503 {
4504 /* we are in a different subtree, or no valid LP fork exists: the LP is completely incorrect */
4505 assert(subroot == NULL || !subroot->active
4506 || (tree->focussubroot != NULL && tree->focussubroot->depth > subroot->depth));
4507 tree->correctlpdepth = -1;
4508 }
4509
4510 /* if the LP state fork changed, the lpcount information for the new LP state fork is unknown */
4511 if( lpstatefork != tree->focuslpstatefork )
4512 tree->focuslpstateforklpcount = -1;
4513
4514 /* in exitsolve we only need to take care of open children
4515 *
4516 * @note because we might do a 'newstart' and converted cuts to constraints might have rendered the LP in the current
4517 * focusnode unsolved the latter code would have resolved the LP unnecessarily
4518 */
4519 if( exitsolve && tree->nchildren > 0 )
4520 {
4521 SCIPsetDebugMsg(set, " -> deleting the %d children (in exitsolve) of the old focus node\n", tree->nchildren);
4522 SCIP_CALL( treeNodesToQueue(tree, reopt, blkmem, set, stat, eventfilter, eventqueue, lp, tree->children, &tree->nchildren, NULL, -SCIPsetInfinity(