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