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