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