Scippy

SCIP

Solving Constraint Integer Programs

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