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