Scippy

SCIP

Solving Constraint Integer Programs

solve.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2024 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file solve.c
26 * @ingroup OTHER_CFILES
27 * @brief main solving loop and node processing
28 * @author Tobias Achterberg
29 * @author Timo Berthold
30 * @author Marc Pfetsch
31 * @author Gerald Gamrath
32 */
33
34/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35#include <assert.h>
36
37#include "lpi/lpi.h"
38#include "scip/branch.h"
39#include "scip/clock.h"
40#include "scip/concurrent.h"
41#include "scip/conflict.h"
42#include "scip/cons.h"
43#include "scip/cutpool.h"
44#include "scip/disp.h"
45#include "scip/event.h"
46#include "scip/heur.h"
47#include "scip/interrupt.h"
48#include "scip/lp.h"
49#include "scip/nodesel.h"
50#include "scip/pricer.h"
51#include "scip/pricestore.h"
52#include "scip/primal.h"
53#include "scip/prob.h"
54#include "scip/prop.h"
55#include "scip/pub_cons.h"
56#include "scip/pub_heur.h"
57#include "scip/pub_message.h"
58#include "scip/pub_misc.h"
59#include "scip/pub_pricer.h"
60#include "scip/pub_prop.h"
61#include "scip/pub_relax.h"
62#include "scip/pub_sepa.h"
63#include "scip/pub_tree.h"
64#include "scip/pub_var.h"
65#include "scip/relax.h"
66#include "scip/reopt.h"
68#include "scip/scip_mem.h"
69#include "scip/scip_prob.h"
70#include "scip/scip_sol.h"
72#include "scip/sepa.h"
73#include "scip/sepastore.h"
74#include "scip/set.h"
75#include "scip/sol.h"
76#include "scip/solve.h"
77#include "scip/stat.h"
78#include "scip/struct_cons.h"
79#include "scip/struct_event.h"
80#include "scip/struct_lp.h"
81#include "scip/struct_mem.h"
82#include "scip/struct_primal.h"
83#include "scip/struct_prob.h"
84#include "scip/struct_set.h"
85#include "scip/struct_stat.h"
86#include "scip/struct_tree.h"
87#include "scip/struct_var.h"
88#include "scip/syncstore.h"
89#include "scip/tree.h"
90#include "scip/var.h"
91#include "scip/visual.h"
92
93
94#define MAXNLPERRORS 10 /**< maximal number of LP error loops in a single node */
95#define MAXNCLOCKSKIPS 64 /**< maximum number of SCIPsolveIsStopped() calls without checking the clock */
96#define NINITCALLS 1000L /**< minimum number of calls to SCIPsolveIsStopped() prior to dynamic clock skips */
97#define SAFETYFACTOR 1e-2 /**< the probability that SCIP skips the clock call after the time limit has already been reached */
98
99/** returns whether the solving process will be / was stopped before proving optimality;
100 * if the solving process was stopped, stores the reason as status in stat
101 */
103 SCIP_SET* set, /**< global SCIP settings */
104 SCIP_STAT* stat, /**< dynamic problem statistics */
105 SCIP_Bool checknodelimits /**< should the node limits be involved in the check? */
106 )
107{
108 assert(set != NULL);
109 assert(stat != NULL);
110
111 /* increase the number of calls to this method */
112 SCIPstatIncrement(stat, set, nisstoppedcalls);
113
114 /* in case lowerbound >= upperbound, we do not want to terminate with SCIP_STATUS_GAPLIMIT but with the ordinary
115 * SCIP_STATUS_OPTIMAL/INFEASIBLE/...
116 */
118 return TRUE;
119
120 /* if some limit has been changed since the last call, we reset the status */
121 if( set->limitchanged )
122 {
124 set->limitchanged = FALSE;
125 }
126
127 if( SCIPinterrupted() || stat->userinterrupt )
128 {
130 stat->userinterrupt = FALSE;
131
132 /* only reset the interrupted counter if this is the main SCIP catching CTRL-C */
133 if( set->misc_catchctrlc )
134 {
136 }
137 }
138 else if( SCIPterminated() )
139 {
141
142 return TRUE;
143 }
144 /* only measure the clock if a time limit is set */
145 else if( set->istimelimitfinite )
146 {
147 /* check if we have already called this function sufficiently often for a valid estimation of its average call interval */
148 if( stat->nclockskipsleft <= 0 || stat->nisstoppedcalls < NINITCALLS )
149 {
150 SCIP_Real currtime = SCIPclockGetTime(stat->solvingtime);
151
152 /* use the measured time to update the average time interval between two calls to this method */
153 if( set->time_rareclockcheck && stat->nisstoppedcalls >= NINITCALLS )
154 {
155 SCIP_Real avgisstoppedfreq;
156 int nclockskips = MAXNCLOCKSKIPS;
157
158 avgisstoppedfreq = currtime / stat->nisstoppedcalls;
159
160 /* if we are approaching the time limit, reset the number of clock skips to 0 */
161 if( (SAFETYFACTOR * (set->limit_time - currtime) / (avgisstoppedfreq + 1e-6)) < nclockskips )
162 nclockskips = 0;
163
164 stat->nclockskipsleft = nclockskips;
165 }
166 else
167 stat->nclockskipsleft = 0;
168
169 /* set the status if the time limit was hit */
170 if( currtime >= set->limit_time )
171 {
173 return TRUE;
174 }
175 }
176 else if( SCIPclockGetLastTime(stat->solvingtime) >= set->limit_time )
177 {
178 /* use information if clock has been updated more recently */
180 return TRUE;
181 }
182 else
183 --stat->nclockskipsleft;
184 }
185 if( SCIPgetConcurrentMemTotal(set->scip) >= set->limit_memory*1048576.0 - stat->externmemestim * (1.0 + SCIPgetNConcurrentSolvers(set->scip)) )
187 else if( SCIPgetNLimSolsFound(set->scip) > 0
188 && (SCIPsetIsLT(set, SCIPgetGap(set->scip), set->limit_gap)
189 || SCIPsetIsLT(set, (SCIPgetUpperbound(set->scip) - SCIPgetLowerbound(set->scip)) * SCIPgetTransObjscale(set->scip), set->limit_absgap )) )
191 else if( set->limit_primal != SCIP_INVALID && !SCIPsetIsPositive(set, (int)SCIPgetObjsense(set->scip) * (SCIPgetPrimalbound(set->scip) - set->limit_primal)) ) /*lint !e777*/
193 else if( set->limit_dual != SCIP_INVALID && !SCIPsetIsNegative(set, (int)SCIPgetObjsense(set->scip) * (SCIPgetDualbound(set->scip) - set->limit_dual)) ) /*lint !e777*/
195 else if( set->limit_solutions >= 0 && set->stage >= SCIP_STAGE_PRESOLVING
196 && SCIPgetNLimSolsFound(set->scip) >= set->limit_solutions )
198 else if( set->limit_bestsol >= 0 && set->stage >= SCIP_STAGE_PRESOLVING
199 && SCIPgetNBestSolsFound(set->scip) >= set->limit_bestsol )
201 else if( checknodelimits && set->limit_nodes >= 0 && stat->nnodes >= set->limit_nodes )
203 else if( checknodelimits && set->limit_totalnodes >= 0 && stat->ntotalnodes >= set->limit_totalnodes )
205 else if( checknodelimits && set->limit_stallnodes >= 0 && stat->nnodes >= stat->bestsolnode + set->limit_stallnodes )
207
208 /* If stat->status was initialized to SCIP_STATUS_NODELIMIT or SCIP_STATUS_STALLNODELIMIT due to a previous call to SCIPsolveIsStopped(,,TRUE),
209 * in the case of checknodelimits == FALSE, we do not want to report here that the solve will be stopped due to a nodelimit.
210 */
211 if( !checknodelimits )
213 else
215}
216
217/** calls primal heuristics */
219 SCIP_SET* set, /**< global SCIP settings */
220 SCIP_STAT* stat, /**< dynamic problem statistics */
221 SCIP_PROB* prob, /**< transformed problem after presolve */
222 SCIP_PRIMAL* primal, /**< primal data */
223 SCIP_TREE* tree, /**< branch and bound tree, or NULL if called during presolving */
224 SCIP_LP* lp, /**< LP data, or NULL if called during presolving or propagation */
225 SCIP_NODE* nextnode, /**< next node that will be processed, or NULL if no more nodes left
226 * (only needed when calling after node heuristics) */
227 SCIP_HEURTIMING heurtiming, /**< current point in the node solving process */
228 SCIP_Bool nodeinfeasible, /**< was the current node already detected to be infeasible? */
229 SCIP_Bool* foundsol, /**< pointer to store whether a solution has been found */
230 SCIP_Bool* unbounded /**< pointer to store whether an unbounded ray was found in the LP */
231 )
232{ /*lint --e{715}*/
233 SCIP_RESULT result;
234 SCIP_Longint oldnbestsolsfound;
235 SCIP_Real lowerbound;
236 int ndelayedheurs;
237 int depth;
238 int lpstateforkdepth;
239 int h;
240#ifndef NDEBUG
241 SCIP_Bool inprobing;
242 SCIP_Bool indiving;
243#endif
244
245 assert(set != NULL);
246 assert(primal != NULL);
247 assert(tree != NULL || heurtiming == SCIP_HEURTIMING_BEFOREPRESOL || heurtiming == SCIP_HEURTIMING_DURINGPRESOLLOOP);
248 assert(lp != NULL || heurtiming == SCIP_HEURTIMING_BEFOREPRESOL || heurtiming == SCIP_HEURTIMING_DURINGPRESOLLOOP
249 || heurtiming == SCIP_HEURTIMING_AFTERPROPLOOP);
250 assert(heurtiming == SCIP_HEURTIMING_BEFORENODE || heurtiming == SCIP_HEURTIMING_DURINGLPLOOP
251 || heurtiming == SCIP_HEURTIMING_AFTERLPLOOP || heurtiming == SCIP_HEURTIMING_AFTERNODE
255 assert(heurtiming != SCIP_HEURTIMING_AFTERNODE || (nextnode == NULL) == (SCIPtreeGetNNodes(tree) == 0));
256 assert(foundsol != NULL);
257
258 *foundsol = FALSE;
259
260 /* nothing to do, if no heuristics are available, or if the branch-and-bound process is finished */
261 if( set->nheurs == 0 || (heurtiming == SCIP_HEURTIMING_AFTERNODE && nextnode == NULL) )
262 return SCIP_OKAY;
263
264 /* do not continue if we reached a time limit */
265 if( SCIPsolveIsStopped(set, stat, FALSE) )
266 return SCIP_OKAY;
267
268 /* sort heuristics by priority, but move the delayed heuristics to the front */
270
271 /* specialize the AFTERNODE timing flag */
273 {
274 SCIP_Bool plunging;
275 SCIP_Bool pseudonode;
276
277 /* clear the AFTERNODE flags and replace them by the right ones */
278 heurtiming &= ~SCIP_HEURTIMING_AFTERNODE;
279
280 /* we are in plunging mode iff the next node is a sibling or a child, and no leaf */
281 assert(nextnode == NULL
284 || SCIPnodeGetType(nextnode) == SCIP_NODETYPE_LEAF);
285 plunging = (nextnode != NULL && SCIPnodeGetType(nextnode) != SCIP_NODETYPE_LEAF);
286 pseudonode = !SCIPtreeHasFocusNodeLP(tree);
287 if( plunging && SCIPtreeGetCurrentDepth(tree) > 0 ) /* call plunging heuristics also at root node */
288 {
289 if( !pseudonode )
290 heurtiming |= SCIP_HEURTIMING_AFTERLPNODE;
291 else
293 }
294 else
295 {
296 if( !pseudonode )
298 else
300 }
301 }
302
303 /* initialize the tree related data, if we are not in presolving */
304 if( heurtiming == SCIP_HEURTIMING_BEFOREPRESOL || heurtiming == SCIP_HEURTIMING_DURINGPRESOLLOOP )
305 {
306 depth = -1;
307 lpstateforkdepth = -1;
308
309 SCIPsetDebugMsg(set, "calling primal heuristics %s presolving\n",
310 heurtiming == SCIP_HEURTIMING_BEFOREPRESOL ? "before" : "during");
311 }
312 else
313 {
314 assert(tree != NULL); /* for lint */
315 depth = SCIPtreeGetFocusDepth(tree);
316 lpstateforkdepth = (tree->focuslpstatefork != NULL ? SCIPnodeGetDepth(tree->focuslpstatefork) : -1);
317
318 SCIPsetDebugMsg(set, "calling primal heuristics in depth %d (timing: %u)\n", depth, heurtiming);
319 }
320
321 /* call heuristics */
322 ndelayedheurs = 0;
323 oldnbestsolsfound = primal->nbestsolsfound;
324
325#ifndef NDEBUG
326 /* remember old probing and diving status */
327 inprobing = tree != NULL && SCIPtreeProbing(tree);
328 indiving = lp != NULL && SCIPlpDiving(lp);
329
330 /* heuristics should currently not be called in diving mode */
331 assert(!indiving);
332#endif
333
334 /* collect lower bound of current node */
335 if( tree != NULL )
336 {
337 assert(SCIPtreeGetFocusNode(tree) != NULL);
339 }
340 else if( lp != NULL )
341 lowerbound = SCIPlpGetPseudoObjval(lp, set, prob);
342 else
343 lowerbound = -SCIPsetInfinity(set);
344
345 for( h = 0; h < set->nheurs; ++h )
346 {
347#ifndef NDEBUG
348 size_t nusedbuffer = BMSgetNUsedBufferMemory(SCIPbuffer(set->scip));
349#endif
350 /* it might happen that a diving heuristic renders the previously solved node LP invalid
351 * such that additional calls to LP heuristics will fail; better abort the loop in this case
352 */
353 if( lp != NULL && lp->resolvelperror)
354 break;
355
356#ifdef SCIP_DEBUG
357 {
358 SCIP_Bool delayed;
359 if( SCIPheurShouldBeExecuted(set->heurs[h], depth, lpstateforkdepth, heurtiming, &delayed) )
360 {
361 SCIPsetDebugMsg(set, " -> executing heuristic <%s> with priority %d\n",
362 SCIPheurGetName(set->heurs[h]), SCIPheurGetPriority(set->heurs[h]));
363 }
364 }
365#endif
366
367 SCIP_CALL( SCIPheurExec(set->heurs[h], set, primal, depth, lpstateforkdepth, heurtiming, nodeinfeasible,
368 &ndelayedheurs, &result) );
369
370#ifndef NDEBUG
371 if( BMSgetNUsedBufferMemory(SCIPbuffer(set->scip)) > nusedbuffer )
372 {
373 SCIPerrorMessage("Buffer not completely freed after executing heuristic <%s>\n", SCIPheurGetName(set->heurs[h]));
374 SCIPABORT();
375 }
376#endif
377
378 /* if the new solution cuts off the current node due to a new primal solution (via the cutoff bound) interrupt
379 * calling the remaining heuristics
380 */
381 if( (result == SCIP_FOUNDSOL && lowerbound > primal->cutoffbound) || SCIPsolveIsStopped(set, stat, FALSE) )
382 break;
383
384 /* check if the problem is proven to be unbounded, currently this happens only in reoptimization */
385 if( result == SCIP_UNBOUNDED )
386 {
387 *unbounded = TRUE;
388 break;
389 }
390
391 /* make sure that heuristic did not change probing or diving status */
392 assert(tree == NULL || inprobing == SCIPtreeProbing(tree));
393 assert(lp == NULL || indiving == SCIPlpDiving(lp));
394 }
395 assert(0 <= ndelayedheurs && ndelayedheurs <= set->nheurs);
396
397 *foundsol = (primal->nbestsolsfound > oldnbestsolsfound);
398
399 return SCIP_OKAY;
400}
401
402/** applies one round of propagation */
403static
405 BMS_BLKMEM* blkmem, /**< block memory buffers */
406 SCIP_SET* set, /**< global SCIP settings */
407 SCIP_STAT* stat, /**< dynamic problem statistics */
408 SCIP_TREE* tree, /**< branch and bound tree */
409 int depth, /**< depth level to use for propagator frequency checks */
410 SCIP_Bool fullpropagation, /**< should all constraints be propagated (or only new ones)? */
411 SCIP_Bool onlydelayed, /**< should only delayed propagators be called? */
412 SCIP_Bool* delayed, /**< pointer to store whether a propagator was delayed */
413 SCIP_Bool* propagain, /**< pointer to store whether propagation should be applied again */
414 SCIP_PROPTIMING timingmask, /**< timing mask to decide which propagators are executed */
415 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
416 SCIP_Bool* postpone /**< pointer to store whether the node should be postponed */
417 )
418{ /*lint --e{715}*/
419 SCIP_RESULT result;
420 SCIP_Bool abortoncutoff;
421 int i;
422
423 assert(set != NULL);
424 assert(delayed != NULL);
425 assert(propagain != NULL);
426 assert(cutoff != NULL);
427 assert(postpone != NULL);
428
429 *delayed = FALSE;
430 *propagain = FALSE;
431
432 /* sort propagators */
434
435 /* check if we want to abort on a cutoff; if we are not in the solving stage (e.g., in presolving), we want to abort
436 * anyway
437 */
438 abortoncutoff = set->prop_abortoncutoff || (set->stage != SCIP_STAGE_SOLVING);
439
440 /* call additional propagators with nonnegative priority */
441 for( i = 0; i < set->nprops && !(*postpone) && (!(*cutoff) || !abortoncutoff); ++i )
442 {
443#ifndef NDEBUG
444 size_t nusedbuffer = BMSgetNUsedBufferMemory(SCIPbuffer(set->scip));
445#endif
446 /* timing needs to fit */
447 if( (SCIPpropGetTimingmask(set->props[i]) & timingmask) == 0 )
448 continue;
449
450 if( SCIPpropGetPriority(set->props[i]) < 0 )
451 continue;
452
453 if( onlydelayed && !SCIPpropWasDelayed(set->props[i]) )
454 continue;
455
456 SCIPsetDebugMsg(set, "calling propagator <%s>\n", SCIPpropGetName(set->props[i]));
457
458 SCIP_CALL( SCIPpropExec(set->props[i], set, stat, depth, onlydelayed, tree->sbprobing, timingmask, &result) );
459
460#ifndef NDEBUG
461 if( BMSgetNUsedBufferMemory(SCIPbuffer(set->scip)) > nusedbuffer )
462 {
463 SCIPerrorMessage("Buffer not completely freed after executing propagator <%s>\n", SCIPpropGetName(set->props[i]));
464 SCIPABORT();
465 }
466#endif
467
468 *delayed = *delayed || (result == SCIP_DELAYED);
469 *propagain = *propagain || (result == SCIP_REDUCEDDOM);
470
471 /* beside the result pointer of the propagator we have to check if an internal cutoff was detected; this can
472 * happen when a global bound change was applied which is globally valid and leads locally (for the current node
473 * and others) to an infeasible problem;
474 */
475 *cutoff = *cutoff || (result == SCIP_CUTOFF) || (tree->cutoffdepth <= SCIPtreeGetCurrentDepth(tree));
476 *postpone = (result == SCIP_DELAYNODE) && !(*cutoff);
477
478 if( result == SCIP_CUTOFF )
479 {
480 SCIPsetDebugMsg(set, " -> propagator <%s> detected cutoff\n", SCIPpropGetName(set->props[i]));
481 }
482
483 /* if we work off the delayed propagators, we stop immediately if a reduction was found */
484 if( onlydelayed && result == SCIP_REDUCEDDOM )
485 {
486 *delayed = TRUE;
487 return SCIP_OKAY;
488 }
489 }
490
491 /* propagate constraints */
492 for( i = 0; i < set->nconshdlrs && !(*postpone) && (!(*cutoff) || !abortoncutoff); ++i )
493 {
494 /* timing needs to fit */
495 if( (SCIPconshdlrGetPropTiming(set->conshdlrs[i]) & timingmask) == 0 )
496 continue;
497
498 if( onlydelayed && !SCIPconshdlrWasPropagationDelayed(set->conshdlrs[i]) )
499 continue;
500
501 SCIPsetDebugMsg(set, "calling propagation method of constraint handler <%s>\n", SCIPconshdlrGetName(set->conshdlrs[i]));
502
503 SCIP_CALL( SCIPconshdlrPropagate(set->conshdlrs[i], blkmem, set, stat, depth, fullpropagation, onlydelayed,
504 tree->sbprobing, timingmask, &result) );
505 *delayed = *delayed || (result == SCIP_DELAYED);
506 *propagain = *propagain || (result == SCIP_REDUCEDDOM);
507
508 /* beside the result pointer of the propagator we have to check if an internal cutoff was detected; this can
509 * happen when a global bound change was applied which is globally valid and leads locally (for the current node
510 * and others) to an infeasible problem;
511 */
512 *cutoff = *cutoff || (result == SCIP_CUTOFF) || (tree->cutoffdepth <= SCIPtreeGetCurrentDepth(tree));
513 *postpone = (result == SCIP_DELAYNODE) && !(*cutoff);
514
515 if( result == SCIP_CUTOFF )
516 {
517 SCIPsetDebugMsg(set, " -> constraint handler <%s> detected cutoff in propagation\n",
518 SCIPconshdlrGetName(set->conshdlrs[i]));
519 }
520
521 /* if we work off the delayed propagators, we stop immediately if a reduction was found */
522 if( onlydelayed && result == SCIP_REDUCEDDOM )
523 {
524 *delayed = TRUE;
525 return SCIP_OKAY;
526 }
527 }
528
529 /* call additional propagators with negative priority */
530 for( i = 0; i < set->nprops && !(*postpone) && (!(*cutoff) || !abortoncutoff); ++i )
531 {
532 /* timing needs to fit */
533 if( (SCIPpropGetTimingmask(set->props[i]) & timingmask) == 0 )
534 continue;
535
536 if( SCIPpropGetPriority(set->props[i]) >= 0 )
537 continue;
538
539 if( onlydelayed && !SCIPpropWasDelayed(set->props[i]) )
540 continue;
541
542 SCIPsetDebugMsg(set, "calling propagator <%s>\n", SCIPpropGetName(set->props[i]));
543
544 SCIP_CALL( SCIPpropExec(set->props[i], set, stat, depth, onlydelayed, tree->sbprobing, timingmask, &result) );
545 *delayed = *delayed || (result == SCIP_DELAYED);
546 *propagain = *propagain || (result == SCIP_REDUCEDDOM);
547
548 /* beside the result pointer of the propagator we have to check if an internal cutoff was detected; this can
549 * happen when a global bound change was applied which is globally valid and leads locally (for the current node
550 * and others) to an infeasible problem;
551 */
552 *cutoff = *cutoff || (result == SCIP_CUTOFF) || (tree->cutoffdepth <= SCIPtreeGetCurrentDepth(tree));
553 *postpone = (result == SCIP_DELAYNODE) && !(*cutoff);
554
555 if( result == SCIP_CUTOFF )
556 {
557 SCIPsetDebugMsg(set, " -> propagator <%s> detected cutoff\n", SCIPpropGetName(set->props[i]));
558 }
559
560 /* if we work off the delayed propagators, we stop immediately if a reduction was found */
561 if( onlydelayed && result == SCIP_REDUCEDDOM )
562 {
563 *delayed = TRUE;
564 return SCIP_OKAY;
565 }
566 }
567
568 return SCIP_OKAY;
569}
570
571/** applies domain propagation on current node */
572static
574 BMS_BLKMEM* blkmem, /**< block memory buffers */
575 SCIP_SET* set, /**< global SCIP settings */
576 SCIP_STAT* stat, /**< dynamic problem statistics */
577 SCIP_TREE* tree, /**< branch and bound tree */
578 int depth, /**< depth level to use for propagator frequency checks */
579 int maxproprounds, /**< maximal number of propagation rounds (-1: no limit, 0: parameter settings) */
580 SCIP_Bool fullpropagation, /**< should all constraints be propagated (or only new ones)? */
581 SCIP_PROPTIMING timingmask, /**< timing mask to decide which propagators are executed */
582 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
583 SCIP_Bool* postpone /**< pointer to store whether the node should be postponed */
584 )
585{
586 SCIP_NODE* node;
587 SCIP_Bool delayed;
588 SCIP_Bool propagain;
589 int propround;
590
591 assert(set != NULL);
592 assert(tree != NULL);
593 assert(depth >= 0);
594 assert(cutoff != NULL);
595
596 node = SCIPtreeGetCurrentNode(tree);
597 assert(node != NULL && SCIPnodeIsActive(node));
601
602 /* adjust maximal number of propagation rounds */
603 if( maxproprounds == 0 )
604 maxproprounds = (depth == 0 ? set->prop_maxroundsroot : set->prop_maxrounds);
605 if( maxproprounds == -1 )
606 maxproprounds = INT_MAX;
607
608 SCIPsetDebugMsg(set, "domain propagation of node %p in depth %d (using depth %d, maxrounds %d, proptiming %u)\n",
609 (void*)node, SCIPnodeGetDepth(node), depth, maxproprounds, timingmask);
610
611 /* propagate as long new bound changes were found and the maximal number of propagation rounds is not exceeded */
612 *cutoff = FALSE;
613 *postpone = FALSE;
614 propround = 0;
615 propagain = TRUE;
616 while( propagain && !(*cutoff) && !(*postpone) && propround < maxproprounds && !SCIPsolveIsStopped(set, stat, FALSE) )
617 {
618 propround++;
619
620 /* perform the propagation round by calling the propagators and constraint handlers */
621 SCIP_CALL( propagationRound(blkmem, set, stat, tree, depth, fullpropagation, FALSE, &delayed, &propagain, timingmask, cutoff, postpone) );
622
623 /* if the propagation will be terminated, call the delayed propagators */
624 while( delayed && (!propagain || propround >= maxproprounds) && !(*cutoff) )
625 {
626 /* call the delayed propagators and constraint handlers */
627 SCIP_CALL( propagationRound(blkmem, set, stat, tree, depth, fullpropagation, TRUE, &delayed, &propagain, timingmask, cutoff, postpone) );
628 }
629
630 /* if a reduction was found, we want to do another full propagation round (even if the propagator only claimed
631 * to have done a domain reduction without applying a domain change)
632 */
633 fullpropagation = TRUE;
634 }
635
636 /* mark the node to be completely propagated in the current repropagation subtree level */
637 SCIPnodeMarkPropagated(node, tree);
638
639 if( *cutoff )
640 {
641 SCIPsetDebugMsg(set, " --> domain propagation of node %p finished: cutoff!\n", (void*)node);
642 }
643
644 return SCIP_OKAY;
645}
646
647/** applies domain propagation on current node and flushes the conflict store afterwards */
649 BMS_BLKMEM* blkmem, /**< block memory buffers */
650 SCIP_SET* set, /**< global SCIP settings */
651 SCIP_STAT* stat, /**< dynamic problem statistics */
652 SCIP_PROB* transprob, /**< transformed problem */
653 SCIP_PROB* origprob, /**< original problem */
654 SCIP_TREE* tree, /**< branch and bound tree */
655 SCIP_REOPT* reopt, /**< reoptimization data structure */
656 SCIP_LP* lp, /**< LP data */
657 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
658 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
659 SCIP_CONFLICT* conflict, /**< conflict analysis data */
660 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
661 int depth, /**< depth level to use for propagator frequency checks */
662 int maxproprounds, /**< maximal number of propagation rounds (-1: no limit, 0: parameter settings) */
663 SCIP_PROPTIMING timingmask, /**< timing mask to decide which propagators are executed */
664 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
665 )
666{
667 SCIP_Bool postpone;
668
669 /* apply domain propagation */
670 SCIP_CALL( propagateDomains(blkmem, set, stat, tree, depth, maxproprounds, TRUE, timingmask, cutoff, &postpone) );
671
672 /* flush the conflict set storage */
673 SCIP_CALL( SCIPconflictFlushConss(conflict, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue, cliquetable) );
674
675 return SCIP_OKAY;
676}
677
678/** returns whether the given variable with the old LP solution value should lead to an update of the pseudo cost entry */
679static
681 SCIP_VAR* var, /**< problem variable */
682 SCIP_SET* set, /**< global SCIP settings */
683 SCIP_Real oldlpsolval, /**< solution value of variable in old LP */
684 SCIP_Bool updateintegers, /**< whether to update pseudo costs for integer variables */
685 SCIP_Bool updatecontinuous /**< whether to update pseudo costs for continuous variables */
686 )
687{
688 SCIP_Real newlpsolval;
689
690 assert(var != NULL);
691
692 if( !updatecontinuous && SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
693 return FALSE;
694
695 if( !updateintegers && SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS )
696 return FALSE;
697
698 if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS && set->branch_lpgainnorm != 'l' )
699 {
700 /* if the variable is fixed at +/- infinity or it has an unbounded domain, then the domain-based update strategies will not work */
702 return FALSE;
703
704 /* @todo if set->branch_lpgainnorm == 's', then we would need to know then domain before branching
705 * since this is difficult to get, we don't check for unboundedness here and let the pscost update fail later
706 * however, this makes the weights used to spread a pseudo cost update over all domain changes inaccurate
707 */
708
709 return TRUE;
710 }
711
712 /* if the old LP solution value is unknown, the pseudo cost update cannot be performed */
713 if( oldlpsolval >= SCIP_INVALID )
714 return FALSE;
715
716 /* the bound change on the given variable was responsible for the gain in the dual bound, if the variable's
717 * old solution value is outside the current bounds, and the new solution value is equal to the bound
718 * closest to the old solution value
719 */
720
721 /* find out, which of the current bounds is violated by the old LP solution value */
722 if( SCIPsetIsLT(set, oldlpsolval, SCIPvarGetLbLocal(var)) )
723 {
724 newlpsolval = SCIPvarGetLPSol(var);
725 return SCIPsetIsEQ(set, newlpsolval, SCIPvarGetLbLocal(var));
726 }
727 else if( SCIPsetIsGT(set, oldlpsolval, SCIPvarGetUbLocal(var)) )
728 {
729 newlpsolval = SCIPvarGetLPSol(var);
730 return SCIPsetIsEQ(set, newlpsolval, SCIPvarGetUbLocal(var));
731 }
732 else
733 return FALSE;
734}
735
736/** pseudo cost flag stored in the variables to mark them for the pseudo cost update */
738{
739 PSEUDOCOST_NONE = 0, /**< variable's bounds were not changed */
740 PSEUDOCOST_IGNORE = 1, /**< bound changes on variable should be ignored for pseudo cost updates */
741 PSEUDOCOST_UPDATE = 2 /**< pseudo cost value of variable should be updated */
744
745/** updates the variable's pseudo cost values after the node's initial LP was solved */
746static
748 SCIP_SET* set, /**< global SCIP settings */
749 SCIP_STAT* stat, /**< dynamic problem statistics */
750 SCIP_PROB* prob, /**< transformed problem after presolve */
751 SCIP_TREE* tree, /**< branch and bound tree */
752 SCIP_LP* lp, /**< LP data */
753 SCIP_Bool updateintegers, /**< whether to update pseudo costs for integer variables */
754 SCIP_Bool updatecontinuous /**< whether to update pseudo costs for continuous variables */
755 )
756{
757 SCIP_NODE* focusnode;
758 int actdepth;
759
760 assert(lp != NULL);
761 assert(tree != NULL);
762 assert(tree->path != NULL);
763
764 focusnode = SCIPtreeGetFocusNode(tree);
765 assert(SCIPnodeIsActive(focusnode));
766 assert(SCIPnodeGetType(focusnode) == SCIP_NODETYPE_FOCUSNODE);
767 actdepth = SCIPnodeGetDepth(focusnode);
768 assert(tree->path[actdepth] == focusnode);
769
770 if( (updateintegers || updatecontinuous) && lp->solved && SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL && tree->focuslpstatefork != NULL )
771 {
772 SCIP_BOUNDCHG** updates;
773 SCIP_NODE* node;
774 SCIP_VAR* var;
775 SCIP_Real weight;
776 SCIP_Real lpgain;
777 int nupdates;
778 int nvalidupdates;
779 int d;
780 int i;
781
782 assert(SCIPnodeIsActive(tree->focuslpstatefork));
783 assert(tree->path[tree->focuslpstatefork->depth] == tree->focuslpstatefork);
784
785 /* get a buffer for the collected bound changes; start with a size twice as large as the number of nodes between
786 * current node and LP fork
787 */
788 SCIP_CALL( SCIPsetAllocBufferArray(set, &updates, (int)(2*(actdepth - tree->focuslpstatefork->depth))) );
789 nupdates = 0;
790 nvalidupdates = 0;
791
792 /* search the nodes from LP fork down to current node for bound changes in between; move in this direction,
793 * because the bound changes closer to the LP fork are more likely to have a valid LP solution information
794 * attached; collect the bound changes for pseudo cost value updates and mark the corresponding variables such
795 * that they are not updated twice in case of more than one bound change on the same variable
796 */
797 for( d = tree->focuslpstatefork->depth+1; d <= actdepth; ++d )
798 {
799 node = tree->path[d];
800
801 if( node->domchg != NULL )
802 {
803 SCIP_BOUNDCHG* boundchgs;
804 int nboundchgs;
805
806 boundchgs = node->domchg->domchgbound.boundchgs;
807 nboundchgs = (int) node->domchg->domchgbound.nboundchgs;
808 for( i = 0; i < nboundchgs; ++i )
809 {
810 var = boundchgs[i].var;
811 assert(var != NULL);
812
813 /* we even collect redundant bound changes, since they were not redundant in the LP branching decision
814 * and therefore should be regarded in the pseudocost updates
815 *
816 * however, if the variable is continuous and we normalize the pseudo costs by the domain reduction,
817 * then getting the variable bound before the branching is not possible by looking at the variables branching information (since redundant branchings are not applied)
818 * thus, in this case we ignore the boundchange
819 */
820 if( (SCIP_BOUNDCHGTYPE)boundchgs[i].boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING &&
822 )
823 {
824 /* remember the bound change and mark the variable */
825 SCIP_CALL( SCIPsetReallocBufferArray(set, &updates, nupdates+1) );
826 updates[nupdates] = &boundchgs[i];
827 nupdates++;
828
829 /* check, if the bound change would lead to a valid pseudo cost update
830 * and see comment above (however, ...) */
831 if( isPseudocostUpdateValid(var, set, boundchgs[i].data.branchingdata.lpsolval, updateintegers, updatecontinuous) &&
832 (SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS || !boundchgs[i].redundant || set->branch_lpgainnorm != 'd')
833 )
834 {
835 var->pseudocostflag = PSEUDOCOST_UPDATE; /*lint !e641*/
836 nvalidupdates++;
837 }
838 else
839 var->pseudocostflag = PSEUDOCOST_IGNORE; /*lint !e641*/
840 }
841 }
842 }
843 }
844
845 /* update the pseudo cost values and reset the variables' flags; assume, that the responsibility for the dual gain
846 * is equally spread on all bound changes that lead to valid pseudo cost updates
847 */
849 weight = (nvalidupdates > 0 ? 1.0 / (SCIP_Real)nvalidupdates : 1.0);
850 lpgain = (SCIPlpGetObjval(lp, set, prob) - tree->focuslpstatefork->data.fork->lpobjval) * weight;
851 lpgain = MAX(lpgain, 0.0);
852
853 for( i = 0; i < nupdates; ++i )
854 {
855 assert((SCIP_BOUNDCHGTYPE)updates[i]->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING);
856
857 var = updates[i]->var;
858 assert(var != NULL);
860
862 {
863 if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS || set->branch_lpgainnorm == 'l' )
864 {
865 SCIPsetDebugMsg(set, "updating pseudocosts of <%s>: sol: %g -> %g, LP: %e -> %e => solvaldelta = %g, gain=%g, weight: %g\n",
866 SCIPvarGetName(var), updates[i]->data.branchingdata.lpsolval, SCIPvarGetLPSol(var),
868 SCIPvarGetLPSol(var) - updates[i]->data.branchingdata.lpsolval, lpgain, weight);
870 SCIPvarGetLPSol(var) - updates[i]->data.branchingdata.lpsolval, lpgain, weight) );
871 }
872 else
873 {
874 /* set->branch_lpgainnorm == 'd':
875 * For continuous variables, we want to pseudocosts to be the average of the gain in the LP value
876 * if the domain is reduced from x% of its original width to y% of its original (e.g., global) width, i.e.,
877 * to be the average of LPgain / (oldwidth/origwidth - newwidth/origwidth) = LPgain * origwidth / (oldwidth - newwidth).
878 * Then an expected improvement in the LP value by a reduction of the domain width
879 * from x% to y% of its original width can be computed by pseudocost * (oldwidth - newwidth) / origwidth.
880 * Since the original width cancels out, we can also define the pseudocosts as average of LPgain / (oldwidth - newwidth)
881 * and compute the expected improvement as pseudocost * (oldwidth - newwidth).
882 *
883 * Let var have bounds [a,c] before the branching and assume we branched on some value b.
884 * b is given by updates[i]->newbound.
885 *
886 * If updates[i]->boundtype = upper, then node corresponds to the child [a,b].
887 * Thus, we have oldwidth = c-a, newwidth = b-a, and oldwidth - newwidth = c-b.
888 * To get c (the previous upper bound), we look into the var->ubchginfos array.
889 *
890 * If updates[i]->boundtype = lower, then node corresponds to the child [b,c].
891 * Thus, we have oldwidth = c-a, newwidth = c-b, and oldwidth - newwidth = b-a.
892 * To get c (the previous lower bound), we look into the var->lbchginfos array.
893 */
894 SCIP_BDCHGINFO* bdchginfo;
895 SCIP_Real oldbound;
896 SCIP_Real delta;
897 int j;
898 int nbdchginfos;
899
900 assert(set->branch_lpgainnorm == 'd' || set->branch_lpgainnorm == 's');
901
902 oldbound = SCIP_INVALID;
903
904 if( set->branch_lpgainnorm == 'd' )
905 {
906 assert(!updates[i]->redundant);
907
908 if( (SCIP_BOUNDTYPE)updates[i]->boundtype == SCIP_BOUNDTYPE_UPPER )
909 {
910 nbdchginfos = SCIPvarGetNBdchgInfosUb(var);
911
912 /* walk backwards through bound change information array to find the bound change corresponding to branching in updates[i]
913 * usually it will be the first one we look at */
914 for( j = nbdchginfos-1; j >= 0; --j )
915 {
916 bdchginfo = SCIPvarGetBdchgInfoUb(var, j);
917
918 if( bdchginfo->oldbound > updates[i]->newbound )
919 {
920 /* first boundchange which upper bound is above the upper bound set by the branching in updates[i]
921 * if bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING, then this should be exactly the bound change that we are looking for
922 * if bdchginfo->boundchgtype != SCIP_BOUNDCHGTYPE_BRANCHING, then this should be because the branching domain change has not been applied to the variable due to redundancy
923 * in this case, i.e., if there was another boundchange coming from somewhere else, I am not sure whether oldbound is an accurate value to compute the old domain size, so we skip the pseudocosts update
924 */
926 {
927 assert(bdchginfo->newbound == updates[i]->newbound); /*lint !e777*/
928 oldbound = bdchginfo->oldbound;
929 }
930 else
931 assert(updates[i]->redundant);
932
933 break;
934 }
935 }
936 /* if the bound change was redundant (e.g., due to a change in the global bound), then it was not applied, so there exists no corresponding bound change info
937 * if it is not redundant, then we should have found at least one corresponding boundchange */
938 assert(j >= 0 || updates[i]->redundant);
939 if( oldbound != SCIP_INVALID ) /*lint !e777*/
940 {
941 assert(!SCIPsetIsInfinity(set, -oldbound)); /* branching on a variable fixed to -infinity does not make sense */
942 assert(!SCIPsetIsInfinity(set, updates[i]->newbound)); /* branching to infinity does not make sense */
943
944 /* if the old upper bound is at infinity or the new upper bound is at -infinity, then we say the delta (c-b) is infinity */
945 if( SCIPsetIsInfinity(set, oldbound) || SCIPsetIsInfinity(set, -updates[i]->newbound) )
946 delta = SCIP_INVALID;
947 else
948 delta = updates[i]->newbound - oldbound;
949 }
950 else
951 delta = SCIP_INVALID;
952 }
953 else
954 {
955 assert((SCIP_BOUNDTYPE)updates[i]->boundtype == SCIP_BOUNDTYPE_LOWER);
956 nbdchginfos = SCIPvarGetNBdchgInfosLb(var);
957
958 /* walk backwards through bound change information array to find the bound change corresponding to branching in updates[i]
959 * usually it will be the first one we look at */
960 for( j = nbdchginfos-1; j >= 0; --j )
961 {
962 bdchginfo = SCIPvarGetBdchgInfoLb(var, j);
963
964 if( bdchginfo->oldbound < updates[i]->newbound )
965 {
966 /* first boundchange which lower bound is below the lower bound set by the branching in updates[i]
967 * if bdchginfo->boundchgtype == SCIP_BOUNDCHGTYPE_BRANCHING, then this should be exactly the bound change that we are looking for
968 * if bdchginfo->boundchgtype != SCIP_BOUNDCHGTYPE_BRANCHING, then this should be because the branching domain change has not been applied to the variable due to redundancy
969 * in this case, i.e., if there was another boundchange coming from somewhere else, I am not sure whether oldbound is an accurate value to compute the old domain size, so we skip the pseudocosts update
970 */
972 {
973 assert(bdchginfo->newbound == updates[i]->newbound); /*lint !e777*/
974 oldbound = bdchginfo->oldbound;
975 }
976 else
977 assert(updates[i]->redundant);
978
979 break;
980 }
981 }
982 /* if the bound change was redundant (e.g., due to a change in the global bound), then it was not applied, so there exists no corresponding bound change info
983 * if it is not redundant, then we should have found at least one corresponding boundchange */
984 assert(j >= 0 || updates[i]->redundant);
985 if( oldbound != SCIP_INVALID ) /*lint !e777*/
986 {
987 assert(!SCIPsetIsInfinity(set, oldbound)); /* branching on a variable fixed to +infinity does not make sense */
988 assert(!SCIPsetIsInfinity(set, -updates[i]->newbound)); /* branching to infinity does not make sense */
989
990 /* if the old lower bound is at -infinity or the new lower bound is at +infinity, then we say the delta (b-a) is infinity */
991 if( SCIPsetIsInfinity(set, -oldbound) || SCIPsetIsInfinity(set, updates[i]->newbound) )
992 delta = SCIP_INVALID;
993 else
994 delta = updates[i]->newbound - oldbound;
995 }
996 else
997 delta = SCIP_INVALID;
998 }
999 }
1000 else
1001 {
1002 /* set->branch_lpgainnorm == 's':
1003 * Here, we divide the LPgain by the reduction in the sibling node.
1004 *
1005 * If updates[i]->boundtype = upper, then node corresponds to the child [a,b].
1006 * Thus, we have oldwidth = c-a, newwidth = c-b, and oldwidth - newwidth = b-a.
1007 * Conveniently, we just use the current lower bound for a (it may have been tightened, though).
1008 *
1009 * If updates[i]->boundtype = lower, then node corresponds to the child [b,a].
1010 * Thus, we have oldwidth = c-a, newwidth = b-a, and oldwidth - newwidth = c-b.
1011 * Conveniently, we just use the current upper bound for c (it may have been tightened, though).
1012 */
1013 if( (SCIP_BOUNDTYPE)updates[i]->boundtype == SCIP_BOUNDTYPE_UPPER )
1014 {
1015 assert(!SCIPsetIsInfinity(set, updates[i]->newbound)); /* branching on a variable fixed to +infinity does not make sense */
1016 assert(!SCIPsetIsInfinity(set, SCIPvarGetLbLocal(var))); /* branching to infinity does not make sense */
1017 if( SCIPsetIsInfinity(set, -updates[i]->newbound) || SCIPsetIsInfinity(set, -SCIPvarGetLbLocal(var)) )
1018 delta = SCIP_INVALID;
1019 else
1020 delta = updates[i]->newbound - SCIPvarGetLbLocal(var);
1021 }
1022 else
1023 {
1024 assert((SCIP_BOUNDTYPE)updates[i]->boundtype == SCIP_BOUNDTYPE_LOWER);
1025 assert(!SCIPsetIsInfinity(set, -updates[i]->newbound)); /* branching on a variable fixed to -infinity does not make sense */
1026 assert(!SCIPsetIsInfinity(set, -SCIPvarGetUbLocal(var))); /* branching to -infinity does not make sense */
1027 if( SCIPsetIsInfinity(set, updates[i]->newbound) || SCIPsetIsInfinity(set, SCIPvarGetUbLocal(var)) )
1028 delta = SCIP_INVALID;
1029 else
1030 delta = -(SCIPvarGetUbLocal(var) - updates[i]->newbound);
1031 }
1032 }
1033
1034 if( delta != SCIP_INVALID ) /*lint !e777*/
1035 {
1036 SCIPsetDebugMsg(set, "updating pseudocosts of <%s> with strategy %c: domain: [%g,%g] -> [%g,%g], LP: %e -> %e => "
1037 "delta = %g, gain=%g, weight: %g\n",
1038 SCIPvarGetName(var), set->branch_lpgainnorm,
1039 (SCIP_BOUNDTYPE)updates[i]->boundtype == SCIP_BOUNDTYPE_UPPER ? SCIPvarGetLbLocal(var) : oldbound,
1040 (SCIP_BOUNDTYPE)updates[i]->boundtype == SCIP_BOUNDTYPE_UPPER ? oldbound : SCIPvarGetUbLocal(var),
1041 (SCIP_BOUNDTYPE)updates[i]->boundtype == SCIP_BOUNDTYPE_UPPER ? SCIPvarGetLbLocal(var) : updates[i]->newbound,
1042 (SCIP_BOUNDTYPE)updates[i]->boundtype == SCIP_BOUNDTYPE_UPPER ? updates[i]->newbound : SCIPvarGetUbLocal(var),
1044 delta, lpgain, weight);
1045
1046 SCIP_CALL( SCIPvarUpdatePseudocost(var, set, stat, delta, lpgain, weight) );
1047 }
1048 }
1049 }
1050 var->pseudocostflag = PSEUDOCOST_NONE; /*lint !e641*/
1051 }
1052
1053 /* free the buffer for the collected bound changes */
1054 SCIPsetFreeBufferArray(set, &updates);
1055 }
1056
1057 return SCIP_OKAY;
1058}
1059
1060/** updates the estimated value of a primal feasible solution for the focus node after the LP was solved */
1061static
1063 SCIP_SET* set, /**< global SCIP settings */
1064 SCIP_STAT* stat, /**< problem statistics */
1065 SCIP_TREE* tree, /**< branch and bound tree */
1066 SCIP_LP* lp, /**< current LP data */
1067 SCIP_BRANCHCAND* branchcand /**< branching candidate storage */
1068 )
1069{
1070 SCIP_NODE* focusnode;
1071 SCIP_VAR** lpcands;
1072 SCIP_Real* lpcandsfrac;
1073 SCIP_Real estimate;
1074 int nlpcands;
1075 int i;
1076
1077 /* estimate is only available if LP was solved to optimality */
1079 return SCIP_OKAY;
1080
1081 focusnode = SCIPtreeGetFocusNode(tree);
1082 assert(focusnode != NULL);
1083
1084 /* get the fractional variables */
1085 SCIP_CALL( SCIPbranchcandGetLPCands(branchcand, set, stat, lp, &lpcands, NULL, &lpcandsfrac, &nlpcands, NULL, NULL) );
1086
1087 /* calculate the estimate: lowerbound + sum(min{f_j * pscdown_j, (1-f_j) * pscup_j}) */
1088 estimate = SCIPnodeGetLowerbound(focusnode);
1089
1090 /* an infinite lower bound implies an infinite estimate */
1091 if( SCIPsetIsInfinity(set, estimate) )
1092 {
1093 SCIPnodeSetEstimate(focusnode, set, estimate);
1094 return SCIP_OKAY;
1095 }
1096
1097 for( i = 0; i < nlpcands; ++i )
1098 {
1099 SCIP_Real pscdown;
1100 SCIP_Real pscup;
1101
1102 pscdown = SCIPvarGetPseudocost(lpcands[i], stat, 0.0-lpcandsfrac[i]);
1103 pscup = SCIPvarGetPseudocost(lpcands[i], stat, 1.0-lpcandsfrac[i]);
1104 estimate += MIN(pscdown, pscup);
1105 }
1106 SCIPnodeSetEstimate(focusnode, set, estimate);
1107
1108 return SCIP_OKAY;
1109}
1110
1111/** puts all constraints with initial flag TRUE into the LP */
1113 BMS_BLKMEM* blkmem, /**< block memory buffers */
1114 SCIP_SET* set, /**< global SCIP settings */
1115 SCIP_SEPASTORE* sepastore, /**< separation storage */
1116 SCIP_CUTPOOL* cutpool, /**< global cutpool */
1117 SCIP_STAT* stat, /**< dynamic problem statistics */
1118 SCIP_PROB* transprob, /**< transformed problem */
1119 SCIP_PROB* origprob, /**< original problem */
1120 SCIP_TREE* tree, /**< branch and bound tree */
1121 SCIP_REOPT* reopt, /**< reoptimization data structure */
1122 SCIP_LP* lp, /**< LP data */
1123 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1124 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1125 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
1126 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1127 SCIP_Bool root, /**< is this the initial root LP? */
1128 SCIP_Bool firstsubtreeinit, /**< is this the first call in the current subtree after jumping through the tree? */
1129 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
1130 )
1131{
1132 int h;
1133
1134 assert(set != NULL);
1135 assert(lp != NULL);
1136 assert(cutoff != NULL);
1137
1138 *cutoff = FALSE;
1139
1140 /* inform separation storage, that LP is now filled with initial data */
1141 SCIPsepastoreStartInitialLP(sepastore);
1142
1143 /* add LP relaxations of all initial constraints to LP */
1144 SCIPsetDebugMsg(set, "init LP: initial rows\n");
1145 for( h = 0; h < set->nconshdlrs && !(*cutoff); ++h )
1146 {
1147 SCIP_CALL( SCIPconshdlrInitLP(set->conshdlrs[h], blkmem, set, stat, tree, firstsubtreeinit, cutoff) );
1148 }
1149
1150 if( set->reopt_enable && set->reopt_usecuts && firstsubtreeinit && !(*cutoff) )
1151 {
1152 /* add stored cuts from last reoptimization run */
1153 SCIP_CALL( SCIPreoptApplyCuts(reopt, tree->focusnode, sepastore, cutpool, blkmem, set, stat, eventqueue,
1154 eventfilter, lp, root) );
1155 }
1156
1157 if( !(*cutoff) )
1158 {
1159 /* apply cuts */
1160 SCIP_CALL( SCIPsepastoreApplyCuts(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
1161 eventqueue, eventfilter, cliquetable, root, SCIP_EFFICIACYCHOICE_LP, cutoff) );
1162 }
1163 else
1164 {
1165 /* the current node will be cut off; we clear the sepastore */
1166 SCIP_CALL( SCIPsepastoreClearCuts(sepastore, blkmem, set, eventqueue, eventfilter, lp) );
1167 }
1168
1169 /* inform separation storage, that initial LP setup is now finished */
1170 SCIPsepastoreEndInitialLP(sepastore);
1171
1172 return SCIP_OKAY;
1173}
1174
1175/** constructs the initial LP of the current node */
1176static
1178 BMS_BLKMEM* blkmem, /**< block memory buffers */
1179 SCIP_SET* set, /**< global SCIP settings */
1180 SCIP_STAT* stat, /**< dynamic problem statistics */
1181 SCIP_PROB* transprob, /**< transformed problem */
1182 SCIP_PROB* origprob, /**< original problem */
1183 SCIP_TREE* tree, /**< branch and bound tree */
1184 SCIP_REOPT* reopt, /**< reoptimization data structure */
1185 SCIP_LP* lp, /**< LP data */
1186 SCIP_PRICESTORE* pricestore, /**< pricing storage */
1187 SCIP_SEPASTORE* sepastore, /**< separation storage */
1188 SCIP_CUTPOOL* cutpool, /**< global cut pool */
1189 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1190 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1191 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
1192 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1193 SCIP_Bool root, /**< is this the initial root LP? */
1194 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
1195 )
1196{
1197 SCIP_VAR* var;
1198 int oldnvars = 0;
1199 int v;
1200
1201 assert(set != NULL);
1202 assert(transprob != NULL);
1203 assert(lp != NULL);
1204 assert(cutoff != NULL);
1205
1206 *cutoff = FALSE;
1207
1208 /* at the root node, we have to add the initial variables as columns */
1209 if( root )
1210 {
1211 assert(SCIPlpGetNCols(lp) == 0);
1212 assert(SCIPlpGetNRows(lp) == 0);
1213 assert(lp->nremovablecols == 0);
1214 assert(lp->nremovablerows == 0);
1215
1216 /* store number of variables for later */
1217 oldnvars = transprob->nvars;
1218
1219 /* inform pricing storage, that LP is now filled with initial data */
1220 SCIPpricestoreStartInitialLP(pricestore);
1221
1222 /* add all initial variables to LP */
1223 SCIPsetDebugMsg(set, "init LP: initial columns\n");
1224 for( v = 0; v < transprob->nvars && !(*cutoff); ++v )
1225 {
1226 var = transprob->vars[v];
1227 assert(SCIPvarGetProbindex(var) >= 0);
1228
1229 if( SCIPvarIsInitial(var) )
1230 {
1231 SCIP_CALL( SCIPpricestoreAddVar(pricestore, blkmem, set, eventqueue, lp, var, 0.0, TRUE) );
1232 }
1233
1234 /* check for empty domains (necessary if no presolving was performed) */
1236 *cutoff = TRUE;
1237 }
1238 assert(lp->nremovablecols == 0);
1239 SCIP_CALL( SCIPpricestoreApplyVars(pricestore, blkmem, set, stat, eventqueue, transprob, tree, lp) );
1240
1241 /* inform pricing storage, that initial LP setup is now finished */
1242 SCIPpricestoreEndInitialLP(pricestore);
1243 }
1244
1245 if( *cutoff )
1246 return SCIP_OKAY;
1247
1248 /* put all initial constraints into the LP */
1249 /* @todo check whether we jumped through the tree */
1250 SCIP_CALL( SCIPinitConssLP(blkmem, set, sepastore, cutpool, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
1251 eventfilter, cliquetable, root, TRUE, cutoff) );
1252
1253 /* putting all initial constraints into the LP might have added new variables */
1254 if( root && !(*cutoff) && transprob->nvars > oldnvars )
1255 {
1256 /* inform pricing storage, that LP is now filled with initial data */
1257 SCIPpricestoreStartInitialLP(pricestore);
1258
1259 /* check all initial variables */
1260 for( v = 0; v < transprob->nvars && !(*cutoff); ++v )
1261 {
1262 var = transprob->vars[v];
1263 assert(SCIPvarGetProbindex(var) >= 0);
1264
1266 {
1267 SCIP_CALL( SCIPpricestoreAddVar(pricestore, blkmem, set, eventqueue, lp, var, 0.0, TRUE) );
1268 }
1269
1270 /* check for empty domains (necessary if no presolving was performed) */
1272 *cutoff = TRUE;
1273 }
1274 assert(lp->nremovablecols == 0);
1275 SCIP_CALL( SCIPpricestoreApplyVars(pricestore, blkmem, set, stat, eventqueue, transprob, tree, lp) );
1276
1277 /* inform pricing storage, that initial LP setup is now finished */
1278 SCIPpricestoreEndInitialLP(pricestore);
1279 }
1280
1281 return SCIP_OKAY;
1282}
1283
1284/** constructs the LP of the current node, but does not load the LP state and warmstart information */
1286 BMS_BLKMEM* blkmem, /**< block memory buffers */
1287 SCIP_SET* set, /**< global SCIP settings */
1288 SCIP_STAT* stat, /**< dynamic problem statistics */
1289 SCIP_PROB* transprob, /**< transformed problem */
1290 SCIP_PROB* origprob, /**< original problem */
1291 SCIP_TREE* tree, /**< branch and bound tree */
1292 SCIP_REOPT* reopt, /**< reoptimization data structure */
1293 SCIP_LP* lp, /**< LP data */
1294 SCIP_PRICESTORE* pricestore, /**< pricing storage */
1295 SCIP_SEPASTORE* sepastore, /**< separation storage */
1296 SCIP_CUTPOOL* cutpool, /**< global cutpool */
1297 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1298 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1299 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
1300 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1301 SCIP_Bool newinitconss, /**< do we have to add new initial constraints? */
1302 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
1303 )
1304{
1305 SCIP_Bool initroot = FALSE;
1306
1307 assert(tree != NULL);
1308 assert(cutoff != NULL);
1309
1310 *cutoff = FALSE;
1311
1313 {
1314 /* inform separation storage, that LP is now filled with initial data */
1315 SCIPsepastoreStartInitialLP(sepastore);
1316
1317 if( tree->correctlpdepth >= 0 )
1318 {
1319 int i;
1320
1321 for( i = tree->pathnlprows[tree->correctlpdepth]; i < lp->nrows; ++i )
1322 {
1323 /* keep all active global cuts that where applied in the previous node in the lp */
1324 if( !lp->rows[i]->local && lp->rows[i]->age == 0 )
1325 {
1326 lp->rows[i]->fromcutpool = TRUE; /* this has no effect inside initial LP, but is set for consistency */
1327 SCIP_CALL( SCIPsepastoreAddCut(sepastore, blkmem, set, stat, eventqueue, eventfilter, lp, lp->rows[i],
1328 TRUE, (SCIPtreeGetCurrentDepth(tree) == 0), cutoff) );
1329 }
1330 }
1331 }
1332
1333 if( !(*cutoff) )
1334 {
1335 /* load the LP into the solver and load the LP state */
1336 SCIPsetDebugMsg(set, "loading LP\n");
1337 SCIP_CALL( SCIPtreeLoadLP(tree, blkmem, set, eventqueue, eventfilter, lp, &initroot) );
1338 assert(initroot || SCIPnodeGetDepth(SCIPtreeGetFocusNode(tree)) > 0);
1340
1341 /* apply cuts */
1342 SCIP_CALL( SCIPsepastoreApplyCuts(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
1343 eventqueue, eventfilter, cliquetable, (SCIPtreeGetCurrentDepth(tree) == 0), SCIP_EFFICIACYCHOICE_LP, cutoff) );
1344 }
1345 else
1346 {
1347 /* the current node will be cut off; we clear the sepastore */
1348 SCIP_CALL( SCIPsepastoreClearCuts(sepastore, blkmem, set, eventqueue, eventfilter, lp) );
1349 }
1350
1351 /* inform separation storage, that initial LP setup is now finished */
1352 SCIPsepastoreEndInitialLP(sepastore);
1353
1354 if( !(*cutoff) )
1355 {
1356 /* setup initial LP relaxation of node */
1357 SCIP_CALL( initLP(blkmem, set, stat, transprob, origprob, tree, reopt, lp, pricestore, sepastore, cutpool, branchcand,
1358 eventqueue, eventfilter, cliquetable, initroot, cutoff) );
1359 }
1360 }
1361 else if( newinitconss )
1362 {
1363 SCIP_CALL( SCIPinitConssLP(blkmem, set, sepastore, cutpool, stat, transprob,
1364 origprob, tree, reopt, lp, branchcand, eventqueue, eventfilter, cliquetable, FALSE, FALSE,
1365 cutoff) );
1366 }
1367
1368 return SCIP_OKAY;
1369}
1370
1371/** updates the primal ray stored in primal data
1372 * clears previously stored primal ray, if existing and there was no LP error
1373 * stores current primal ray, if LP is unbounded and there has been no error
1374 */
1375static
1377 BMS_BLKMEM* blkmem, /**< block memory buffers */
1378 SCIP_SET* set, /**< global SCIP settings */
1379 SCIP_STAT* stat, /**< dynamic problem statistics */
1380 SCIP_PROB* prob, /**< transformed problem after presolve */
1381 SCIP_PRIMAL* primal, /**< primal data */
1382 SCIP_TREE* tree, /**< branch and bound tree */
1383 SCIP_LP* lp, /**< LP data */
1384 SCIP_Bool lperror /**< has there been an LP error? */
1385 )
1386{
1387 assert(blkmem != NULL);
1388 assert(set != NULL);
1389 assert(stat != NULL);
1390 assert(prob != NULL);
1391 assert(primal != NULL);
1392 assert(tree != NULL);
1393 assert(lp != NULL);
1394
1395 if( lperror )
1396 return SCIP_OKAY;
1397
1398 /* clear previously stored primal ray, if any */
1399 if( primal->primalray != NULL )
1400 {
1401 SCIP_CALL( SCIPsolFree(&primal->primalray, blkmem, primal) );
1402 }
1403
1404 /* store unbounded ray, if LP is unbounded */
1406 {
1407 SCIP_VAR** vars;
1408 SCIP_Real* ray;
1409 int nvars;
1410 int i;
1411
1412 SCIPsetDebugMsg(set, "LP is unbounded, store primal ray\n");
1413
1414 vars = prob->vars;
1415 nvars = prob->nvars;
1416
1417 /* get buffer memory for storing the ray and load the ray values into it */
1418 SCIP_CALL( SCIPsetAllocBufferArray(set, &ray, nvars) );
1419 BMSclearMemoryArray(ray, nvars);
1420 SCIP_CALL( SCIPlpGetPrimalRay(lp, set, ray) );
1421
1422 /* create solution to store the primal ray in */
1423 assert(primal->primalray == NULL);
1424 SCIP_CALL( SCIPsolCreate(&primal->primalray, blkmem, set, stat, primal, tree, NULL) );
1425
1426 /* set values of all active variable in the solution that represents the primal ray */
1427 for( i = 0; i < nvars; i++ )
1428 {
1429 SCIP_CALL( SCIPsolSetVal(primal->primalray, set, stat, tree, vars[i], ray[i]) );
1430 }
1431
1432 SCIPdebug( SCIP_CALL( SCIPprintRay(set->scip, primal->primalray, NULL, FALSE) ) );
1433
1434 /* free memory for buffering the ray values */
1436 }
1437
1438 return SCIP_OKAY;
1439}
1440
1441/** load and solve the initial LP of a node */
1442static
1444 BMS_BLKMEM* blkmem, /**< block memory buffers */
1445 SCIP_SET* set, /**< global SCIP settings */
1446 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
1447 SCIP_STAT* stat, /**< dynamic problem statistics */
1448 SCIP_PROB* transprob, /**< transformed problem after presolve */
1449 SCIP_PROB* origprob, /**< original problem */
1450 SCIP_PRIMAL* primal, /**< primal data */
1451 SCIP_TREE* tree, /**< branch and bound tree */
1452 SCIP_REOPT* reopt, /**< reoptimization data structure */
1453 SCIP_LP* lp, /**< LP data */
1454 SCIP_PRICESTORE* pricestore, /**< pricing storage */
1455 SCIP_SEPASTORE* sepastore, /**< separation storage */
1456 SCIP_CUTPOOL* cutpool, /**< global cutpool */
1457 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1458 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
1459 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1460 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1461 SCIP_Bool newinitconss, /**< do we have to add new initial constraints? */
1462 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
1463 SCIP_Bool* lperror /**< pointer to store whether an unresolved error in LP solving occured */
1464 )
1465{
1466 /* initializing variables for compiler warnings, which are not correct */
1467 SCIP_Real starttime = 0.0;
1468 SCIP_Longint nlpiterations = 0;
1469 SCIP_NODE* focusnode;
1470
1471 assert(stat != NULL);
1472 assert(tree != NULL);
1473 assert(lp != NULL);
1474 assert(cutoff != NULL);
1475 assert(lperror != NULL);
1476 assert(SCIPtreeGetFocusNode(tree) != NULL);
1478
1479 *cutoff = FALSE;
1480 *lperror = FALSE;
1481
1482 /* load the LP into the solver */
1483 SCIP_CALL( SCIPconstructCurrentLP(blkmem, set, stat, transprob, origprob, tree, reopt, lp, pricestore, sepastore, cutpool,
1484 branchcand, eventqueue, eventfilter, cliquetable, newinitconss, cutoff) );
1485
1486 if( *cutoff )
1487 return SCIP_OKAY;
1488
1489 /* load the LP state */
1490 SCIP_CALL( SCIPtreeLoadLPState(tree, blkmem, set, transprob, stat, eventqueue, lp) );
1491
1492 focusnode = SCIPtreeGetFocusNode(tree);
1493
1494 /* store current LP iteration count and solving time if we are at the root node */
1495 if( focusnode->depth == 0 )
1496 {
1497 nlpiterations = stat->nlpiterations;
1498 starttime = SCIPclockGetTime(stat->solvingtime);
1499 }
1500
1501 /* solve initial LP */
1502 SCIPsetDebugMsg(set, "node: solve initial LP\n");
1503 SCIP_CALL( SCIPlpSolveAndEval(lp, set, messagehdlr, blkmem, stat, eventqueue, eventfilter, transprob,
1504 SCIPnodeGetDepth(SCIPtreeGetFocusNode(tree)) == 0 ? set->lp_rootiterlim : set->lp_iterlim, TRUE, TRUE, FALSE, lperror) );
1505 assert(lp->flushed);
1506 assert(lp->solved || *lperror);
1507
1508 /* save time for very first LP in root node */
1509 if ( stat->nnodelps == 0 && focusnode->depth == 0 )
1510 {
1511 stat->firstlptime = SCIPclockGetTime(stat->solvingtime) - starttime;
1512 }
1513
1514 /* remove previous primal ray, store new one if LP is unbounded */
1515 SCIP_CALL( updatePrimalRay(blkmem, set, stat, transprob, primal, tree, lp, *lperror) );
1516
1517 if( !(*lperror) )
1518 {
1519 /* cppcheck-suppress unassignedVariable */
1520 SCIP_EVENT event;
1521
1523 {
1524 /* issue FIRSTLPSOLVED event */
1527 SCIP_CALL( SCIPeventProcess(&event, set, NULL, NULL, NULL, eventfilter) );
1528 }
1529
1530 /* update pseudo cost values for integer variables (always) and for continuous variables (if not delayed) */
1531 SCIP_CALL( updatePseudocost(set, stat, transprob, tree, lp, TRUE, !set->branch_delaypscost) );
1532
1533 /* update lower bound of current node w.r.t. initial lp */
1534 assert(!(*cutoff));
1537 && SCIPprobAllColsInLP(transprob, set, lp) && SCIPlpIsRelax(lp) )
1538 {
1539 SCIP_CALL( SCIPnodeUpdateLowerboundLP(focusnode, set, stat, tree, transprob, origprob, lp) );
1540
1541 /* if this is the first LP solved at the root, store its iteration count and solution value */
1542 if( stat->nnodelps == 0 && focusnode->depth == 0 )
1543 {
1544 SCIP_Real lowerbound;
1545
1546 assert(stat->nrootfirstlpiterations == 0);
1547 stat->nrootfirstlpiterations = stat->nlpiterations - nlpiterations;
1548
1549 if( set->misc_exactsolve )
1550 {
1551 SCIP_CALL( SCIPlpGetProvedLowerbound(lp, set, &lowerbound) );
1552 }
1553 else
1554 lowerbound = SCIPlpGetObjval(lp, set, transprob);
1555
1556 stat->firstlpdualbound = SCIPprobExternObjval(transprob, origprob, set, lowerbound);
1557 }
1558 }
1559 }
1560
1561 return SCIP_OKAY;
1562}
1563
1564/** makes sure the LP is flushed and solved */
1565static
1567 BMS_BLKMEM* blkmem, /**< block memory buffers */
1568 SCIP_SET* set, /**< global SCIP settings */
1569 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
1570 SCIP_STAT* stat, /**< dynamic problem statistics */
1571 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1572 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
1573 SCIP_PROB* prob, /**< transformed problem after presolve */
1574 SCIP_PRIMAL* primal, /**< primal data */
1575 SCIP_TREE* tree, /**< branch and bound tree */
1576 SCIP_LP* lp, /**< LP data */
1577 SCIP_Bool* lperror, /**< pointer to store whether an unresolved error in LP solving occured */
1578 SCIP_Bool* mustsepa, /**< pointer to store TRUE if additional separation rounds should be performed */
1579 SCIP_Bool* mustprice /**< pointer to store TRUE if additional pricing rounds should be performed */
1580 )
1581{
1582 assert(lp != NULL);
1583 assert(lperror != NULL);
1584 assert(mustsepa != NULL);
1585 assert(mustprice != NULL);
1586
1587 /* if bound changes were applied in the separation round, we have to resolve the LP */
1588 if( !lp->flushed )
1589 {
1590 /* solve LP (with dual simplex) */
1591 SCIPsetDebugMsg(set, "separation: resolve LP\n");
1592 SCIP_CALL( SCIPlpSolveAndEval(lp, set, messagehdlr, blkmem, stat, eventqueue, eventfilter, prob, set->lp_iterlim, FALSE, TRUE, FALSE, lperror) );
1593 assert(lp->flushed);
1594 assert(lp->solved || *lperror);
1595 *mustsepa = TRUE;
1596 *mustprice = TRUE;
1597
1598 /* remove previous primal ray, store new one if LP is unbounded */
1599 SCIP_CALL( updatePrimalRay(blkmem, set, stat, prob, primal, tree, lp, *lperror) );
1600 }
1601
1602 return SCIP_OKAY;
1603}
1604
1605/** applies one round of LP separation */
1606static
1608 BMS_BLKMEM* blkmem, /**< block memory buffers */
1609 SCIP_SET* set, /**< global SCIP settings */
1610 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
1611 SCIP_STAT* stat, /**< dynamic problem statistics */
1612 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1613 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
1614 SCIP_PROB* prob, /**< transformed problem after presolve */
1615 SCIP_PRIMAL* primal, /**< primal data */
1616 SCIP_TREE* tree, /**< branch and bound tree */
1617 SCIP_LP* lp, /**< LP data */
1618 SCIP_SEPASTORE* sepastore, /**< separation storage */
1619 int actdepth, /**< current depth in the tree */
1620 SCIP_Real bounddist, /**< current relative distance of local dual bound to global dual bound */
1621 SCIP_Bool allowlocal, /**< should the separators be asked to separate local cuts */
1622 SCIP_Bool onlydelayed, /**< should only delayed separators be called? */
1623 SCIP_Bool* delayed, /**< pointer to store whether a separator was delayed */
1624 SCIP_Bool* enoughcuts, /**< pointer to store whether enough cuts have been found this round */
1625 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
1626 SCIP_Bool* lperror, /**< pointer to store whether an unresolved error in LP solving occured */
1627 SCIP_Bool* mustsepa, /**< pointer to store TRUE if additional separation rounds should be performed */
1628 SCIP_Bool* mustprice /**< pointer to store TRUE if additional pricing rounds should be performed */
1629 )
1630{
1631 SCIP_RESULT result;
1632 int i;
1633 SCIP_Bool consadded;
1634 SCIP_Bool root;
1635
1636 assert(set != NULL);
1637 assert(lp != NULL);
1638 assert(set->conshdlrs_sepa != NULL);
1639 assert(delayed != NULL);
1640 assert(enoughcuts != NULL);
1641 assert(cutoff != NULL);
1642 assert(lperror != NULL);
1643
1644 root = (actdepth == 0);
1645 *delayed = FALSE;
1647 *enoughcuts = TRUE;
1649 *enoughcuts = FALSE;
1650 else
1651 *enoughcuts = (SCIPsepastoreGetNCuts(sepastore) >= (SCIP_Longint)SCIPsetCeil(set,
1653 *lperror = FALSE;
1654 consadded = FALSE;
1655
1656 SCIPsetDebugMsg(set, "calling separators on LP solution in depth %d (onlydelayed: %u)\n", actdepth, onlydelayed);
1657
1658 /* sort separators by priority */
1660
1661 /* call LP separators with nonnegative priority */
1662 for( i = 0; i < set->nsepas && !(*cutoff) && !(*lperror) && !(*enoughcuts) && lp->flushed && lp->solved
1664 ++i )
1665 {
1666#ifndef NDEBUG
1667 size_t nusedbuffer = BMSgetNUsedBufferMemory(SCIPbuffer(set->scip));
1668#endif
1669
1670 if( SCIPsepaGetPriority(set->sepas[i]) < 0 )
1671 continue;
1672
1673 if( onlydelayed && !SCIPsepaWasLPDelayed(set->sepas[i]) )
1674 continue;
1675
1676 SCIPsetDebugMsg(set, " -> executing separator <%s> with priority %d\n",
1677 SCIPsepaGetName(set->sepas[i]), SCIPsepaGetPriority(set->sepas[i]));
1678 SCIP_CALL( SCIPsepaExecLP(set->sepas[i], set, stat, sepastore, actdepth, bounddist, allowlocal, onlydelayed, &result) );
1679#ifndef NDEBUG
1680 if( BMSgetNUsedBufferMemory(SCIPbuffer(set->scip)) > nusedbuffer )
1681 {
1682 SCIPerrorMessage("Buffer not completely freed after executing separator <%s>\n", SCIPsepaGetName(set->sepas[i]));
1683 SCIPABORT();
1684 }
1685#endif
1686 *cutoff = *cutoff || (result == SCIP_CUTOFF);
1687 consadded = consadded || (result == SCIP_CONSADDED);
1689 *enoughcuts = TRUE;
1691 *enoughcuts = *enoughcuts || (result == SCIP_NEWROUND);
1692 else
1693 {
1694 *enoughcuts = *enoughcuts || (SCIPsepastoreGetNCuts(sepastore) >= (SCIP_Longint)SCIPsetCeil(set,
1696 || (result == SCIP_NEWROUND);
1697 }
1698 *delayed = *delayed || (result == SCIP_DELAYED);
1699
1700 if( !(*cutoff) )
1701 {
1702 /* make sure the LP is solved (after adding bound changes, LP has to be flushed and resolved) */
1703 SCIP_CALL( separationRoundResolveLP(blkmem, set, messagehdlr, stat, eventqueue, eventfilter, prob, primal, tree, lp, lperror, mustsepa, mustprice) );
1704 }
1705 else
1706 {
1707 SCIPsetDebugMsg(set, " -> separator <%s> detected cutoff\n", SCIPsepaGetName(set->sepas[i]));
1708 }
1709
1710 /* if we work off the delayed separators, we stop immediately if a cut was found */
1711 if( onlydelayed && (result == SCIP_CONSADDED || result == SCIP_REDUCEDDOM || result == SCIP_SEPARATED || result == SCIP_NEWROUND) )
1712 {
1713 SCIPsetDebugMsg(set, " -> delayed separator <%s> found a cut\n", SCIPsepaGetName(set->sepas[i]));
1714 *delayed = TRUE;
1715 return SCIP_OKAY;
1716 }
1717 }
1718
1719 /* try separating constraints of the constraint handlers */
1720 for( i = 0; i < set->nconshdlrs && !(*cutoff) && !(*lperror) && !(*enoughcuts) && lp->flushed && lp->solved
1722 ++i )
1723 {
1724 if( onlydelayed && !SCIPconshdlrWasLPSeparationDelayed(set->conshdlrs_sepa[i]) )
1725 continue;
1726
1727 SCIPsetDebugMsg(set, " -> executing separation of constraint handler <%s> with priority %d\n",
1728 SCIPconshdlrGetName(set->conshdlrs_sepa[i]), SCIPconshdlrGetSepaPriority(set->conshdlrs_sepa[i]));
1729 SCIP_CALL( SCIPconshdlrSeparateLP(set->conshdlrs_sepa[i], blkmem, set, stat, sepastore, actdepth, onlydelayed,
1730 &result) );
1731
1732 *cutoff = *cutoff || (result == SCIP_CUTOFF);
1733 consadded = consadded || (result == SCIP_CONSADDED);
1735 *enoughcuts = TRUE;
1737 *enoughcuts = *enoughcuts || (result == SCIP_NEWROUND);
1738 else
1739 {
1740 *enoughcuts = *enoughcuts || (SCIPsepastoreGetNCuts(sepastore) >= (SCIP_Longint)SCIPsetCeil(set,
1742 || (result == SCIP_NEWROUND);
1743 }
1744 *delayed = *delayed || (result == SCIP_DELAYED);
1745
1746 if( !(*cutoff) )
1747 {
1748 /* make sure the LP is solved (after adding bound changes, LP has to be flushed and resolved) */
1749 SCIP_CALL( separationRoundResolveLP(blkmem, set, messagehdlr, stat, eventqueue, eventfilter, prob, primal, tree, lp, lperror, mustsepa, mustprice) );
1750 }
1751 else
1752 {
1753 SCIPsetDebugMsg(set, " -> constraint handler <%s> detected cutoff in separation\n", SCIPconshdlrGetName(set->conshdlrs_sepa[i]));
1754 }
1755
1756 /* if we work off the delayed separators, we stop immediately if a cut was found */
1757 if( onlydelayed && (result == SCIP_CONSADDED || result == SCIP_REDUCEDDOM || result == SCIP_SEPARATED || result == SCIP_NEWROUND) )
1758 {
1759 SCIPsetDebugMsg(set, " -> delayed constraint handler <%s> found a cut\n",
1760 SCIPconshdlrGetName(set->conshdlrs_sepa[i]));
1761 *delayed = TRUE;
1762 return SCIP_OKAY;
1763 }
1764 }
1765
1766 /* call LP separators with negative priority */
1767 for( i = 0; i < set->nsepas && !(*cutoff) && !(*lperror) && !(*enoughcuts) && lp->flushed && lp->solved
1769 ++i )
1770 {
1771 if( SCIPsepaGetPriority(set->sepas[i]) >= 0 )
1772 continue;
1773
1774 if( onlydelayed && !SCIPsepaWasLPDelayed(set->sepas[i]) )
1775 continue;
1776
1777 SCIPsetDebugMsg(set, " -> executing separator <%s> with priority %d\n",
1778 SCIPsepaGetName(set->sepas[i]), SCIPsepaGetPriority(set->sepas[i]));
1779 SCIP_CALL( SCIPsepaExecLP(set->sepas[i], set, stat, sepastore, actdepth, bounddist, allowlocal, onlydelayed, &result) );
1780
1781 *cutoff = *cutoff || (result == SCIP_CUTOFF);
1782 consadded = consadded || (result == SCIP_CONSADDED);
1784 *enoughcuts = TRUE;
1786 *enoughcuts = *enoughcuts || (result == SCIP_NEWROUND);
1787 else
1788 {
1789 *enoughcuts = *enoughcuts || (SCIPsepastoreGetNCuts(sepastore) >= (SCIP_Longint)SCIPsetCeil(set,
1791 || (result == SCIP_NEWROUND);
1792 }
1793 *delayed = *delayed || (result == SCIP_DELAYED);
1794
1795 if( !(*cutoff) )
1796 {
1797 /* make sure the LP is solved (after adding bound changes, LP has to be flushed and resolved) */
1798 SCIP_CALL( separationRoundResolveLP(blkmem, set, messagehdlr, stat, eventqueue, eventfilter, prob, primal, tree, lp, lperror, mustsepa, mustprice) );
1799 }
1800 else
1801 {
1802 SCIPsetDebugMsg(set, " -> separator <%s> detected cutoff\n", SCIPsepaGetName(set->sepas[i]));
1803 }
1804
1805 /* if we work off the delayed separators, we stop immediately if a cut was found */
1806 if( onlydelayed && (result == SCIP_CONSADDED || result == SCIP_REDUCEDDOM || result == SCIP_SEPARATED || result == SCIP_NEWROUND) )
1807 {
1808 SCIPsetDebugMsg(set, " -> delayed separator <%s> found a cut\n", SCIPsepaGetName(set->sepas[i]));
1809 *delayed = TRUE;
1810 return SCIP_OKAY;
1811 }
1812 }
1813
1814 /* process the constraints that were added during this separation round */
1815 while( consadded )
1816 {
1817 assert(!onlydelayed);
1818 consadded = FALSE;
1819
1820 for( i = 0; i < set->nconshdlrs && !(*cutoff) && !(*lperror) && !(*enoughcuts) && lp->flushed && lp->solved
1822 ++i )
1823 {
1824 SCIPsetDebugMsg(set, " -> executing separation of constraint handler <%s> with priority %d\n",
1825 SCIPconshdlrGetName(set->conshdlrs_sepa[i]), SCIPconshdlrGetSepaPriority(set->conshdlrs_sepa[i]));
1826 SCIP_CALL( SCIPconshdlrSeparateLP(set->conshdlrs_sepa[i], blkmem, set, stat, sepastore, actdepth, onlydelayed,
1827 &result) );
1828
1829 *cutoff = *cutoff || (result == SCIP_CUTOFF);
1830 consadded = consadded || (result == SCIP_CONSADDED);
1832 *enoughcuts = TRUE;
1834 *enoughcuts = *enoughcuts || (result == SCIP_NEWROUND);
1835 else
1836 {
1837 *enoughcuts = *enoughcuts || (SCIPsepastoreGetNCuts(sepastore) >= (SCIP_Longint)SCIPsetCeil(set,
1839 || (result == SCIP_NEWROUND);
1840 }
1841 *delayed = *delayed || (result == SCIP_DELAYED);
1842
1843 if( !(*cutoff) )
1844 {
1845 /* make sure the LP is solved (after adding bound changes, LP has to be flushed and resolved) */
1846 SCIP_CALL( separationRoundResolveLP(blkmem, set, messagehdlr, stat, eventqueue, eventfilter, prob, primal, tree, lp, lperror, mustsepa, mustprice) );
1847 }
1848 else
1849 {
1850 SCIPsetDebugMsg(set, " -> constraint handler <%s> detected cutoff in separation\n", SCIPconshdlrGetName(set->conshdlrs_sepa[i]));
1851 }
1852 }
1853 }
1854
1855 SCIPsetDebugMsg(set, " -> separation round finished: delayed=%u, enoughcuts=%u, lpflushed=%u, cutoff=%u\n",
1856 *delayed, *enoughcuts, lp->flushed, *cutoff);
1857
1858 return SCIP_OKAY;
1859}
1860
1861/** applies one round of separation on the given primal solution */
1862static
1864 BMS_BLKMEM* blkmem, /**< block memory buffers */
1865 SCIP_SET* set, /**< global SCIP settings */
1866 SCIP_STAT* stat, /**< dynamic problem statistics */
1867 SCIP_SEPASTORE* sepastore, /**< separation storage */
1868 SCIP_SOL* sol, /**< primal solution that should be separated, or NULL for LP solution */
1869 int actdepth, /**< current depth in the tree */
1870 SCIP_Bool allowlocal, /**< should the separator be asked to separate local cuts */
1871 SCIP_Bool onlydelayed, /**< should only delayed separators be called? */
1872 SCIP_Bool* delayed, /**< pointer to store whether a separator was delayed */
1873 SCIP_Bool* enoughcuts, /**< pointer to store whether enough cuts have been found this round */
1874 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
1875 )
1876{
1877 SCIP_RESULT result;
1878 int i;
1879 SCIP_Bool consadded;
1880 SCIP_Bool root;
1881
1882 assert(set != NULL);
1883 assert(set->conshdlrs_sepa != NULL);
1884 assert(delayed != NULL);
1885 assert(enoughcuts != NULL);
1886 assert(cutoff != NULL);
1887
1888 *delayed = FALSE;
1889 *enoughcuts = FALSE;
1890 consadded = FALSE;
1891 root = (actdepth == 0);
1892
1893 SCIPsetDebugMsg(set, "calling separators on primal solution in depth %d (onlydelayed: %u)\n", actdepth, onlydelayed);
1894
1895 /* sort separators by priority */
1897
1898 /* call separators with nonnegative priority */
1899 for( i = 0; i < set->nsepas && !(*cutoff) && !(*enoughcuts) && !SCIPsolveIsStopped(set, stat, FALSE); ++i )
1900 {
1901 if( SCIPsepaGetPriority(set->sepas[i]) < 0 )
1902 continue;
1903
1904 if( onlydelayed && !SCIPsepaWasSolDelayed(set->sepas[i]) )
1905 continue;
1906
1907 SCIP_CALL( SCIPsepaExecSol(set->sepas[i], set, stat, sepastore, sol, actdepth, allowlocal, onlydelayed, &result) );
1908 *cutoff = *cutoff || (result == SCIP_CUTOFF);
1909 consadded = consadded || (result == SCIP_CONSADDED);
1911 *enoughcuts = TRUE;
1913 *enoughcuts = *enoughcuts || (result == SCIP_NEWROUND);
1914 else
1915 {
1916 *enoughcuts = *enoughcuts || (SCIPsepastoreGetNCuts(sepastore) >= (SCIP_Longint)SCIPsetCeil(set,
1918 || (result == SCIP_NEWROUND);
1919 }
1920 *delayed = *delayed || (result == SCIP_DELAYED);
1921 if( *cutoff )
1922 {
1923 SCIPsetDebugMsg(set, " -> separator <%s> detected cutoff\n", SCIPsepaGetName(set->sepas[i]));
1924 }
1925
1926 /* if we work off the delayed separators, we stop immediately if a cut was found */
1927 if( onlydelayed && (result == SCIP_CONSADDED || result == SCIP_REDUCEDDOM || result == SCIP_SEPARATED || result == SCIP_NEWROUND) )
1928 {
1929 *delayed = TRUE;
1930 return SCIP_OKAY;
1931 }
1932 }
1933
1934 /* try separating constraints of the constraint handlers */
1935 for( i = 0; i < set->nconshdlrs && !(*cutoff) && !(*enoughcuts) && !SCIPsolveIsStopped(set, stat, FALSE); ++i )
1936 {
1937 if( onlydelayed && !SCIPconshdlrWasSolSeparationDelayed(set->conshdlrs_sepa[i]) )
1938 continue;
1939
1940 SCIP_CALL( SCIPconshdlrSeparateSol(set->conshdlrs_sepa[i], blkmem, set, stat, sepastore, sol, actdepth, onlydelayed,
1941 &result) );
1942 *cutoff = *cutoff || (result == SCIP_CUTOFF);
1943 consadded = consadded || (result == SCIP_CONSADDED);
1945 *enoughcuts = TRUE;
1947 *enoughcuts = *enoughcuts || (result == SCIP_NEWROUND);
1948 else
1949 {
1950 *enoughcuts = *enoughcuts || (SCIPsepastoreGetNCuts(sepastore) >= (SCIP_Longint)SCIPsetCeil(set,
1952 || (result == SCIP_NEWROUND);
1953 }
1954 *delayed = *delayed || (result == SCIP_DELAYED);
1955 if( *cutoff )
1956 {
1957 SCIPsetDebugMsg(set, " -> constraint handler <%s> detected cutoff in separation\n",
1958 SCIPconshdlrGetName(set->conshdlrs_sepa[i]));
1959 }
1960
1961 /* if we work off the delayed separators, we stop immediately if a cut was found */
1962 if( onlydelayed && (result == SCIP_CONSADDED || result == SCIP_REDUCEDDOM || result == SCIP_SEPARATED || result == SCIP_NEWROUND) )
1963 {
1964 *delayed = TRUE;
1965 return SCIP_OKAY;
1966 }
1967 }
1968
1969 /* call separators with negative priority */
1970 for( i = 0; i < set->nsepas && !(*cutoff) && !(*enoughcuts) && !SCIPsolveIsStopped(set, stat, FALSE); ++i )
1971 {
1972 if( SCIPsepaGetPriority(set->sepas[i]) >= 0 )
1973 continue;
1974
1975 if( onlydelayed && !SCIPsepaWasSolDelayed(set->sepas[i]) )
1976 continue;
1977
1978 SCIP_CALL( SCIPsepaExecSol(set->sepas[i], set, stat, sepastore, sol, actdepth, allowlocal, onlydelayed, &result) );
1979 *cutoff = *cutoff || (result == SCIP_CUTOFF);
1980 consadded = consadded || (result == SCIP_CONSADDED);
1982 *enoughcuts = TRUE;
1984 *enoughcuts = *enoughcuts || (result == SCIP_NEWROUND);
1985 else
1986 {
1987 *enoughcuts = *enoughcuts || (SCIPsepastoreGetNCuts(sepastore) >= (SCIP_Longint)SCIPsetCeil(set,
1989 || (result == SCIP_NEWROUND);
1990 }
1991 *delayed = *delayed || (result == SCIP_DELAYED);
1992 if( *cutoff )
1993 {
1994 SCIPsetDebugMsg(set, " -> separator <%s> detected cutoff\n", SCIPsepaGetName(set->sepas[i]));
1995 }
1996
1997 /* if we work off the delayed separators, we stop immediately if a cut was found */
1998 if( onlydelayed && (result == SCIP_CONSADDED || result == SCIP_REDUCEDDOM || result == SCIP_SEPARATED || result == SCIP_NEWROUND) )
1999 {
2000 *delayed = TRUE;
2001 return SCIP_OKAY;
2002 }
2003 }
2004
2005 /* process the constraints that were added during this separation round */
2006 while( consadded )
2007 {
2008 assert(!onlydelayed);
2009 consadded = FALSE;
2010
2011 for( i = 0; i < set->nconshdlrs && !(*cutoff) && !(*enoughcuts) && !SCIPsolveIsStopped(set, stat, FALSE); ++i )
2012 {
2013 SCIP_CALL( SCIPconshdlrSeparateSol(set->conshdlrs_sepa[i], blkmem, set, stat, sepastore, sol, actdepth, onlydelayed, &result) );
2014 *cutoff = *cutoff || (result == SCIP_CUTOFF);
2015 consadded = consadded || (result == SCIP_CONSADDED);
2017 *enoughcuts = TRUE;
2019 *enoughcuts = *enoughcuts || (result == SCIP_NEWROUND);
2020 else
2021 {
2022 *enoughcuts = *enoughcuts || (SCIPsepastoreGetNCuts(sepastore) >= (SCIP_Longint)SCIPsetCeil(set,
2024 || (result == SCIP_NEWROUND);
2025 }
2026 *delayed = *delayed || (result == SCIP_DELAYED);
2027 if( *cutoff )
2028 {
2029 SCIPsetDebugMsg(set, " -> constraint handler <%s> detected cutoff in separation\n",
2030 SCIPconshdlrGetName(set->conshdlrs_sepa[i]));
2031 }
2032 }
2033 }
2034
2035 SCIPsetDebugMsg(set, " -> separation round finished: delayed=%u, enoughcuts=%u, cutoff=%u\n",
2036 *delayed, *enoughcuts, *cutoff);
2037
2038 return SCIP_OKAY;
2039}
2040
2041/** applies one round of separation on the given primal solution or on the LP solution */
2043 BMS_BLKMEM* blkmem, /**< block memory buffers */
2044 SCIP_SET* set, /**< global SCIP settings */
2045 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2046 SCIP_STAT* stat, /**< dynamic problem statistics */
2047 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2048 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
2049 SCIP_PROB* prob, /**< transformed problem after presolve */
2050 SCIP_PRIMAL* primal, /**< primal data */
2051 SCIP_TREE* tree, /**< branch and bound tree */
2052 SCIP_LP* lp, /**< LP data */
2053 SCIP_SEPASTORE* sepastore, /**< separation storage */
2054 SCIP_SOL* sol, /**< primal solution that should be separated, or NULL for LP solution */
2055 int actdepth, /**< current depth in the tree */
2056 SCIP_Bool allowlocal, /**< should the separator be asked to separate local cuts */
2057 SCIP_Bool onlydelayed, /**< should only delayed separators be called? */
2058 SCIP_Bool* delayed, /**< pointer to store whether a separator was delayed */
2059 SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
2060 )
2061{
2062 SCIP_Bool enoughcuts;
2063
2064 assert(delayed != NULL);
2065 assert(cutoff != NULL);
2066
2067 *delayed = FALSE;
2068 *cutoff = FALSE;
2069 enoughcuts = FALSE;
2070
2071 if( sol == NULL )
2072 {
2073 SCIP_Bool lperror;
2074 SCIP_Bool mustsepa;
2075 SCIP_Bool mustprice;
2076
2077 /* apply a separation round on the LP solution */
2078 lperror = FALSE;
2079 mustsepa = FALSE;
2080 mustprice = FALSE;
2081 SCIP_CALL( separationRoundLP(blkmem, set, messagehdlr, stat, eventqueue, eventfilter, prob, primal, tree, lp, sepastore, \
2082 actdepth, 0.0, allowlocal, onlydelayed, delayed, &enoughcuts, cutoff, \
2083 &lperror, &mustsepa, &mustprice) );
2084 }
2085 else
2086 {
2087 /* apply a separation round on the given primal solution */
2088 SCIP_CALL( separationRoundSol(blkmem, set, stat, sepastore, sol, actdepth, allowlocal, onlydelayed, delayed, &enoughcuts, cutoff) );
2089 }
2090
2091 return SCIP_OKAY;
2092}
2093
2094/** solves the current LP completely with pricing in new variables */
2096 BMS_BLKMEM* blkmem, /**< block memory buffers */
2097 SCIP_SET* set, /**< global SCIP settings */
2098 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2099 SCIP_STAT* stat, /**< dynamic problem statistics */
2100 SCIP_PROB* transprob, /**< transformed problem */
2101 SCIP_PROB* origprob, /**< original problem */
2102 SCIP_PRIMAL* primal, /**< primal data */
2103 SCIP_TREE* tree, /**< branch and bound tree */
2104 SCIP_REOPT* reopt, /**< reoptimization data structure */
2105 SCIP_LP* lp, /**< LP data */
2106 SCIP_PRICESTORE* pricestore, /**< pricing storage */
2107 SCIP_SEPASTORE* sepastore, /**< separation storage */
2108 SCIP_CUTPOOL* cutpool, /**< global cutpool */
2109 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
2110 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2111 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
2112 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
2113 SCIP_Bool pretendroot, /**< should the pricers be called as if we are at the root node? */
2114 SCIP_Bool displayinfo, /**< should info lines be displayed after each pricing round? */
2115 int maxpricerounds, /**< maximal number of pricing rounds (-1: no limit);
2116 * a finite limit means that the LP might not be solved to optimality! */
2117 int* npricedcolvars, /**< pointer to store number of column variables after problem vars were priced */
2118 SCIP_Bool* mustsepa, /**< pointer to store TRUE if a separation round should follow */
2119 SCIP_Bool* lperror, /**< pointer to store whether an unresolved error in LP solving occured */
2120 SCIP_Bool* aborted /**< pointer to store whether the pricing was aborted and the lower bound must
2121 * not be used */
2122 )
2123{
2124 SCIP_NODE* currentnode;
2125 int npricerounds;
2126 SCIP_Bool mustprice;
2127 SCIP_Bool cutoff;
2128 SCIP_Bool unbounded;
2129
2130 assert(transprob != NULL);
2131 assert(lp != NULL);
2132 assert(lp->flushed);
2133 assert(lp->solved);
2134 assert(npricedcolvars != NULL);
2135 assert(mustsepa != NULL);
2136 assert(lperror != NULL);
2137 assert(aborted != NULL);
2138
2139 currentnode = SCIPtreeGetCurrentNode(tree);
2140 assert(currentnode == SCIPtreeGetFocusNode(tree) || SCIPtreeProbing(tree));
2141 *npricedcolvars = transprob->ncolvars;
2142 *lperror = FALSE;
2143 *aborted = FALSE;
2144
2145 /* if the LP is unbounded, we don't need to price */
2146 mustprice = (SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL
2149
2150 /* if all the variables are already in the LP, we don't need to price */
2151 mustprice = mustprice && !SCIPprobAllColsInLP(transprob, set, lp);
2152
2153 /* check if infinite number of pricing rounds should be used */
2154 if( maxpricerounds == -1 )
2155 maxpricerounds = INT_MAX;
2156
2157 /* pricing (has to be done completely to get a valid lower bound) */
2158 npricerounds = 0;
2159 while( !(*lperror) && mustprice && npricerounds < maxpricerounds )
2160 {
2161 SCIP_Bool enoughvars;
2162 SCIP_RESULT result;
2163 SCIP_Real lb;
2164 SCIP_Bool foundsol;
2165 SCIP_Bool stopearly;
2166 SCIP_Bool stoppricing;
2167 int p;
2168
2169 assert(lp->flushed);
2170 assert(lp->solved);
2172
2173 /* check if pricing loop should be aborted */
2174 if( SCIPsolveIsStopped(set, stat, FALSE) )
2175 {
2176 /* do not print the warning message if we stopped because the problem is solved */
2178 SCIPmessagePrintWarning(messagehdlr, "pricing has been interrupted -- LP of current node is invalid\n");
2179
2180 *aborted = TRUE;
2181 break;
2182 }
2183
2184 /* call primal heuristics which are callable during pricing */
2185 SCIP_CALL( SCIPprimalHeuristics(set, stat, transprob, primal, tree, lp, NULL, SCIP_HEURTIMING_DURINGPRICINGLOOP,
2186 FALSE, &foundsol, &unbounded) );
2187
2188 /* price problem variables */
2189 SCIPsetDebugMsg(set, "problem variable pricing\n");
2190 assert(SCIPpricestoreGetNVars(pricestore) == 0);
2191 assert(SCIPpricestoreGetNBoundResets(pricestore) == 0);
2192 SCIP_CALL( SCIPpricestoreAddProbVars(pricestore, blkmem, set, stat, transprob, tree, lp, branchcand, eventqueue) );
2193 *npricedcolvars = transprob->ncolvars;
2194
2195 /* call external pricers to create additional problem variables */
2196 SCIPsetDebugMsg(set, "external variable pricing\n");
2197
2198 /* sort pricer algorithms by priority */
2200
2201 /* call external pricer algorithms, that are active for the current problem */
2202 enoughvars = (SCIPsetGetPriceMaxvars(set, pretendroot) == INT_MAX ?
2203 FALSE : SCIPpricestoreGetNVars(pricestore) >= SCIPsetGetPriceMaxvars(set, pretendroot) + 1);
2204 stoppricing = FALSE;
2205 for( p = 0; p < set->nactivepricers && !enoughvars; ++p )
2206 {
2207 SCIP_CALL( SCIPpricerExec(set->pricers[p], set, transprob, lp, pricestore, &lb, &stopearly, &result) );
2208 assert(result == SCIP_DIDNOTRUN || result == SCIP_SUCCESS);
2209 SCIPsetDebugMsg(set, "pricing: pricer %s returned result = %s, lowerbound = %f\n",
2210 SCIPpricerGetName(set->pricers[p]), (result == SCIP_DIDNOTRUN ? "didnotrun" : "success"), lb);
2211 enoughvars = enoughvars || (SCIPsetGetPriceMaxvars(set, pretendroot) == INT_MAX ?
2212 FALSE : SCIPpricestoreGetNVars(pricestore) >= SCIPsetGetPriceMaxvars(set, pretendroot) + 1);
2213 *aborted = ( (*aborted) || (result == SCIP_DIDNOTRUN) );
2214
2215 /* set stoppricing to TRUE, if the first pricer wants to stop pricing */
2216 if( p == 0 && stopearly )
2217 stoppricing = TRUE;
2218
2219 /* stoppricing only remains TRUE, if all other pricers want to stop pricing as well */
2220 if( stoppricing && !stopearly )
2221 stoppricing = FALSE;
2222
2223 /* update lower bound w.r.t. the lower bound given by the pricer */
2224 SCIPnodeUpdateLowerbound(currentnode, stat, set, tree, transprob, origprob, lb);
2225 SCIPsetDebugMsg(set, " -> new lower bound given by pricer %s: %g\n", SCIPpricerGetName(set->pricers[p]), lb);
2226 }
2227
2228 /* apply the priced variables to the LP */
2229 SCIP_CALL( SCIPpricestoreApplyVars(pricestore, blkmem, set, stat, eventqueue, transprob, tree, lp) );
2230 assert(SCIPpricestoreGetNVars(pricestore) == 0);
2231 assert(!lp->flushed || lp->solved);
2232 mustprice = !lp->flushed || (transprob->ncolvars != *npricedcolvars);
2233 *mustsepa = *mustsepa || !lp->flushed;
2234
2235 /* after adding columns, the LP should be primal feasible such that the primal simplex is applicable;
2236 * if LP was infeasible, we have to use dual simplex
2237 */
2238 SCIPsetDebugMsg(set, "pricing: solve LP\n");
2239 SCIP_CALL( SCIPlpSolveAndEval(lp, set, messagehdlr, blkmem, stat, eventqueue, eventfilter, transprob, -1LL, FALSE, TRUE, FALSE, lperror) );
2240 assert(lp->flushed);
2241 assert(lp->solved || *lperror);
2242
2243 /* reset bounds temporarily set by pricer to their original values */
2244 SCIPsetDebugMsg(set, "pricing: reset bounds\n");
2245 SCIP_CALL( SCIPpricestoreResetBounds(pricestore, blkmem, set, stat, lp, branchcand, eventqueue) );
2246 assert(SCIPpricestoreGetNVars(pricestore) == 0);
2247 assert(SCIPpricestoreGetNBoundResets(pricestore) == 0);
2248 assert(!lp->flushed || lp->solved || *lperror);
2249
2250 /* put all initial constraints into the LP */
2251 SCIP_CALL( SCIPinitConssLP(blkmem, set, sepastore, cutpool, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
2252 eventfilter, cliquetable, FALSE, FALSE, &cutoff) );
2253 assert(cutoff == FALSE);
2254
2255 mustprice = mustprice || !lp->flushed || (transprob->ncolvars != *npricedcolvars);
2256 *mustsepa = *mustsepa || !lp->flushed;
2257
2258 /* if all pricers wanted to stop pricing, do not do another pricing round (LP value is no valid dual bound in this case) */
2259 if( stoppricing )
2260 {
2261 SCIPsetDebugMsg(set, "pricing: stop pricing and perform early branching\n");
2262 mustprice = FALSE;
2263 *aborted = TRUE;
2264 }
2265
2266 /* solve LP again after resetting bounds and adding new initial constraints (with dual simplex) */
2267 SCIPsetDebugMsg(set, "pricing: solve LP after resetting bounds and adding new initial constraints\n");
2268 SCIP_CALL( SCIPlpSolveAndEval(lp, set, messagehdlr, blkmem, stat, eventqueue, eventfilter, transprob, -1LL, FALSE, FALSE, FALSE, lperror) );
2269 assert(lp->flushed);
2270 assert(lp->solved || *lperror);
2271
2272 /* remove previous primal ray, store new one if LP is unbounded */
2273 SCIP_CALL( updatePrimalRay(blkmem, set, stat, transprob, primal, tree, lp, *lperror) );
2274
2275 /* increase pricing round counter */
2276 stat->npricerounds++;
2277 npricerounds++;
2278
2279 /* display node information line */
2280 if( displayinfo && mustprice )
2281 {
2282 if( (SCIP_VERBLEVEL)set->disp_verblevel >= SCIP_VERBLEVEL_FULL
2283 || ((SCIP_VERBLEVEL)set->disp_verblevel >= SCIP_VERBLEVEL_HIGH && npricerounds % 100 == 1) )
2284 {
2285 SCIP_CALL( SCIPdispPrintLine(set, messagehdlr, stat, NULL, TRUE, TRUE) );
2286 }
2287 }
2288
2289 /* if the LP is unbounded, we can stop pricing */
2290 mustprice = mustprice &&
2294
2295 /* if the lower bound is already higher than the cutoff bound, we can stop pricing */
2296 mustprice = mustprice && SCIPsetIsLT(set, SCIPnodeGetLowerbound(currentnode), primal->cutoffbound);
2297 } /*lint !e438*/
2298 assert(lp->flushed);
2299 assert(lp->solved || *lperror);
2300
2301 *aborted = ( (*aborted) || (*lperror) || SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_NOTSOLVED
2302 || SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_ERROR || npricerounds == maxpricerounds );
2303
2304 /* set information, whether the current lp is a valid relaxation of the current problem */
2305 SCIPlpSetIsRelax(lp, !(*aborted));
2306
2307 return SCIP_OKAY; /*lint !e438*/
2308}
2309
2310/** separates cuts of the cut pool */
2311static
2313 SCIP_CUTPOOL* cutpool, /**< cut pool */
2314 BMS_BLKMEM* blkmem, /**< block memory */
2315 SCIP_SET* set, /**< global SCIP settings */
2316 SCIP_STAT* stat, /**< problem statistics data */
2317 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2318 SCIP_EVENTFILTER* eventfilter, /**< event filter for global events */
2319 SCIP_LP* lp, /**< current LP data */
2320 SCIP_SEPASTORE* sepastore, /**< separation storage */
2321 SCIP_Bool cutpoolisdelayed, /**< is the cutpool delayed (count cuts found)? */
2322 SCIP_Bool root, /**< are we at the root node? */
2323 int actdepth, /**< the depth of the focus node */
2324 SCIP_Bool* enoughcuts, /**< pointer to store if enough cuts were found in current separation round */
2325 SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
2326 )
2327{
2328 if( (set->sepa_poolfreq == 0 && actdepth == 0)
2329 || (set->sepa_poolfreq > 0 && actdepth % set->sepa_poolfreq == 0) )
2330 {
2331 SCIP_RESULT result;
2332
2333 SCIP_CALL( SCIPcutpoolSeparate(cutpool, blkmem, set, stat, eventqueue, eventfilter, lp, sepastore, NULL, cutpoolisdelayed, root, &result) );
2334 *cutoff = *cutoff || (result == SCIP_CUTOFF);
2336 *enoughcuts = TRUE;
2338 *enoughcuts = *enoughcuts || (result == SCIP_NEWROUND);
2339 else
2340 {
2341 *enoughcuts = *enoughcuts || (SCIPsepastoreGetNCuts(sepastore) >= (SCIP_Longint)SCIPsetCeil(set,
2343 || (result == SCIP_NEWROUND);
2344 }
2345 }
2346
2347 return SCIP_OKAY;
2348}
2349
2350/** solve the current LP of a node with a price-and-cut loop */
2351static
2353 BMS_BLKMEM* blkmem, /**< block memory buffers */
2354 SCIP_SET* set, /**< global SCIP settings */
2355 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2356 SCIP_STAT* stat, /**< dynamic problem statistics */
2357 SCIP_MEM* mem, /**< block memory pools */
2358 SCIP_PROB* transprob, /**< transformed problem */
2359 SCIP_PROB* origprob, /**< original problem */
2360 SCIP_PRIMAL* primal, /**< primal data */
2361 SCIP_TREE* tree, /**< branch and bound tree */
2362 SCIP_REOPT* reopt, /**< reoptimization data structure */
2363 SCIP_LP* lp, /**< LP data */
2364 SCIP_PRICESTORE* pricestore, /**< pricing storage */
2365 SCIP_SEPASTORE* sepastore, /**< separation storage */
2366 SCIP_CUTPOOL* cutpool, /**< global cut pool */
2367 SCIP_CUTPOOL* delayedcutpool, /**< global delayed cut pool */
2368 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
2369 SCIP_CONFLICT* conflict, /**< conflict analysis data */
2370 SCIP_CONFLICTSTORE* conflictstore, /**< conflict store */
2371 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
2372 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2373 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
2374 SCIP_Bool fullseparation, /**< are we in the first prop-and-cut-and-price loop? */
2375 SCIP_Bool* propagateagain, /**< pointer to store whether we want to propagate again */
2376 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
2377 SCIP_Bool* unbounded, /**< pointer to store whether an unbounded ray was found in the LP */
2378 SCIP_Bool* lperror, /**< pointer to store whether an unresolved error in LP solving occured */
2379 SCIP_Bool* pricingaborted /**< pointer to store whether the pricing was aborted and the lower bound must
2380 * not be used */
2381 )
2382{
2383 SCIP_NODE* focusnode;
2384 /* cppcheck-suppress unassignedVariable */
2385 SCIP_EVENT event;
2386 SCIP_LPSOLSTAT stalllpsolstat;
2387 SCIP_Real loclowerbound;
2388 SCIP_Real glblowerbound;
2389 SCIP_Real bounddist;
2390 SCIP_Real stalllpobjval;
2391 SCIP_Bool separate;
2392 SCIP_Bool mustprice;
2393 SCIP_Bool mustsepa;
2394 SCIP_Bool delayedsepa;
2395 SCIP_Bool root;
2396 SCIP_Bool allowlocal;
2397 int maxseparounds;
2398 int nsepastallrounds;
2399 int maxnsepastallrounds;
2400 int stallnfracs;
2401 int actdepth;
2402 int npricedcolvars;
2403
2404 assert(set != NULL);
2405 assert(blkmem != NULL);
2406 assert(stat != NULL);
2407 assert(transprob != NULL);
2408 assert(tree != NULL);
2409 assert(lp != NULL);
2410 assert(pricestore != NULL);
2411 assert(sepastore != NULL);
2412 assert(cutpool != NULL);
2413 assert(delayedcutpool != NULL);
2414 assert(primal != NULL);
2415 assert(cutoff != NULL);
2416 assert(unbounded != NULL);
2417 assert(lperror != NULL);
2418
2419 focusnode = SCIPtreeGetFocusNode(tree);
2420 assert(focusnode != NULL);
2421 assert(SCIPnodeGetType(focusnode) == SCIP_NODETYPE_FOCUSNODE);
2422 actdepth = SCIPnodeGetDepth(focusnode);
2423 root = (actdepth == 0);
2424
2425 /* check, if we want to separate at this node */
2426 loclowerbound = SCIPnodeGetLowerbound(focusnode);
2427 glblowerbound = SCIPtreeGetLowerbound(tree, set);
2428 assert(primal->cutoffbound > glblowerbound);
2429 bounddist = (loclowerbound - glblowerbound)/(primal->cutoffbound - glblowerbound);
2430 allowlocal = SCIPsetIsLE(set, bounddist, set->sepa_maxlocalbounddist);
2431 separate = (set->sepa_maxruns == -1 || stat->nruns < set->sepa_maxruns);
2432
2433 /* get maximal number of separation rounds */
2434 maxseparounds = (root ? set->sepa_maxroundsroot : set->sepa_maxrounds);
2435 if( maxseparounds == -1 )
2436 maxseparounds = INT_MAX;
2437 if( stat->nruns > 1 && root && set->sepa_maxroundsrootsubrun >= 0 )
2438 maxseparounds = MIN(maxseparounds, set->sepa_maxroundsrootsubrun);
2439 if( !fullseparation && set->sepa_maxaddrounds >= 0 )
2440 maxseparounds = MIN(maxseparounds, stat->nseparounds + set->sepa_maxaddrounds);
2441 maxnsepastallrounds = root ? set->sepa_maxstallroundsroot : set->sepa_maxstallrounds;
2442 if( maxnsepastallrounds == -1 )
2443 maxnsepastallrounds = INT_MAX;
2444
2445 /* solve initial LP of price-and-cut loop */
2446 SCIPsetDebugMsg(set, "node: solve LP with price and cut\n");
2447 SCIP_CALL( SCIPlpSolveAndEval(lp, set, messagehdlr, blkmem, stat, eventqueue, eventfilter, transprob,
2448 set->lp_iterlim, FALSE, TRUE, FALSE, lperror) );
2449 assert(lp->flushed);
2450 assert(lp->solved || *lperror);
2451
2452 /* remove previous primal ray, store new one if LP is unbounded */
2453 SCIP_CALL( updatePrimalRay(blkmem, set, stat, transprob, primal, tree, lp, *lperror) );
2454
2455 /* price-and-cut loop */
2456 npricedcolvars = transprob->ncolvars;
2457 mustprice = TRUE;
2458 mustsepa = separate;
2459 delayedsepa = FALSE;
2460 *cutoff = FALSE;
2461 *unbounded = (SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_UNBOUNDEDRAY);
2462 nsepastallrounds = 0;
2463 stalllpsolstat = SCIP_LPSOLSTAT_NOTSOLVED;
2464 stalllpobjval = SCIP_REAL_MIN;
2465 stallnfracs = INT_MAX;
2466 lp->installing = FALSE;
2467 while( !(*cutoff) && !(*unbounded) && !(*lperror) && (mustprice || mustsepa || delayedsepa) )
2468 {
2469 SCIPsetDebugMsg(set, "-------- node solving loop --------\n");
2470 assert(lp->flushed);
2471 assert(lp->solved);
2472
2473 /* solve the LP with pricing in new variables */
2474 while( mustprice && !(*lperror) )
2475 {
2476 SCIP_CALL( SCIPpriceLoop(blkmem, set, messagehdlr, stat, transprob, origprob, primal, tree, reopt, lp,
2477 pricestore, sepastore, cutpool, branchcand, eventqueue, eventfilter, cliquetable, root, root, -1, &npricedcolvars,
2478 &mustsepa, lperror, pricingaborted) );
2479
2480 mustprice = FALSE;
2481
2482 assert(lp->flushed);
2483 assert(lp->solved || *lperror);
2484
2485 /* update lower bound w.r.t. the LP solution */
2486 if( !(*lperror) && !(*pricingaborted) && SCIPlpIsRelax(lp) )
2487 {
2488 SCIP_CALL( SCIPnodeUpdateLowerboundLP(focusnode, set, stat, tree, transprob, origprob, lp) );
2489 SCIPsetDebugMsg(set, " -> new lower bound: %g (LP status: %d, LP obj: %g)\n",
2490 SCIPnodeGetLowerbound(focusnode), SCIPlpGetSolstat(lp), SCIPlpGetObjval(lp, set, transprob));
2491
2492 /* update node estimate */
2493 SCIP_CALL( updateEstimate(set, stat, tree, lp, branchcand) );
2494
2495 if( root && SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL )
2496 SCIPprobUpdateBestRootSol(transprob, set, stat, lp);
2497 }
2498 else
2499 {
2500 SCIPsetDebugMsg(set, " -> error solving LP or pricing aborted. keeping old bound: %g\n", SCIPnodeGetLowerbound(focusnode));
2501 }
2502
2503 /* display node information line for root node */
2504 if( root && (SCIP_VERBLEVEL)set->disp_verblevel >= SCIP_VERBLEVEL_HIGH )
2505 {
2506 SCIP_CALL( SCIPdispPrintLine(set, messagehdlr, stat, NULL, TRUE, TRUE) );
2507 }
2508
2509 if( !(*lperror) )
2510 {
2511 /* call propagators that are applicable during LP solving loop only if the node is not cut off */
2512 if( SCIPsetIsLT(set, SCIPnodeGetLowerbound(focusnode), primal->cutoffbound) )
2513 {
2514 SCIP_Longint oldnboundchgs;
2515 SCIP_Longint oldninitconssadded;
2516 SCIP_Bool postpone;
2517
2518 oldnboundchgs = stat->nboundchgs;
2519 oldninitconssadded = stat->ninitconssadded;
2520
2521 SCIPsetDebugMsg(set, " -> LP solved: call propagators that are applicable during LP solving loop\n");
2522
2523 SCIP_CALL( propagateDomains(blkmem, set, stat, tree, SCIPtreeGetCurrentDepth(tree), 0, FALSE,
2524 SCIP_PROPTIMING_DURINGLPLOOP, cutoff, &postpone) );
2525 assert(BMSgetNUsedBufferMemory(mem->buffer) == 0);
2526 assert(!postpone);
2527
2528 if( stat->ninitconssadded != oldninitconssadded )
2529 {
2530 SCIPsetDebugMsg(set, "new initial constraints added during propagation: old=%" SCIP_LONGINT_FORMAT ", new=%" SCIP_LONGINT_FORMAT "\n", oldninitconssadded, stat->ninitconssadded);
2531
2532 SCIP_CALL( SCIPinitConssLP(blkmem, set, sepastore, cutpool, stat, transprob, origprob, tree, reopt, lp,
2533 branchcand, eventqueue, eventfilter, cliquetable, FALSE, FALSE, cutoff) );
2534 }
2535
2536 if( !(*cutoff) && !(*unbounded) )
2537 {
2538 /* if we found something, solve LP again */
2539 if( !lp->flushed )
2540 {
2541 SCIPsetDebugMsg(set, " -> found reduction: resolve LP\n");
2542
2543 /* in the root node, remove redundant rows permanently from the LP */
2544 if( root )
2545 {
2546 SCIP_CALL( SCIPlpFlush(lp, blkmem, set, transprob, eventqueue) );
2547 SCIP_CALL( SCIPlpRemoveRedundantRows(lp, blkmem, set, stat, eventqueue, eventfilter) );
2548 }
2549
2550 /* resolve LP */
2551 SCIP_CALL( SCIPlpSolveAndEval(lp, set, messagehdlr, blkmem, stat, eventqueue, eventfilter, transprob,
2552 set->lp_iterlim, FALSE, TRUE, FALSE, lperror) );
2553 assert(lp->flushed);
2554 assert(lp->solved || *lperror);
2555
2556 /* remove previous primal ray, store new one if LP is unbounded */
2557 SCIP_CALL( updatePrimalRay(blkmem, set, stat, transprob, primal, tree, lp, *lperror) );
2558
2559 mustprice = TRUE;
2560 *propagateagain = TRUE;
2561 }
2562 /* propagation might have changed the best bound of loose variables, thereby changing the loose objective
2563 * value which is added to the LP value; because of the loose status, the LP might not be reoptimized,
2564 * but the lower bound of the node needs to be updated
2565 */
2566 else if( stat->nboundchgs > oldnboundchgs )
2567 {
2568 *propagateagain = TRUE;
2569
2570 if( lp->solved && SCIPprobAllColsInLP(transprob, set, lp) && SCIPlpIsRelax(lp) )
2571 {
2572 assert(lp->flushed);
2573 assert(lp->solved);
2574
2575 SCIP_CALL( SCIPnodeUpdateLowerboundLP(focusnode, set, stat, tree, transprob, origprob, lp) );
2576 SCIPsetDebugMsg(set, " -> new lower bound: %g (LP status: %d, LP obj: %g)\n",
2577 SCIPnodeGetLowerbound(focusnode), SCIPlpGetSolstat(lp), SCIPlpGetObjval(lp, set, transprob));
2578
2579 /* update node estimate */
2580 SCIP_CALL( updateEstimate(set, stat, tree, lp, branchcand) );
2581
2582 if( root && SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL )
2583 SCIPprobUpdateBestRootSol(transprob, set, stat, lp);
2584 }
2585 }
2586 }
2587 }
2588 }
2589
2590 /* call primal heuristics that are applicable during node LP solving loop */
2591 if( !*cutoff && !(*unbounded) && SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL )
2592 {
2593 SCIP_Bool foundsol;
2594
2595 SCIP_CALL( SCIPprimalHeuristics(set, stat, transprob, primal, tree, lp, NULL, SCIP_HEURTIMING_DURINGLPLOOP,
2596 FALSE, &foundsol, unbounded) );
2597 assert(BMSgetNUsedBufferMemory(mem->buffer) == 0);
2598
2599 *lperror = *lperror || lp->resolvelperror;
2600 } /*lint !e438*/
2601 }
2602 assert(lp->flushed || *cutoff || *unbounded);
2603 assert(lp->solved || *lperror || *cutoff || *unbounded);
2604
2605 /* check, if we exceeded the separation round limit */
2606 mustsepa = mustsepa
2607 && stat->nseparounds < maxseparounds
2608 && nsepastallrounds < maxnsepastallrounds
2609 && !(*cutoff);
2610
2611 /* if separators were delayed, we want to apply a final separation round with the delayed separators */
2612 delayedsepa = delayedsepa && !mustsepa && !(*cutoff); /* if regular separation applies, we ignore delayed separators */
2613 mustsepa = mustsepa || delayedsepa;
2614
2615 if( mustsepa )
2616 {
2617 /* if the LP is infeasible, unbounded, exceeded the objective limit or a global performance limit was reached,
2618 * we don't need to separate cuts
2619 * (the global limits are only checked at the root node in order to not query system time too often)
2620 */
2621 if( !separate || (*cutoff) || (*unbounded)
2623 || SCIPsetIsGE(set, SCIPnodeGetLowerbound(focusnode), primal->cutoffbound)
2624 || (root && SCIPsolveIsStopped(set, stat, FALSE)) )
2625 {
2626 mustsepa = FALSE;
2627 delayedsepa = FALSE;
2628 }
2629 else
2630 assert(!(*lperror));
2631 }
2632
2633 /* separation (needs not to be done completely, because we just want to increase the lower bound) */
2634 if( mustsepa )
2635 {
2636 SCIP_Longint olddomchgcount;
2637 SCIP_Longint oldninitconssadded;
2638 SCIP_Bool enoughcuts;
2639
2640 assert(lp->flushed);
2641 assert(lp->solved);
2643 assert(!(*lperror));
2644 assert(!(*cutoff));
2645
2646 olddomchgcount = stat->domchgcount;
2647 oldninitconssadded = stat->ninitconssadded;
2648
2649 mustsepa = FALSE;
2651
2652 /* global cut pool separation */
2653 if( !enoughcuts && !delayedsepa )
2654 {
2655 SCIP_CALL( cutpoolSeparate(cutpool, blkmem, set, stat, eventqueue, eventfilter, lp, sepastore, FALSE, root,
2656 actdepth, &enoughcuts, cutoff) );
2657
2658 if( *cutoff )
2659 {
2660 SCIPsetDebugMsg(set, " -> global cut pool detected cutoff\n");
2661 }
2662 }
2663 assert(lp->flushed);
2664 assert(lp->solved);
2666 assert(!(*lperror));
2667
2668 /* separate constraints and LP */
2669 if( !(*cutoff) && !enoughcuts )
2670 {
2671 /* constraint and LP separation */
2672 SCIPsetDebugMsg(set, "constraint and LP separation\n");
2673
2674 /* apply a separation round */
2675 SCIP_CALL( separationRoundLP(blkmem, set, messagehdlr, stat, eventqueue, eventfilter, transprob, primal, tree,
2676 lp, sepastore, actdepth, bounddist, allowlocal, delayedsepa,
2677 &delayedsepa, &enoughcuts, cutoff, lperror, &mustsepa, &mustprice) );
2678 assert(BMSgetNUsedBufferMemory(mem->buffer) == 0);
2679
2680 /* if we are close to the stall round limit, also call the delayed separators */
2681 if( !(*cutoff) && !(*lperror) && !enoughcuts && lp->solved
2683 && nsepastallrounds >= maxnsepastallrounds-1 && delayedsepa )
2684 {
2685 SCIP_CALL( separationRoundLP(blkmem, set, messagehdlr, stat, eventqueue, eventfilter, transprob, primal,
2686 tree, lp, sepastore, actdepth, bounddist, allowlocal, delayedsepa,
2687 &delayedsepa, &enoughcuts, cutoff, lperror, &mustsepa, &mustprice) );
2688 assert(BMSgetNUsedBufferMemory(mem->buffer) == 0);
2689 }
2690 }
2691
2692 /* call global cut pool separation again since separators may add cuts to the pool instead of the sepastore */
2693 if( !(*cutoff) && !(*lperror) && lp->solved && SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL && !enoughcuts )
2694 {
2695 SCIP_CALL( cutpoolSeparate(cutpool, blkmem, set, stat, eventqueue, eventfilter, lp, sepastore, FALSE, root,
2696 actdepth, &enoughcuts, cutoff) );
2697
2698 if( *cutoff )
2699 {
2700 SCIPsetDebugMsg(set, " -> global cut pool detected cutoff\n");
2701 }
2702 }
2703
2704 /* delayed global cut pool separation */
2705 if( !(*cutoff) && !(*lperror) && lp->solved && SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL && SCIPsepastoreGetNCuts(sepastore) == 0 && !enoughcuts )
2706 {
2707 SCIP_CALL( cutpoolSeparate(delayedcutpool, blkmem, set, stat, eventqueue, eventfilter, lp, sepastore, TRUE,
2708 root, actdepth, &enoughcuts, cutoff) );
2709
2710 if( *cutoff )
2711 {
2712 SCIPsetDebugMsg(set, " -> delayed global cut pool detected cutoff\n");
2713 }
2714 assert(lp->solved);
2716 assert(lp->flushed);
2717 }
2718
2719 /* delayed separation if no cuts where produced */
2720 if( !(*cutoff) && !(*lperror) && SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL && SCIPsepastoreGetNCuts(sepastore) == 0 && delayedsepa )
2721 {
2722 SCIP_CALL( separationRoundLP(blkmem, set, messagehdlr, stat, eventqueue, eventfilter, transprob, primal,
2723 tree, lp, sepastore, actdepth, bounddist, allowlocal, delayedsepa,
2724 &delayedsepa, &enoughcuts, cutoff, lperror, &mustsepa, &mustprice) );
2725 assert(BMSgetNUsedBufferMemory(mem->buffer) == 0);
2726
2727 /* call delayed cut pool separation again, since separators may add cuts to the pool instead of the sepastore */
2728 if( !(*cutoff) && SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL )
2729 {
2730 assert( !(*lperror) );
2731
2732 SCIP_CALL( cutpoolSeparate(delayedcutpool, blkmem, set, stat, eventqueue, eventfilter, lp, sepastore, TRUE,
2733 root, actdepth, &enoughcuts, cutoff) );
2734
2735 if( *cutoff )
2736 {
2737 SCIPsetDebugMsg(set, " -> delayed global cut pool detected cutoff\n");
2738 }
2740 assert(lp->flushed);
2741 assert(lp->solved);
2742 }
2743 }
2744
2745 assert(*cutoff || *lperror || SCIPlpIsSolved(lp));
2746 assert(!SCIPlpIsSolved(lp)
2753
2754 if( *cutoff || *lperror
2757 {
2758 /* the found cuts are of no use, because the node is infeasible anyway (or we have an error in the LP) */
2759 SCIP_CALL( SCIPsepastoreClearCuts(sepastore, blkmem, set, eventqueue, eventfilter, lp) );
2760 }
2761 else
2762 {
2763 /* apply found cuts */
2764 SCIP_CALL( SCIPsepastoreApplyCuts(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
2765 branchcand, eventqueue, eventfilter, cliquetable, root, SCIP_EFFICIACYCHOICE_LP, cutoff) );
2766
2767 if( !(*cutoff) )
2768 {
2769 mustprice = mustprice || !lp->flushed || (transprob->ncolvars != npricedcolvars);
2770 mustsepa = mustsepa || !lp->flushed;
2771
2772 /* if a new bound change (e.g. a cut with only one column) was found, propagate domains again */
2773 if( stat->domchgcount != olddomchgcount )
2774 {
2775 SCIPsetDebugMsg(set, " -> separation changed bound: propagate again\n");
2776
2777 *propagateagain = TRUE;
2778
2779 /* in the root node, remove redundant rows permanently from the LP */
2780 if( root )
2781 {
2782 SCIP_CALL( SCIPlpFlush(lp, blkmem, set, transprob, eventqueue) );
2783 SCIP_CALL( SCIPlpRemoveRedundantRows(lp, blkmem, set, stat, eventqueue, eventfilter) );
2784 }
2785 }
2786
2787 if( stat->ninitconssadded != oldninitconssadded )
2788 {
2789 SCIPsetDebugMsg(set, "new initial constraints added during propagation: old=%" SCIP_LONGINT_FORMAT ", new=%" SCIP_LONGINT_FORMAT "\n",
2790 oldninitconssadded, stat->ninitconssadded);
2791
2792 SCIP_CALL( SCIPinitConssLP(blkmem, set, sepastore, cutpool, stat, transprob, origprob, tree, reopt, lp,
2793 branchcand, eventqueue, eventfilter, cliquetable, FALSE, FALSE, cutoff) );
2794 }
2795
2796 if( !(*cutoff) )
2797 {
2798 SCIP_Real lpobjval;
2799
2800 /* solve LP (with dual simplex) */
2801 SCIPsetDebugMsg(set, "separation: solve LP\n");
2802 SCIP_CALL( SCIPlpSolveAndEval(lp, set, messagehdlr, blkmem, stat, eventqueue, eventfilter, transprob,
2803 set->lp_iterlim, FALSE, TRUE, FALSE, lperror) );
2804 assert(lp->flushed);
2805 assert(lp->solved || *lperror);
2806
2807 /* remove previous primal ray, store new one if LP is unbounded */
2808 SCIP_CALL( updatePrimalRay(blkmem, set, stat, transprob, primal, tree, lp, *lperror) );
2809
2810 if( !(*lperror) )
2811 {
2812 SCIP_Bool stalling;
2813
2814 /* propagation might have changed the best bound of loose variables, thereby changing the loose objective value
2815 * which is added to the LP value; because of the loose status, the LP might not be reoptimized, but the lower
2816 * bound of the node needs to be updated
2817 */
2818 if( stat->domchgcount != olddomchgcount && (!mustprice || mustsepa) && !(*cutoff)
2819 && SCIPprobAllColsInLP(transprob, set, lp) && SCIPlpIsRelax(lp) )
2820 {
2821 SCIP_CALL( SCIPnodeUpdateLowerboundLP(focusnode, set, stat, tree, transprob, origprob, lp) );
2822 SCIPsetDebugMsg(set, " -> new lower bound: %g (LP status: %d, LP obj: %g)\n",
2823 SCIPnodeGetLowerbound(focusnode), SCIPlpGetSolstat(lp), SCIPlpGetObjval(lp, set, transprob));
2824
2825 /* update node estimate */
2826 SCIP_CALL( updateEstimate(set, stat, tree, lp, branchcand) );
2827
2828 if( root && SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL )
2829 SCIPprobUpdateBestRootSol(transprob, set, stat, lp);
2830 }
2831
2832 /* check if we are stalling
2833 * If we have an LP solution, then we are stalling if
2834 * we had an LP solution before and
2835 * the LP value did not improve and
2836 * the number of fractional variables did not decrease.
2837 * If we do not have an LP solution, then we are stalling if the solution status of the LP did not change.
2838 */
2840 {
2841 SCIP_Real objreldiff;
2842 int nfracs;
2843
2844 SCIP_CALL( SCIPbranchcandGetLPCands(branchcand, set, stat, lp, NULL, NULL, NULL, &nfracs, NULL,
2845 NULL) );
2846 lpobjval = SCIPlpGetObjval(lp, set, transprob);
2847
2848 objreldiff = SCIPrelDiff(lpobjval, stalllpobjval);
2849 SCIPsetDebugMsg(set, " -> LP bound moved from %g to %g (reldiff: %g)\n",
2850 stalllpobjval, lpobjval, objreldiff);
2851
2852 stalling = (stalllpsolstat == SCIP_LPSOLSTAT_OPTIMAL &&
2853 objreldiff <= 1e-04 &&
2854 nfracs >= (0.9 - 0.1 * nsepastallrounds) * stallnfracs);
2855
2856 stalllpobjval = lpobjval;
2857 stallnfracs = nfracs;
2858 } /*lint !e438*/
2859 else
2860 {
2861 stalling = (stalllpsolstat == SCIPlpGetSolstat(lp));
2862 }
2863
2864 if( !stalling )
2865 {
2866 nsepastallrounds = 0;
2867 lp->installing = FALSE;
2868 }
2869 else
2870 {
2871 nsepastallrounds++;
2872 }
2873 stalllpsolstat = SCIPlpGetSolstat(lp);
2874
2875 /* tell LP that we are (close to) stalling */
2876 if( nsepastallrounds >= maxnsepastallrounds-2 )
2877 lp->installing = TRUE;
2878 SCIPsetDebugMsg(set, " -> nsepastallrounds=%d/%d\n", nsepastallrounds, maxnsepastallrounds);
2879 }
2880 }
2881 }
2882 }
2883 assert(*cutoff || *lperror || (lp->flushed && lp->solved)); /* cutoff: LP may be unsolved due to bound changes */
2884
2885 SCIPsetDebugMsg(set, "separation round %d/%d finished (%d/%d stall rounds): mustprice=%u, mustsepa=%u, delayedsepa=%u, propagateagain=%u\n",
2886 stat->nseparounds, maxseparounds, nsepastallrounds, maxnsepastallrounds, mustprice, mustsepa, delayedsepa, *propagateagain);
2887
2888 /* increase separation round counter */
2889 stat->nseparounds++;
2890 }
2891 }
2892
2893 if( root && nsepastallrounds >= maxnsepastallrounds )
2894 {
2895 SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
2896 "Truncate separation round because of stalling (%d stall rounds).\n", maxnsepastallrounds);
2897 }
2898
2899 if( !*lperror )
2900 {
2901 /* update pseudo cost values for continuous variables, if it should be delayed */
2902 SCIP_CALL( updatePseudocost(set, stat, transprob, tree, lp, FALSE, set->branch_delaypscost) );
2903 }
2904
2905 /* update lower bound w.r.t. the LP solution */
2906 if( *cutoff )
2907 {
2908 SCIPnodeUpdateLowerbound(focusnode, stat, set, tree, transprob, origprob, SCIPsetInfinity(set));
2909 }
2910 else if( !(*lperror) )
2911 {
2912 assert(lp->flushed);
2913 assert(lp->solved);
2914
2915 if( SCIPlpIsRelax(lp) )
2916 {
2917 SCIP_CALL( SCIPnodeUpdateLowerboundLP(focusnode, set, stat, tree, transprob, origprob, lp) );
2918 }
2919
2920 /* update node estimate */
2921 SCIP_CALL( updateEstimate(set, stat, tree, lp, branchcand) );
2922
2923 /* issue LPSOLVED event */
2925 {
2927 SCIP_CALL( SCIPeventChgNode(&event, focusnode) );
2928 SCIP_CALL( SCIPeventProcess(&event, set, NULL, NULL, NULL, eventfilter) );
2929 }
2930
2931 /* if the LP is a relaxation and we are not solving exactly, then we may analyze an infeasible or bound exceeding
2932 * LP (not necessary in the root node) and cut off the current node
2933 */
2934 if( !set->misc_exactsolve && !root && SCIPlpIsRelax(lp) && SCIPprobAllColsInLP(transprob, set, lp)
2936 {
2937 SCIP_CALL( SCIPconflictAnalyzeLP(conflict, conflictstore, blkmem, set, stat, transprob, origprob, tree, reopt,
2938 lp, branchcand, eventqueue, cliquetable, NULL) );
2939 *cutoff = TRUE;
2940 }
2941 }
2942 /* check for unboundedness */
2943 if( !(*lperror) )
2944 {
2945 *unbounded = (SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_UNBOUNDEDRAY);
2946 /* assert(!(*unbounded) || root); */ /* unboundedness can only happen in the root node; no, of course it can also happens in the tree if a branching did not help to resolve unboundedness */
2947 }
2948
2949 lp->installing = FALSE;
2950
2951 SCIPsetDebugMsg(set, " -> final lower bound: %g (LP status: %d, LP obj: %g)\n",
2953 (*cutoff || *unbounded) ? SCIPsetInfinity(set) : *lperror ? -SCIPsetInfinity(set) : SCIPlpGetObjval(lp, set, transprob));
2954
2955 return SCIP_OKAY; /*lint !e438*/
2956}
2957
2958/** updates the current lower bound with the pseudo objective value, cuts off node by bounding, and applies conflict
2959 * analysis if the pseudo objective lead to the cutoff
2960 */
2961static
2963 BMS_BLKMEM* blkmem, /**< block memory buffers */
2964 SCIP_SET* set, /**< global SCIP settings */
2965 SCIP_STAT* stat, /**< dynamic problem statistics */
2966 SCIP_PROB* transprob, /**< tranformed problem after presolve */
2967 SCIP_PROB* origprob, /**< original problem */
2968 SCIP_PRIMAL* primal, /**< primal data */
2969 SCIP_TREE* tree, /**< branch and bound tree */
2970 SCIP_REOPT* reopt, /**< reoptimization data structure */
2971 SCIP_LP* lp, /**< LP data */
2972 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
2973 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2974 SCIP_CONFLICT* conflict, /**< conflict analysis data */
2975 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
2976 SCIP_Bool* cutoff /**< pointer to store TRUE, if the node can be cut off */
2977 )
2978{
2979 assert(transprob != NULL);
2980 assert(origprob != NULL);
2981 assert(primal != NULL);
2982 assert(cutoff != NULL);
2983
2984 if( !(*cutoff) )
2985 {
2986 SCIP_NODE* focusnode;
2987 SCIP_Real pseudoobjval;
2988
2989 /* get current focus node */
2990 focusnode = SCIPtreeGetFocusNode(tree);
2991
2992 /* update lower bound w.r.t. the pseudo solution */
2993 pseudoobjval = SCIPlpGetPseudoObjval(lp, set, transprob);
2994 SCIPnodeUpdateLowerbound(focusnode, stat, set, tree, transprob, origprob, pseudoobjval);
2995 SCIPsetDebugMsg(set, " -> lower bound: %g [%g] (pseudoobj: %g [%g]), cutoff bound: %g [%g]\n",
2996 SCIPnodeGetLowerbound(focusnode), SCIPprobExternObjval(transprob, origprob, set, SCIPnodeGetLowerbound(focusnode)) + SCIPgetOrigObjoffset(set->scip),
2997 pseudoobjval, SCIPprobExternObjval(transprob, origprob, set, pseudoobjval) + SCIPgetOrigObjoffset(set->scip),
2998 primal->cutoffbound, SCIPprobExternObjval(transprob, origprob, set, primal->cutoffbound) + SCIPgetOrigObjoffset(set->scip));
2999
3000 /* check for infeasible node by bounding */
3001 if( (set->misc_exactsolve && SCIPnodeGetLowerbound(focusnode) >= primal->cutoffbound)
3002 || (!set->misc_exactsolve && SCIPsetIsGE(set, SCIPnodeGetLowerbound(focusnode), primal->cutoffbound)) )
3003 {
3004 SCIPsetDebugMsg(set, "node is cut off by bounding (lower=%g, upper=%g)\n",
3005 SCIPnodeGetLowerbound(focusnode), primal->cutoffbound);
3006 SCIPnodeUpdateLowerbound(focusnode, stat, set, tree, transprob, origprob, SCIPsetInfinity(set));
3007 *cutoff = TRUE;
3008
3009 /* call pseudo conflict analysis, if the node is cut off due to the pseudo objective value */
3010 if( pseudoobjval >= primal->cutoffbound && !SCIPsetIsInfinity(set, primal->cutoffbound) && !SCIPsetIsInfinity(set, -pseudoobjval) )
3011 {
3012 SCIP_CALL( SCIPconflictAnalyzePseudo(conflict, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue, cliquetable, NULL) );
3013 }
3014 }
3015 }
3016
3017 return SCIP_OKAY;
3018}
3019
3020/** marks all relaxators to be unsolved */
3021static
3023 SCIP_SET* set, /**< global SCIP settings */
3024 SCIP_RELAXATION* relaxation /**< global relaxation data */
3025 )
3026{
3027 int r;
3028
3029 assert(set != NULL);
3030 assert(relaxation != NULL);
3031
3033
3034 for( r = 0; r < set->nrelaxs; ++r )
3035 SCIPrelaxMarkUnsolved(set->relaxs[r]);
3036}
3037
3038/** solves the current node's LP in a price-and-cut loop */
3039static
3041 BMS_BLKMEM* blkmem, /**< block memory buffers */
3042 SCIP_SET* set, /**< global SCIP settings */
3043 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
3044 SCIP_STAT* stat, /**< dynamic problem statistics */
3045 SCIP_MEM* mem, /**< block memory pools */
3046 SCIP_PROB* origprob, /**< original problem */
3047 SCIP_PROB* transprob, /**< transformed problem after presolve */
3048 SCIP_PRIMAL* primal, /**< primal data */
3049 SCIP_TREE* tree, /**< branch and bound tree */
3050 SCIP_REOPT* reopt, /**< reoptimization data structure */
3051 SCIP_LP* lp, /**< LP data */
3052 SCIP_RELAXATION* relaxation, /**< relaxators */
3053 SCIP_PRICESTORE* pricestore, /**< pricing storage */
3054 SCIP_SEPASTORE* sepastore, /**< separation storage */
3055 SCIP_CUTPOOL* cutpool, /**< global cut pool */
3056 SCIP_CUTPOOL* delayedcutpool, /**< global delayed cut pool */
3057 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
3058 SCIP_CONFLICT* conflict, /**< conflict analysis data */
3059 SCIP_CONFLICTSTORE* conflictstore, /**< conflict store */
3060 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
3061 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3062 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
3063 SCIP_Bool initiallpsolved, /**< was the initial LP already solved? */
3064 SCIP_Bool fullseparation, /**< are we in the first prop-and-cut-and-price loop? */
3065 SCIP_Bool newinitconss, /**< do we have to add new initial constraints? */
3066 SCIP_Bool* propagateagain, /**< pointer to store whether we want to propagate again */
3067 SCIP_Bool* solverelaxagain, /**< pointer to store TRUE, if the external relaxators should be called again */
3068 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
3069 SCIP_Bool* unbounded, /**< pointer to store TRUE, if an unbounded ray was found in the LP */
3070 SCIP_Bool* lperror, /**< pointer to store TRUE, if an unresolved error in LP solving occured */
3071 SCIP_Bool* pricingaborted /**< pointer to store TRUE, if the pricing was aborted and the lower bound
3072 * must not be used */
3073 )
3074{
3075 SCIP_Longint nlpiterations;
3076 SCIP_Longint nlps;
3077 SCIP_Longint nzeroitlps;
3078
3079 assert(stat != NULL);
3080 assert(tree != NULL);
3081 assert(SCIPtreeHasFocusNodeLP(tree));
3082 assert(cutoff != NULL);
3083 assert(unbounded != NULL);
3084 assert(lperror != NULL);
3085 assert(*cutoff == FALSE);
3086 assert(*unbounded == FALSE);
3087 assert(*lperror == FALSE);
3088
3089 nlps = stat->nlps;
3090 nzeroitlps = stat->ndualzeroitlps + stat->nprimalzeroitlps + stat->nbarrierzeroitlps;
3091 nlpiterations = stat->nlpiterations;
3092
3093 if( !initiallpsolved )
3094 {
3095 /* load and solve the initial LP of the node */
3096 SCIP_CALL( solveNodeInitialLP(blkmem, set, messagehdlr, stat, transprob, origprob, primal, tree, reopt, lp,
3097 pricestore, sepastore, cutpool, branchcand, eventfilter, eventqueue, cliquetable, newinitconss, cutoff, lperror) );
3098
3099 assert(*cutoff || *lperror || (lp->flushed && lp->solved));
3100 SCIPsetDebugMsg(set, "price-and-cut-loop: initial LP status: %d, LP obj: %g\n",
3101 SCIPlpGetSolstat(lp),
3102 *cutoff ? SCIPsetInfinity(set) : *lperror ? -SCIPsetInfinity(set) : SCIPlpGetObjval(lp, set, transprob));
3103
3104 /* update initial LP iteration counter */
3105 stat->ninitlps += stat->nlps - nlps;
3106 stat->ninitlpiterations += stat->nlpiterations - nlpiterations;
3107
3108 /* In the root node, we try if the initial LP solution is feasible to avoid expensive setup of data structures in
3109 * separators; in case the root LP is aborted, e.g., by hitting the time limit, we do not check the LP solution
3110 * since the corresponding data structures have not been updated.
3111 */
3112 if( SCIPtreeGetCurrentDepth(tree) == 0 && !(*cutoff) && !(*lperror)
3114 && !SCIPsolveIsStopped(set, stat, FALSE) )
3115 {
3116 SCIP_Bool checklprows;
3117 SCIP_Bool stored;
3118 SCIP_SOL* sol;
3119 SCIP_Longint oldnbestsolsfound = primal->nbestsolsfound;
3120
3121 SCIP_CALL( SCIPsolCreateLPSol(&sol, blkmem, set, stat, transprob, primal, tree, lp, NULL) );
3122
3124 checklprows = FALSE;
3125 else
3126 checklprows = TRUE;
3127
3128#ifndef NDEBUG
3129 /* in the debug mode we want to explicitly check if the solution is feasible if it was stored */
3130 SCIP_CALL( SCIPprimalTrySol(primal, blkmem, set, messagehdlr, stat, origprob, transprob, tree, reopt, lp,
3131 eventqueue, eventfilter, sol, FALSE, FALSE, TRUE, TRUE, checklprows, &stored) );
3132
3133 if( stored )
3134 {
3135 SCIP_Bool feasible;
3136
3137 SCIP_CALL( SCIPsolCheck(sol, set, messagehdlr, blkmem, stat, transprob, FALSE, FALSE, TRUE, TRUE,
3138 checklprows, &feasible) );
3139 assert(feasible);
3140 }
3141
3142 SCIP_CALL( SCIPsolFree(&sol, blkmem, primal) );
3143#else
3144 SCIP_CALL( SCIPprimalTrySolFree(primal, blkmem, set, messagehdlr, stat, origprob, transprob, tree, reopt, lp,
3145 eventqueue, eventfilter, &sol, FALSE, FALSE, TRUE, TRUE, checklprows, &stored) );
3146#endif
3147 if( stored )
3148 {
3149 stat->nlpsolsfound++;
3150
3151 if( primal->nbestsolsfound != oldnbestsolsfound )
3152 {
3153 stat->nlpbestsolsfound++;
3155 }
3156
3157 if( set->reopt_enable )
3158 {
3159 assert(reopt != NULL);
3161 SCIPlpGetSolstat(lp), tree->root == tree->focusnode, TRUE, tree->focusnode->lowerbound,
3162 tree->effectiverootdepth) );
3163 }
3164 }
3165
3167 *unbounded = TRUE;
3168 }
3169 }
3170 else
3171 {
3172 SCIP_CALL( SCIPinitConssLP(blkmem, set, sepastore, cutpool, stat, transprob,
3173 origprob, tree, reopt, lp, branchcand, eventqueue, eventfilter, cliquetable, FALSE, FALSE,
3174 cutoff) );
3175 }
3176 assert(SCIPsepastoreGetNCuts(sepastore) == 0);
3177
3178 /* check for infeasible node by bounding */
3179 SCIP_CALL( applyBounding(blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, eventqueue, conflict, cliquetable, cutoff) );
3180#ifdef SCIP_DEBUG
3181 if( *cutoff )
3182 {
3183 if( SCIPtreeGetCurrentDepth(tree) == 0 )
3184 {
3185 SCIPsetDebugMsg(set, "solution cuts off root node, stop solution process\n");
3186 }
3187 else
3188 {
3189 SCIPsetDebugMsg(set, "solution cuts off node\n");
3190 }
3191 }
3192#endif
3193
3194 if( !(*cutoff) && !(*lperror) )
3195 {
3196 SCIP_Longint oldninitconssadded;
3197 SCIP_Longint oldnboundchgs;
3198 SCIP_Longint olddomchgcount;
3199 int oldnpricedvars;
3200 int oldncutsapplied;
3201
3202 oldnpricedvars = transprob->ncolvars;
3203 oldninitconssadded = stat->ninitconssadded;
3204 oldncutsapplied = SCIPsepastoreGetNCutsApplied(sepastore);
3205 oldnboundchgs = stat->nboundchgs;
3206 olddomchgcount = stat->domchgcount;
3207
3208 /* solve the LP with price-and-cut*/
3209 SCIP_CALL( priceAndCutLoop(blkmem, set, messagehdlr, stat, mem, transprob, origprob, primal, tree, reopt, lp,
3210 pricestore, sepastore, cutpool, delayedcutpool, branchcand, conflict, conflictstore, eventfilter,
3211 eventqueue, cliquetable, fullseparation, propagateagain, cutoff, unbounded, lperror, pricingaborted) );
3212
3213 /* check if the problem was changed and the relaxation needs to be resolved */
3214 if( (transprob->ncolvars != oldnpricedvars) || (stat->ninitconssadded != oldninitconssadded) ||
3215 (SCIPsepastoreGetNCutsApplied(sepastore) != oldncutsapplied) || (stat->nboundchgs != oldnboundchgs) ||
3216 (stat->domchgcount != olddomchgcount) )
3217 {
3218 *solverelaxagain = TRUE;
3219 markRelaxsUnsolved(set, relaxation);
3220 }
3221 }
3222 assert(*cutoff || *lperror || (lp->flushed && lp->solved));
3223
3224 /* if there is no LP error, then *unbounded should be TRUE, iff the LP solution status is unboundedray */
3225 assert(*lperror || ((SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_UNBOUNDEDRAY) == *unbounded));
3226
3227 /* If pricing was aborted while solving the LP of the node and the node cannot be cut off due to the lower bound computed by the pricer,
3228 * the solving of the LP might be stopped due to the objective limit, but the node may not be cut off, since the LP objective
3229 * is not a feasible lower bound for the solutions in the current subtree.
3230 * In this case, the LP has to be solved to optimality by temporarily removing the cutoff bound.
3231 */
3232 if( (*pricingaborted) && (SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OBJLIMIT || SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_ITERLIMIT)
3233 && !(*cutoff) )
3234 {
3235 SCIP_Real tmpcutoff;
3236
3237 /* temporarily disable cutoffbound, which also disables the objective limit */
3238 tmpcutoff = lp->cutoffbound;
3240
3241 lp->solved = FALSE;
3242 SCIP_CALL( SCIPlpSolveAndEval(lp, set, messagehdlr, blkmem, stat, eventqueue, eventfilter, transprob, -1LL, FALSE, FALSE, FALSE, lperror) );
3243
3244 /* reinstall old cutoff bound */
3245 lp->cutoffbound = tmpcutoff;
3246
3247 SCIPsetDebugMsg(set, "re-optimized LP without cutoff bound: LP status: %d, LP obj: %g\n",
3248 SCIPlpGetSolstat(lp), *lperror ? -SCIPsetInfinity(set) : SCIPlpGetObjval(lp, set, transprob));
3249
3250 /* lp solstat should not be objlimit, since the cutoff bound was removed temporarily */
3252 /* lp solstat should not be unboundedray, since the lp was dual feasible */
3254 /* there should be no primal ray, since the lp was dual feasible */
3255 assert(primal->primalray == NULL);
3257 {
3258 *cutoff = TRUE;
3259 }
3260 }
3261
3262 assert(!(*pricingaborted) || SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL /* cppcheck-suppress assertWithSideEffect */
3263 || SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_NOTSOLVED || SCIPsolveIsStopped(set, stat, FALSE) || (*cutoff));
3264
3265 assert(*cutoff || *lperror || (lp->flushed && lp->solved));
3266
3267 /* update node's LP iteration counter */
3268 stat->nnodelps += stat->nlps - nlps;
3269 stat->nnodezeroitlps += stat->ndualzeroitlps + stat->nprimalzeroitlps + stat->nbarrierzeroitlps - nzeroitlps;
3270 stat->nnodelpiterations += stat->nlpiterations - nlpiterations;
3271
3272 /* update number of root node LPs and iterations if the root node was processed */
3273 if( SCIPnodeGetDepth(tree->focusnode) == 0 )
3274 {
3275 stat->nrootlps += stat->nlps - nlps;
3276 stat->nrootlpiterations += stat->nlpiterations - nlpiterations;
3277 }
3278
3279 return SCIP_OKAY;
3280}
3281
3282/** calls relaxators */
3283static
3285 SCIP_SET* set, /**< global SCIP settings */
3286 SCIP_STAT* stat, /**< dynamic problem statistics */
3287 SCIP_TREE* tree, /**< branch and bound tree */
3288 SCIP_RELAXATION* relaxation, /**< relaxators */
3289 SCIP_PROB* transprob, /**< transformed problem */
3290 SCIP_PROB* origprob, /**< original problem */
3291 int depth, /**< depth of current node */
3292 SCIP_Bool beforelp, /**< should the relaxators with non-negative or negative priority be called? */
3293 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
3294 SCIP_Bool* propagateagain, /**< pointer to store TRUE, if domain propagation should be applied again */
3295 SCIP_Bool* solvelpagain, /**< pointer to store TRUE, if the node's LP has to be solved again */
3296 SCIP_Bool* solverelaxagain, /**< pointer to store TRUE, if the external relaxators should be called
3297 * again */
3298 SCIP_Bool* relaxcalled /**< pointer to store TRUE, if at least one relaxator was called (unmodified
3299 * otherwise) */
3300 )
3301{
3302 SCIP_RESULT result;
3303 SCIP_Real lowerbound;
3304 int r;
3305
3306 assert(set != NULL);
3307 assert(relaxation != NULL);
3308 assert(cutoff != NULL);
3309 assert(solvelpagain != NULL);
3310 assert(propagateagain != NULL);
3311 assert(solverelaxagain != NULL);
3312 assert(relaxcalled != NULL);
3313 assert(!(*cutoff));
3314
3315 /* sort by priority */
3317
3318 for( r = 0; r < set->nrelaxs && !(*cutoff); ++r )
3319 {
3320 if( beforelp != (SCIPrelaxGetPriority(set->relaxs[r]) >= 0) )
3321 continue;
3322
3323 *relaxcalled = TRUE;
3324
3325 lowerbound = -SCIPsetInfinity(set);
3326
3327 SCIP_CALL( SCIPrelaxExec(set->relaxs[r], set, tree, stat, depth, &lowerbound, &result) );
3328
3329 switch( result )
3330 {
3331 case SCIP_CUTOFF:
3332 *cutoff = TRUE;
3333 SCIPsetDebugMsg(set, " -> relaxator <%s> detected cutoff\n", SCIPrelaxGetName(set->relaxs[r]));
3334 /* @todo does it make sense to proceed if the node is proven to be infeasible? */
3335 return SCIP_OKAY;
3336
3337 case SCIP_CONSADDED:
3338 *solvelpagain = TRUE; /* the separation for new constraints should be called */
3339 *propagateagain = TRUE; /* the propagation for new constraints should be called */
3340 break;
3341
3342 case SCIP_REDUCEDDOM:
3343 *solvelpagain = TRUE;
3344 *propagateagain = TRUE;
3345 break;
3346
3347 case SCIP_SEPARATED:
3348 *solvelpagain = TRUE;
3349 break;
3350
3351 case SCIP_SUSPENDED:
3352 *solverelaxagain = TRUE;
3353 break;
3354
3355 case SCIP_SUCCESS:
3356 case SCIP_DIDNOTRUN:
3357 break;
3358
3359 default:
3360 SCIPerrorMessage("invalid result code <%d> of relaxator <%s>\n", result, SCIPrelaxGetName(set->relaxs[r]));
3361 return SCIP_INVALIDRESULT;
3362 } /*lint !e788*/
3363
3364 if( result != SCIP_CUTOFF && result != SCIP_DIDNOTRUN && result != SCIP_SUSPENDED )
3365 {
3366 SCIP_NODE* focusnode;
3367
3368 focusnode = SCIPtreeGetFocusNode(tree);
3369 assert(focusnode != NULL);
3370 assert(SCIPnodeGetType(focusnode) == SCIP_NODETYPE_FOCUSNODE);
3371
3372 /* update lower bound w.r.t. the lower bound given by the relaxator */
3373 SCIPnodeUpdateLowerbound(focusnode, stat, set, tree, transprob, origprob, lowerbound);
3374 SCIPsetDebugMsg(set, " -> new lower bound given by relaxator %s: %g\n",
3375 SCIPrelaxGetName(set->relaxs[r]), lowerbound);
3376 }
3377 }
3378
3379 return SCIP_OKAY;
3380}
3381
3382/** enforces constraints by branching, separation, or domain reduction */
3383static
3385 BMS_BLKMEM* blkmem, /**< block memory buffers */
3386 SCIP_SET* set, /**< global SCIP settings */
3387 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
3388 SCIP_STAT* stat, /**< dynamic problem statistics */
3389 SCIP_PROB* prob, /**< transformed problem after presolve */
3390 SCIP_PRIMAL* primal, /**< primal data */
3391 SCIP_TREE* tree, /**< branch and bound tree */
3392 SCIP_LP* lp, /**< LP data */
3393 SCIP_RELAXATION* relaxation, /**< global relaxation data */
3394 SCIP_SEPASTORE* sepastore, /**< separation storage */
3395 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
3396 SCIP_Bool* branched, /**< pointer to store whether a branching was created */
3397 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
3398 SCIP_Bool* infeasible, /**< pointer to store TRUE, if the LP/pseudo solution is infeasible */
3399 SCIP_Bool* propagateagain, /**< pointer to store TRUE, if domain propagation should be applied again */
3400 SCIP_Bool* solvelpagain, /**< pointer to store TRUE, if the node's LP has to be solved again */
3401 SCIP_Bool* solverelaxagain, /**< pointer to store TRUE, if the external relaxators should be called again */
3402 SCIP_Bool forced /**< should enforcement of pseudo solution be forced? */
3403 )
3404{
3405 SCIP_RESULT result;
3406 SCIP_SOL* relaxsol = NULL;
3407 SCIP_Real pseudoobjval;
3408 SCIP_Bool resolved;
3409 SCIP_Bool objinfeasible;
3410 SCIP_Bool enforcerelaxsol;
3411 int h;
3412
3413 assert(set != NULL);
3414 assert(stat != NULL);
3415 assert(tree != NULL);
3416 assert(SCIPtreeGetFocusNode(tree) != NULL);
3417 assert(branched != NULL);
3418 assert(cutoff != NULL);
3419 assert(infeasible != NULL);
3420 assert(propagateagain != NULL);
3421 assert(solvelpagain != NULL);
3422 assert(solverelaxagain != NULL);
3423 assert(!(*cutoff));
3424 assert(!(*propagateagain));
3425 assert(!(*solvelpagain));
3426 assert(!(*solverelaxagain));
3427
3428 *branched = FALSE;
3429 /**@todo avoid checking the same pseudosolution twice */
3430
3431 /* enforce (best) relaxation solution if the LP has a worse objective value */
3432 enforcerelaxsol = SCIPrelaxationIsSolValid(relaxation) && SCIPrelaxationIsLpIncludedForSol(relaxation) && (!SCIPtreeHasFocusNodeLP(tree)
3433 || SCIPsetIsGT(set, SCIPrelaxationGetSolObj(relaxation), SCIPlpGetObjval(lp, set, prob)));
3434
3435 /* check if all constraint handlers implement the enforelax callback, otherwise enforce the LP solution */
3436 for( h = 0; h < set->nconshdlrs && enforcerelaxsol; ++h )
3437 {
3438 if( set->conshdlrs_enfo[h]->consenforelax == NULL && ((! set->conshdlrs_enfo[h]->needscons) ||
3439 (set->conshdlrs_enfo[h]->nconss > 0)) )
3440 {
3441 SCIP_VERBLEVEL verblevel;
3442
3443 enforcerelaxsol = FALSE;
3444
3445 verblevel = SCIP_VERBLEVEL_FULL;
3446
3447 if( !stat->disableenforelaxmsg && set->disp_verblevel == SCIP_VERBLEVEL_HIGH )
3448 {
3449 verblevel = SCIP_VERBLEVEL_HIGH;
3450
3451 /* remember that the disable relaxation enforcement message was posted and only post it again if the
3452 * verblevel is SCIP_VERBLEVEL_FULL
3453 */
3454 stat->disableenforelaxmsg = TRUE;
3455 }
3456 SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, verblevel, "Disable enforcement of relaxation solutions"
3457 " since constraint handler %s does not implement enforelax-callback\n",
3458 SCIPconshdlrGetName(set->conshdlrs_enfo[h]));
3459 }
3460 }
3461
3462 /* enforce constraints by branching, applying additional cutting planes (if LP is being processed),
3463 * introducing new constraints, or tighten the domains
3464 */
3465#ifndef SCIP_NDEBUG
3466 if( enforcerelaxsol )
3467 {
3468 SCIPsetDebugMsg(set, "enforcing constraints on relaxation solution\n");
3469 }
3470 else
3471 {
3472 SCIPsetDebugMsg(set, "enforcing constraints on %s solution\n", SCIPtreeHasFocusNodeLP(tree) ? "LP" : "pseudo");
3473 }
3474#endif
3475
3476 /* check, if the solution is infeasible anyway due to it's objective value */
3477 if( SCIPtreeHasFocusNodeLP(tree) || enforcerelaxsol )
3478 objinfeasible = FALSE;
3479 else
3480 {
3481 pseudoobjval = SCIPlpGetPseudoObjval(lp, set, prob);
3482 objinfeasible = SCIPsetIsFeasLT(set, pseudoobjval, SCIPnodeGetLowerbound(SCIPtreeGetFocusNode(tree)));
3483 }
3484
3485 /* during constraint enforcement, generated cuts should enter the LP in any case; otherwise, a constraint handler
3486 * would fail to enforce its constraints if it relies on the modification of the LP relaxation
3487 */
3488 SCIPsepastoreStartForceCuts(sepastore);
3489
3490 /* enforce constraints until a handler resolved an infeasibility with cutting off the node, branching,
3491 * reducing a domain, or separating a cut
3492 * if a constraint handler introduced new constraints to enforce his constraints, the newly added constraints
3493 * have to be enforced themselves
3494 */
3495 resolved = FALSE;
3496
3497 /* in case the relaxation solution should be enforced, we need to create the corresponding solution for the enforelax callbacks */
3498 if( enforcerelaxsol )
3499 {
3500 SCIP_CALL( SCIPsolCreateRelaxSol(&relaxsol, blkmem, set, stat, primal, tree, relaxation, NULL) );
3501 }
3502
3503 for( h = 0; h < set->nconshdlrs && !resolved; ++h )
3504 {
3505 assert(SCIPsepastoreGetNCuts(sepastore) == 0); /* otherwise, the LP should have been resolved first */
3506
3507 /* enforce LP, pseudo, or relaxation solution */
3508 if( enforcerelaxsol )
3509 {
3510 SCIPsetDebugMsg(set, "enforce relaxation solution with value %g\n", SCIPrelaxationGetSolObj(relaxation));
3511
3512 SCIP_CALL( SCIPconshdlrEnforceRelaxSol(set->conshdlrs_enfo[h], blkmem, set, stat, tree, sepastore,
3513 relaxsol, *infeasible, &result) );
3514 }
3515 else if( SCIPtreeHasFocusNodeLP(tree) )
3516 {
3517 SCIPsetDebugMsg(set, "enforce LP solution with value %g\n", SCIPlpGetObjval(lp, set, prob));
3518
3519 assert(lp->flushed);
3520 assert(lp->solved);
3522 SCIP_CALL( SCIPconshdlrEnforceLPSol(set->conshdlrs_enfo[h], blkmem, set, stat, tree, sepastore, *infeasible,
3523 &result) );
3524 }
3525 else
3526 {
3527 SCIP_CALL( SCIPconshdlrEnforcePseudoSol(set->conshdlrs_enfo[h], blkmem, set, stat, tree, branchcand, *infeasible,
3528 objinfeasible, forced, &result) );
3529 if( SCIPsepastoreGetNCuts(sepastore) != 0 )
3530 {
3531 SCIPerrorMessage("pseudo enforcing method of constraint handler <%s> separated cuts\n",
3532 SCIPconshdlrGetName(set->conshdlrs_enfo[h]));
3533 return SCIP_INVALIDRESULT;
3534 }
3535 }
3536 SCIPsetDebugMsg(set, "enforcing of <%s> returned result %d\n", SCIPconshdlrGetName(set->conshdlrs_enfo[h]), result);
3537
3538 switch( result )
3539 {
3540 case SCIP_CUTOFF:
3541 assert(tree->nchildren == 0);
3542 *cutoff = TRUE;
3543 *infeasible = TRUE;
3544 resolved = TRUE;
3545 SCIPsetDebugMsg(set, " -> constraint handler <%s> detected cutoff in enforcement\n",
3546 SCIPconshdlrGetName(set->conshdlrs_enfo[h]));
3547 break;
3548
3549 case SCIP_CONSADDED:
3550 assert(tree->nchildren == 0);
3551 *infeasible = TRUE;
3552 *propagateagain = TRUE; /* the propagation for new constraints should be called */
3553 *solvelpagain = TRUE; /* the separation for new constraints should be called */
3554 *solverelaxagain = TRUE;
3555 markRelaxsUnsolved(set, relaxation);
3556 resolved = TRUE;
3557 break;
3558
3559 case SCIP_REDUCEDDOM:
3560 assert(tree->nchildren == 0);
3561 *infeasible = TRUE;
3562 *propagateagain = TRUE;
3563 *solvelpagain = TRUE;
3564 *solverelaxagain = TRUE;
3565 markRelaxsUnsolved(set, relaxation);
3566 resolved = TRUE;
3567 break;
3568
3569 case SCIP_SEPARATED:
3570 assert(tree->nchildren == 0);
3571 assert(SCIPsepastoreGetNCuts(sepastore) > 0);
3572 *infeasible = TRUE;
3573 *solvelpagain = TRUE;
3574 *solverelaxagain = TRUE;
3575 markRelaxsUnsolved(set, relaxation);
3576 resolved = TRUE;
3577 break;
3578
3579 case SCIP_BRANCHED:
3580 assert(tree->nchildren >= 1);
3581 assert(!SCIPtreeHasFocusNodeLP(tree) || (lp->flushed && lp->solved));
3582 assert(SCIPsepastoreGetNCuts(sepastore) == 0);
3583 *infeasible = TRUE;
3584 *branched = TRUE;
3585 resolved = TRUE;
3586
3587 /* increase the number of internal nodes */
3588 stat->ninternalnodes++;
3589 stat->ntotalinternalnodes++;
3590 break;
3591
3592 case SCIP_SOLVELP:
3593 /* either LP was not solved, or it is not solved anymore (e.g., because feastol has been tightened by some constraint handler) */
3594 assert(!SCIPtreeHasFocusNodeLP(tree) || !lp->solved);
3595 assert(tree->nchildren == 0);
3596 assert(SCIPsepastoreGetNCuts(sepastore) == 0);
3597 *infeasible = TRUE;
3598 *solvelpagain = TRUE;
3599 resolved = TRUE;
3600 SCIPtreeSetFocusNodeLP(tree, TRUE); /* the node's LP must be solved */
3601 break;
3602
3603 case SCIP_INFEASIBLE:
3604 assert(tree->nchildren == 0);
3605 assert(!SCIPtreeHasFocusNodeLP(tree) || (lp->flushed && lp->solved));
3606 assert(SCIPsepastoreGetNCuts(sepastore) == 0);
3607 *infeasible = TRUE;
3608 break;
3609
3610 case SCIP_FEASIBLE:
3611 assert(tree->nchildren == 0);
3612 assert(!SCIPtreeHasFocusNodeLP(tree) || (lp->flushed && lp->solved));
3613 assert(SCIPsepastoreGetNCuts(sepastore) == 0);
3614 break;
3615
3616 case SCIP_DIDNOTRUN:
3617 assert(tree->nchildren == 0);
3618 assert(!SCIPtreeHasFocusNodeLP(tree) || (lp->flushed && lp->solved));
3619 assert(SCIPsepastoreGetNCuts(sepastore) == 0);
3620 assert(objinfeasible);
3621 *infeasible = TRUE;
3622 break;
3623
3624 default:
3625 SCIPerrorMessage("invalid result code <%d> from enforcing method of constraint handler <%s>\n",
3626 result, SCIPconshdlrGetName(set->conshdlrs_enfo[h]));
3627 return SCIP_INVALIDRESULT;
3628 } /*lint !e788*/
3629
3630 /* the enforcement method may add a primal solution, after which the LP status could be set to
3631 * objective limit reached
3632 */
3634 {
3635 *cutoff = TRUE;
3636 *infeasible = TRUE;
3637 resolved = TRUE;
3638 SCIPsetDebugMsg(set, " -> LP exceeded objective limit\n");
3639
3640 /* If we used the probing mode during branching, it might happen that we added a constraint or global bound
3641 * and returned SCIP_CONSADDED or SCIP_REDUCEDDOM, but when reoptimizing the LP after ending the probing mode,
3642 * this leads to hitting the objective limit. In this case, we do not need to propagate or solve the LP again.
3643 */
3644 *propagateagain = FALSE;
3645 *solvelpagain = FALSE;
3646 }
3647
3648 assert(!(*branched) || (resolved && !(*cutoff) && *infeasible && !(*propagateagain) && !(*solvelpagain)));
3649 assert(!(*cutoff) || (resolved && !(*branched) && *infeasible && !(*propagateagain) && !(*solvelpagain)));
3650 assert(*infeasible || (!resolved && !(*branched) && !(*cutoff) && !(*propagateagain) && !(*solvelpagain)));
3651 assert(!(*propagateagain) || (resolved && !(*branched) && !(*cutoff) && *infeasible));
3652 assert(!(*solvelpagain) || (resolved && !(*branched) && !(*cutoff) && *infeasible));
3653 }
3654 assert(!objinfeasible || *infeasible);
3655 assert(resolved == (*branched || *cutoff || *propagateagain || *solvelpagain));
3656 assert(*cutoff || *solvelpagain || SCIPsepastoreGetNCuts(sepastore) == 0);
3657
3658 /* in case the relaxation solution was enforced, free the created solution */
3659 if( enforcerelaxsol )
3660 {
3661 SCIP_CALL( SCIPsolFree(&relaxsol, blkmem, primal) );
3662 }
3663
3664 /* deactivate the cut forcing of the constraint enforcement */
3665 SCIPsepastoreEndForceCuts(sepastore);
3666
3667 SCIPsetDebugMsg(set, " -> enforcing result: branched=%u, cutoff=%u, infeasible=%u, propagateagain=%u, solvelpagain=%u, resolved=%u\n",
3668 *branched, *cutoff, *infeasible, *propagateagain, *solvelpagain, resolved);
3669
3670 return SCIP_OKAY;
3671}
3672
3673/** applies the cuts stored in the separation store, or clears the store if the node can be cut off */
3674static
3676 BMS_BLKMEM* blkmem, /**< block memory buffers */
3677 SCIP_SET* set, /**< global SCIP settings */
3678 SCIP_STAT* stat, /**< dynamic problem statistics */
3679 SCIP_PROB* transprob, /**< transformed problem */
3680 SCIP_PROB* origprob, /**< original problem */
3681 SCIP_TREE* tree, /**< branch and bound tree */
3682 SCIP_REOPT* reopt, /**< reotimization data structure */
3683 SCIP_LP* lp, /**< LP data */
3684 SCIP_RELAXATION* relaxation, /**< relaxators */
3685 SCIP_SEPASTORE* sepastore, /**< separation storage */
3686 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
3687 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3688 SCIP_EVENTFILTER* eventfilter, /**< global event filter */
3689 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
3690 SCIP_Bool root, /**< is this the initial root LP? */
3691 SCIP_EFFICIACYCHOICE efficiacychoice, /**< type of solution to base efficiacy computation on */
3692 SCIP_Bool* cutoff, /**< pointer to whether the node can be cut off */
3693 SCIP_Bool* propagateagain, /**< pointer to store TRUE, if domain propagation should be applied again */
3694 SCIP_Bool* solvelpagain, /**< pointer to store TRUE, if the node's LP has to be solved again */
3695 SCIP_Bool* solverelaxagain /**< pointer to store TRUE, if the node's relaxation has to be solved again */
3696 )
3697{
3698 assert(stat != NULL);
3699 assert(cutoff != NULL);
3700 assert(propagateagain != NULL);
3701 assert(solvelpagain != NULL);
3702
3703 if( *cutoff )
3704 {
3705 /* the found cuts are of no use, because the node is infeasible anyway (or we have an error in the LP) */
3706 SCIP_CALL( SCIPsepastoreClearCuts(sepastore, blkmem, set, eventqueue, eventfilter, lp) );
3707 }
3708 else if( SCIPsepastoreGetNCuts(sepastore) > 0 )
3709 {
3710 SCIP_Longint olddomchgcount;
3711 int oldncutsapplied;
3712
3713 olddomchgcount = stat->domchgcount;
3714 oldncutsapplied = SCIPsepastoreGetNCutsApplied(sepastore);
3715 SCIP_CALL( SCIPsepastoreApplyCuts(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
3716 eventqueue, eventfilter, cliquetable, root, efficiacychoice, cutoff) );
3717 *propagateagain = *propagateagain || (stat->domchgcount != olddomchgcount);
3718 *solvelpagain = TRUE;
3719 if( (stat->domchgcount != olddomchgcount) || (SCIPsepastoreGetNCutsApplied(sepastore) != oldncutsapplied) )
3720 {
3721 *solverelaxagain = TRUE;
3722 markRelaxsUnsolved(set, relaxation);
3723 }
3724 }
3725
3726 return SCIP_OKAY;
3727}
3728
3729/** updates the cutoff, propagateagain, and solverelaxagain status of the current solving loop */
3730static
3732 SCIP_SET* set, /**< global SCIP settings */
3733 SCIP_STAT* stat, /**< dynamic problem statistics */
3734 SCIP_TREE* tree, /**< branch and bound tree */
3735 int depth, /**< depth of current node */
3736 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
3737 SCIP_Bool* propagateagain, /**< pointer to store TRUE, if domain propagation should be applied again */
3738 SCIP_Bool* solverelaxagain /**< pointer to store TRUE, if at least one relaxator should be called again */
3739 )
3740{
3741 SCIP_NODE* focusnode;
3742 int r;
3743
3744 assert(set != NULL);
3745 assert(stat != NULL);
3746 assert(cutoff != NULL);
3747 assert(propagateagain != NULL);
3748 assert(solverelaxagain != NULL);
3749
3750 /* check, if the path was cutoff */
3751 *cutoff = *cutoff || (tree->cutoffdepth <= depth);
3752
3753 /* check if branching was already performed */
3754 if( tree->nchildren == 0 )
3755 {
3756 /* check, if the focus node should be repropagated */
3757 focusnode = SCIPtreeGetFocusNode(tree);
3758 *propagateagain = *propagateagain || SCIPnodeIsPropagatedAgain(focusnode);
3759
3760 /* check, if one of the external relaxations should be solved again */
3761 for( r = 0; r < set->nrelaxs && !(*solverelaxagain); ++r )
3762 *solverelaxagain = *solverelaxagain || ( !SCIPrelaxIsSolved(set->relaxs[r], stat) );
3763 }
3764 else
3765 {
3766 /* if branching was performed, avoid another node loop iteration */
3767 *propagateagain = FALSE;
3768 *solverelaxagain = FALSE;
3769 }
3770}
3771
3772/** propagate domains and solve relaxation and lp */
3773static
3775 BMS_BLKMEM* blkmem, /**< block memory buffers */
3776 SCIP_SET* set, /**< global SCIP settings */
3777 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
3778 SCIP_STAT* stat, /**< dynamic problem statistics */
3779 SCIP_MEM* mem, /**< block memory pools */
3780 SCIP_PROB* origprob, /**< original problem */
3781 SCIP_PROB* transprob, /**< transformed problem after presolve */
3782 SCIP_PRIMAL* primal, /**< primal data */
3783 SCIP_TREE* tree, /**< branch and bound tree */
3784 SCIP_REOPT* reopt, /**< reoptimization data structure */
3785 SCIP_LP* lp, /**< LP data */
3786 SCIP_RELAXATION* relaxation, /**< global relaxation data */
3787 SCIP_PRICESTORE* pricestore, /**< pricing storage */
3788 SCIP_SEPASTORE* sepastore, /**< separation storage */
3789 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
3790 SCIP_CUTPOOL* cutpool, /**< global cut pool */
3791 SCIP_CUTPOOL* delayedcutpool, /**< global delayed cut pool */
3792 SCIP_CONFLICT* conflict, /**< conflict analysis data */
3793 SCIP_CONFLICTSTORE* conflictstore, /**< conflict store */
3794 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
3795 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
3796 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
3797 SCIP_NODE* focusnode, /**< focused node */
3798 int actdepth, /**< depth in the b&b tree */
3799 SCIP_Bool propagate, /**< should we propagate */
3800 SCIP_Bool solvelp, /**< should we solve the lp */
3801 SCIP_Bool solverelax, /**< should we solve the relaxation */
3802 SCIP_Bool forcedlpsolve, /**< is there a need for a solve lp */
3803 SCIP_Bool initiallpsolved, /**< was the initial LP already solved? */
3804 SCIP_Bool fullseparation, /**< are we in the first prop-and-cut-and-price loop? */
3805 SCIP_Longint* afterlpproplps, /**< pointer to store the last LP count for which AFTERLP propagation was performed */
3806 SCIP_HEURTIMING* heurtiming, /**< timing for running heuristics after propagation call */
3807 int* nlperrors, /**< pointer to store the number of lp errors */
3808 SCIP_Bool* fullpropagation, /**< pointer to store whether we want to do a fullpropagation next time */
3809 SCIP_Bool* propagateagain, /**< pointer to store whether we want to propagate again */
3810 SCIP_Bool* lpsolved, /**< pointer to store whether the lp was solved */
3811 SCIP_Bool* relaxcalled, /**< pointer to store whether a relaxator was called; initialized with last loop's result */
3812 SCIP_Bool* solvelpagain, /**< pointer to store whether we want to solve the lp again */
3813 SCIP_Bool* solverelaxagain, /**< pointer to store whether we want to solve the relaxation again */
3814 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
3815 SCIP_Bool* postpone, /**< pointer to store whether the node should be postponed */
3816 SCIP_Bool* unbounded, /**< pointer to store whether the focus node is unbounded */
3817 SCIP_Bool* stopped, /**< pointer to store whether solving was interrupted */
3818 SCIP_Bool* lperror, /**< pointer to store TRUE, if an unresolved error in LP solving occured */
3819 SCIP_Bool* pricingaborted, /**< pointer to store TRUE, if the pricing was aborted and the lower bound must not be used */
3820 SCIP_Bool* forcedenforcement /**< pointer to store whether the enforcement of pseudo solution should be forced */
3821 )
3822{
3823 SCIP_Bool newinitconss;
3824
3825 assert(set != NULL);
3826 assert(stat != NULL);
3827 assert(origprob != NULL);
3828 assert(transprob != NULL);
3829 assert(tree != NULL);
3830 assert(lp != NULL);
3831 assert(primal != NULL);
3832 assert(pricestore != NULL);
3833 assert(sepastore != NULL);
3834 assert(SCIPsepastoreGetNCuts(sepastore) == 0);
3835 assert(branchcand != NULL);
3836 assert(cutpool != NULL);
3837 assert(delayedcutpool != NULL);
3838 assert(conflict != NULL);
3839 assert(SCIPconflictGetNConflicts(conflict) == 0);
3840 assert(eventfilter != NULL);
3841 assert(eventqueue != NULL);
3842 assert(focusnode != NULL);
3843 assert(heurtiming != NULL);
3844 assert(nlperrors != NULL);
3845 assert(fullpropagation != NULL);
3846 assert(propagateagain != NULL);
3847 assert(afterlpproplps != NULL);
3848 assert(lpsolved != NULL);
3849 assert(solvelpagain != NULL);
3850 assert(solverelaxagain != NULL);
3851 assert(cutoff != NULL);
3852 assert(postpone != NULL);
3853 assert(unbounded != NULL);
3854 assert(lperror != NULL);
3855 assert(pricingaborted != NULL);
3856 assert(forcedenforcement != NULL);
3857
3858 newinitconss = FALSE;
3859
3860 if( !(*cutoff) && !(*postpone) )
3861 {
3862 SCIP_Longint oldninitconssadded;
3863 SCIP_Longint oldnboundchgs;
3864 SCIP_Bool lpwasflushed;
3865
3866 lpwasflushed = lp->flushed;
3867 oldnboundchgs = stat->nboundchgs;
3868 oldninitconssadded = stat->ninitconssadded;
3869
3870 /* call after LP propagators */
3871 if( ((*afterlpproplps) < stat->nnodelps && (*lpsolved)) || (*relaxcalled) )
3872 {
3873 SCIP_CALL( propagateDomains(blkmem, set, stat, tree, SCIPtreeGetCurrentDepth(tree), 0, *fullpropagation,
3874 SCIP_PROPTIMING_AFTERLPLOOP, cutoff, postpone) );
3875 assert(BMSgetNUsedBufferMemory(mem->buffer) == 0);
3876
3877 /* check, if the path was cutoff */
3878 *cutoff = *cutoff || (tree->cutoffdepth <= actdepth);
3879 *afterlpproplps = stat->nnodelps;
3880 propagate = propagate || (stat->nboundchgs > oldnboundchgs);
3881 }
3882
3883 /* call before LP propagators */
3884 if( propagate && !(*cutoff) )
3885 {
3886 SCIP_CALL( propagateDomains(blkmem, set, stat, tree, SCIPtreeGetCurrentDepth(tree), 0, *fullpropagation,
3887 SCIP_PROPTIMING_BEFORELP, cutoff, postpone) );
3888 assert(BMSgetNUsedBufferMemory(mem->buffer) == 0);
3889 }
3890
3891 newinitconss = (stat->ninitconssadded != oldninitconssadded);
3892 *fullpropagation = FALSE;
3893
3894 /* check, if the path was cutoff */
3895 *cutoff = *cutoff || (tree->cutoffdepth <= actdepth);
3896
3897 /* if the LP was flushed and is now no longer flushed, a bound change occurred, and the LP has to be resolved;
3898 * we also have to solve the LP if new intial constraints were added which need to be added to the LP
3899 */
3900 solvelp = solvelp || (lpwasflushed && (!lp->flushed || newinitconss));
3901 solverelax = solverelax || newinitconss;
3902
3903 /* the number of bound changes was increased by the propagation call, thus the relaxation should be solved again */
3904 if( stat->nboundchgs > oldnboundchgs )
3905 {
3906 /* propagation might have changed the best bound of loose variables, thereby changing the loose objective value
3907 * which is added to the LP value; because of the loose status, the LP might not be reoptimized, but the lower
3908 * bound of the node needs to be updated
3909 */
3910 if( !solvelp && lp->flushed && lp->solved && SCIPprobAllColsInLP(transprob, set, lp) && SCIPlpIsRelax(lp) )
3911 {
3912 SCIP_CALL( SCIPnodeUpdateLowerboundLP(focusnode, set, stat, tree, transprob, origprob, lp) );
3913 SCIPsetDebugMsg(set, " -> new lower bound: %g (LP status: %d, LP obj: %g)\n",
3914 SCIPnodeGetLowerbound(focusnode), SCIPlpGetSolstat(lp), SCIPlpGetObjval(lp, set, transprob));
3915
3916 if( SCIPtreeHasFocusNodeLP(tree) )
3917 {
3918 /* update node estimate */
3919 SCIP_CALL( updateEstimate(set, stat, tree, lp, branchcand) );
3920
3921 if( actdepth == 0 && SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_OPTIMAL )
3922 SCIPprobUpdateBestRootSol(transprob, set, stat, lp);
3923 }
3924 }
3925
3926 solverelax = TRUE;
3927 markRelaxsUnsolved(set, relaxation);
3928 }
3929
3930 /* update lower bound with the pseudo objective value, and cut off node by bounding */
3931 SCIP_CALL( applyBounding(blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, eventqueue,
3932 conflict, cliquetable, cutoff) );
3933 }
3934 assert(SCIPsepastoreGetNCuts(sepastore) == 0);
3935
3936 if( *postpone )
3937 return SCIP_OKAY;
3938
3939 /* call primal heuristics that are applicable after propagation loop before lp solve;
3940 * the first time we go here, we call the before node heuristics instead
3941 */
3942 if( !(*cutoff) && !SCIPtreeProbing(tree) )
3943 {
3944 /* if the heuristics find a new incumbent solution, propagate again */
3945 SCIP_CALL( SCIPprimalHeuristics(set, stat, transprob, primal, tree, lp, NULL, *heurtiming,
3946 FALSE, propagateagain, unbounded) );
3947 assert(BMSgetNUsedBufferMemory(mem->buffer) == 0);
3948
3949 *heurtiming = SCIP_HEURTIMING_AFTERPROPLOOP;
3950
3951 /* check if primal heuristics found a solution and we therefore reached a solution limit */
3952 if( SCIPsolveIsStopped(set, stat, FALSE) )
3953 {
3954 /* cppcheck-suppress unassignedVariable */
3955 SCIP_NODE* node;
3956
3957 /* we reached a solution limit and do not want to continue the processing of the current node, but in order to
3958 * allow restarting the optimization process later, we need to create a "branching" with only one child node that
3959 * is a copy of the focusnode
3960 */
3962 SCIP_CALL( SCIPnodeCreateChild(&node, blkmem, set, stat, tree, 1.0, focusnode->estimate) );
3963 assert(tree->nchildren >= 1);
3964 *stopped = TRUE;
3965 return SCIP_OKAY;
3966 }
3967
3968 /* if diving produced an LP error, switch back to non-LP node */
3969 if( lp->resolvelperror )
3970 {
3972 lp->resolvelperror = FALSE;
3973 }
3974
3975 if( *propagateagain )
3976 {
3977 *solvelpagain = solvelp;
3978 *solverelaxagain = solverelax;
3979
3980 return SCIP_OKAY;
3981 }
3982 }
3983
3984 /* solve external relaxations with non-negative priority */
3985 *relaxcalled = FALSE;
3986 if( solverelax && !(*cutoff) )
3987 {
3988 /* clear the storage of external branching candidates */
3990
3991 SCIP_CALL( solveNodeRelax(set, stat, tree, relaxation, transprob, origprob, actdepth, TRUE,
3992 cutoff, propagateagain, solvelpagain, solverelaxagain, relaxcalled) );
3993 assert(BMSgetNUsedBufferMemory(mem->buffer) == 0);
3994
3995 /* check, if the path was cutoff */
3996 *cutoff = *cutoff || (tree->cutoffdepth <= actdepth);
3997
3998 /* apply found cuts */
3999 SCIP_CALL( applyCuts(blkmem, set, stat, transprob, origprob, tree, reopt, lp, relaxation, sepastore, branchcand,
4000 eventqueue, eventfilter, cliquetable, (actdepth == 0), SCIP_EFFICIACYCHOICE_RELAX, cutoff, propagateagain,
4001 solvelpagain, solverelaxagain) );
4002
4003 /* update lower bound with the pseudo objective value, and cut off node by bounding */
4004 SCIP_CALL( applyBounding(blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, eventqueue, conflict, cliquetable, cutoff) );
4005 }
4006 assert(SCIPsepastoreGetNCuts(sepastore) == 0);
4007
4008 /* check, if we want to solve the LP at this node */
4009 if( solvelp && !(*cutoff) && SCIPtreeHasFocusNodeLP(tree) )
4010 {
4011 *lperror = FALSE;
4012 *unbounded = FALSE;
4013
4014 /* solve the node's LP */
4015 SCIP_CALL( solveNodeLP(blkmem, set, messagehdlr, stat, mem, origprob, transprob, primal, tree, reopt, lp, relaxation, pricestore,
4016 sepastore, cutpool, delayedcutpool, branchcand, conflict, conflictstore, eventfilter, eventqueue, cliquetable,
4017 initiallpsolved, fullseparation, newinitconss, propagateagain, solverelaxagain, cutoff, unbounded, lperror, pricingaborted) );
4018
4019 *lpsolved = TRUE;
4020 *solvelpagain = FALSE;
4021 SCIPsetDebugMsg(set, " -> LP status: %d, LP obj: %g, iter: %" SCIP_LONGINT_FORMAT ", count: %" SCIP_LONGINT_FORMAT "\n",
4022 SCIPlpGetSolstat(lp),
4023 *cutoff ? SCIPsetInfinity(set) : (*lperror ? -SCIPsetInfinity(set) : SCIPlpGetObjval(lp, set, transprob)),
4024 stat->nlpiterations, stat->lpcount);
4025
4026 /* check, if the path was cutoff */
4027 *cutoff = *cutoff || (tree->cutoffdepth <= actdepth);
4028
4029 /* if an error occured during LP solving, switch to pseudo solution */
4030 if( *lperror )
4031 {
4032 if( forcedlpsolve )
4033 {
4034 SCIPerrorMessage("(node %" SCIP_LONGINT_FORMAT ") unresolved numerical troubles in LP %" SCIP_LONGINT_FORMAT " cannot be dealt with\n",
4035 stat->nnodes, stat->nlps);
4036 return SCIP_LPERROR;
4037 }
4039 ++(*nlperrors);
4040 SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, actdepth == 0 ? SCIP_VERBLEVEL_HIGH : SCIP_VERBLEVEL_FULL,
4041 "(node %" SCIP_LONGINT_FORMAT ") unresolved numerical troubles in LP %" SCIP_LONGINT_FORMAT " -- using pseudo solution instead (loop %d)\n",
4042 stat->nnodes, stat->nlps, *nlperrors);
4043 }
4044
4046 {
4048 *forcedenforcement = TRUE;
4049
4050 SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, actdepth == 0 ? SCIP_VERBLEVEL_HIGH : SCIP_VERBLEVEL_FULL,
4051 "(node %" SCIP_LONGINT_FORMAT ") LP solver hit %s limit in LP %" SCIP_LONGINT_FORMAT " -- using pseudo solution instead\n",
4052 stat->nnodes, SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_TIMELIMIT ? "time" : "iteration", stat->nlps);
4053 }
4054
4056 {
4057 SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
4058 "(node %" SCIP_LONGINT_FORMAT ") LP relaxation is unbounded (LP %" SCIP_LONGINT_FORMAT ")\n", stat->nnodes, stat->nlps);
4059 }
4060
4061 /* if we solve exactly, the LP claims to be infeasible but the infeasibility could not be proved,
4062 * we have to forget about the LP and use the pseudo solution instead
4063 */
4064 if( !(*cutoff) && !(*lperror) && (set->misc_exactsolve || *pricingaborted) && SCIPlpGetSolstat(lp) == SCIP_LPSOLSTAT_INFEASIBLE
4065 && SCIPnodeGetLowerbound(focusnode) < primal->cutoffbound )
4066 {
4067 if( SCIPbranchcandGetNPseudoCands(branchcand) == 0 && transprob->ncontvars > 0 )
4068 {
4069 SCIPerrorMessage("(node %" SCIP_LONGINT_FORMAT ") could not prove infeasibility of LP %" SCIP_LONGINT_FORMAT " (exactsolve=%u, pricingaborted=%u), all variables are fixed, %d continuous vars\n",
4070 stat->nnodes, stat->nlps, set->misc_exactsolve, *pricingaborted, transprob->ncontvars);
4071 SCIPerrorMessage("(node %" SCIP_LONGINT_FORMAT ") -> have to call PerPlex() (feature not yet implemented)\n", stat->nnodes);
4072 /**@todo call PerPlex */
4073 return SCIP_LPERROR;
4074 }
4075 else
4076 {
4078 *forcedenforcement = TRUE;
4079
4080 SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
4081 "(node %" SCIP_LONGINT_FORMAT ") could not prove infeasibility of LP %" SCIP_LONGINT_FORMAT " (exactsolve=%u, pricingaborted=%u) -- using pseudo solution (%d unfixed vars) instead\n",
4082 stat->nnodes, stat->nlps, set->misc_exactsolve, *pricingaborted, SCIPbranchcandGetNPseudoCands(branchcand));
4083 }
4084 }
4085
4086 /* update lower bound with the pseudo objective value, and cut off node by bounding */
4087 SCIP_CALL( applyBounding(blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, eventqueue, conflict,
4088 cliquetable, cutoff) );
4089 }
4090 assert(SCIPsepastoreGetNCuts(sepastore) == 0);
4091 assert(*cutoff || !SCIPtreeHasFocusNodeLP(tree) || (lp->flushed && lp->solved));
4092
4093 /* reset solverelaxagain if no relaxations were solved up to this point (the LP-changes are already included in
4094 * relaxators called after the LP)
4095 */
4096 *solverelaxagain = *solverelaxagain && *relaxcalled;
4097
4098 /* solve external relaxations with negative priority */
4099 if( solverelax && !(*cutoff) )
4100 {
4101 SCIP_CALL( solveNodeRelax(set, stat, tree, relaxation, transprob, origprob, actdepth, FALSE, cutoff,
4102 propagateagain, solvelpagain, solverelaxagain, relaxcalled) );
4103 assert(BMSgetNUsedBufferMemory(mem->buffer) == 0);
4104
4105 /* check, if the path was cutoff */
4106 *cutoff = *cutoff || (tree->cutoffdepth <= actdepth);
4107
4108 /* apply found cuts */
4109 SCIP_CALL( applyCuts(blkmem, set, stat, transprob, origprob, tree, reopt, lp, relaxation, sepastore, branchcand,
4110 eventqueue, eventfilter, cliquetable, (actdepth == 0), SCIP_EFFICIACYCHOICE_RELAX, cutoff, propagateagain,
4111 solvelpagain, solverelaxagain) );
4112
4113 /* update lower bound with the pseudo objective value, and cut off node by bounding */
4114 SCIP_CALL( applyBounding(blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, eventqueue, conflict,
4115 cliquetable, cutoff) );
4116 }
4117 assert(SCIPsepastoreGetNCuts(sepastore) == 0);
4118
4119 return SCIP_OKAY;
4120}
4121
4122/** check if a restart can be performed */
4123#ifndef NDEBUG
4124static
4126 SCIP_SET* set, /**< global SCIP settings */
4127 SCIP_STAT* stat /**< dynamic problem statistics */
4128 )
4129{
4130 assert(set != NULL);
4131 assert(stat != NULL);
4132
4133 return set->nactivepricers == 0 && !set->reopt_enable
4134 && ( set->presol_maxrestarts == -1 || stat->nruns <= set->presol_maxrestarts );
4135}
4136#else
4137#define restartAllowed(set,stat) ((set)->nactivepricers == 0 && !set->reopt_enable && ((set)->presol_maxrestarts == -1 || (stat)->nruns <= (set)->presol_maxrestarts))
4138#endif
4139
4140/** solves the focus node */
4141static
4143 BMS_BLKMEM* blkmem, /**< block memory buffers */
4144 SCIP_SET* set, /**< global SCIP settings */
4145 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
4146 SCIP_STAT* stat, /**< dynamic problem statistics */
4147 SCIP_MEM* mem, /**< block memory pools */
4148 SCIP_PROB* origprob, /**< original problem */
4149 SCIP_PROB* transprob, /**< transformed problem after presolve */
4150 SCIP_PRIMAL* primal, /**< primal data */
4151 SCIP_TREE* tree, /**< branch and bound tree */
4152 SCIP_REOPT* reopt, /**< reoptimization data structure */
4153 SCIP_LP* lp, /**< LP data */
4154 SCIP_RELAXATION* relaxation, /**< global relaxation data */
4155 SCIP_PRICESTORE* pricestore, /**< pricing storage */
4156 SCIP_SEPASTORE* sepastore, /**< separation storage */
4157 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
4158 SCIP_CUTPOOL* cutpool, /**< global cut pool */
4159 SCIP_CUTPOOL* delayedcutpool, /**< global delayed cut pool */
4160 SCIP_CONFLICT* conflict, /**< conflict analysis data */
4161 SCIP_CONFLICTSTORE* conflictstore, /**< conflict store */
4162 SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
4163 SCIP_EVENTQUEUE* eventqueue, /**< event queue */
4164 SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
4165 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
4166 SCIP_Bool* postpone, /**< pointer to store whether the node should be postponed */
4167 SCIP_Bool* unbounded, /**< pointer to store whether the focus node is unbounded */
4168 SCIP_Bool* infeasible, /**< pointer to store whether the focus node's solution is infeasible */
4169 SCIP_Bool* restart, /**< should solving process be started again with presolving? */
4170 SCIP_Bool* afternodeheur, /**< pointer to store whether AFTERNODE heuristics were already called */
4171 SCIP_Bool* stopped /**< pointer to store whether solving was interrupted */
4172 )
4173{
4174 SCIP_NODE* focusnode;
4175 SCIP_Longint lastdomchgcount;
4176 SCIP_Longint afterlpproplps;
4177 SCIP_Real restartfac;
4178 SCIP_Longint lastlpcount;
4179 SCIP_HEURTIMING heurtiming;
4180 int actdepth;
4181 int nlperrors;
4182 int nloops;
4183 SCIP_Bool foundsol;
4184 SCIP_Bool focusnodehaslp;
4185 SCIP_Bool lpsolved;
4186 SCIP_Bool initiallpsolved;
4187 SCIP_Bool fullseparation;
4188 SCIP_Bool solverelaxagain;
4189 SCIP_Bool solvelpagain;
4190 SCIP_Bool propagateagain;
4191 SCIP_Bool fullpropagation;
4192 SCIP_Bool branched;
4193 SCIP_Bool forcedlpsolve;
4194 SCIP_Bool wasforcedlpsolve;
4195 SCIP_Bool pricingaborted;
4196
4197 assert(set != NULL);
4198 assert(stat != NULL);
4199 assert(origprob != NULL);
4200 assert(transprob != NULL);
4201 assert(tree != NULL);
4202 assert(primal != NULL);
4203 assert(SCIPsepastoreGetNCuts(sepastore) == 0);
4204 assert(SCIPconflictGetNConflicts(conflict) == 0);
4205 assert(cutoff != NULL);
4206 assert(postpone != NULL);
4207 assert(unbounded != NULL);
4208 assert(infeasible != NULL);
4209 assert(restart != NULL);
4210 assert(afternodeheur != NULL);
4211
4212 *cutoff = FALSE;
4213 *postpone = FALSE;
4214 *unbounded = FALSE;
4215 *infeasible = FALSE;
4216 *restart = FALSE;
4217 *afternodeheur = FALSE;
4218 *stopped = FALSE;
4219 pricingaborted = FALSE;
4220
4221 focusnode = SCIPtreeGetFocusNode(tree);
4222 assert(focusnode != NULL);
4223 assert(SCIPnodeGetType(focusnode) == SCIP_NODETYPE_FOCUSNODE);
4224 actdepth = SCIPnodeGetDepth(focusnode);
4225
4226 /* invalidate relaxation solution */
4228
4229 /* clear the storage of external branching candidates */
4231
4232 SCIPsetDebugMsg(set, "Processing node %" SCIP_LONGINT_FORMAT " in depth %d, %d siblings\n",
4233 stat->nnodes, actdepth, tree->nsiblings);
4234 SCIPsetDebugMsg(set, "current pseudosolution: obj=%g\n", SCIPlpGetPseudoObjval(lp, set, transprob));
4235 /*debug(SCIPprobPrintPseudoSol(transprob, set));*/
4236
4237 /* check, if we want to solve the LP at the selected node:
4238 * - solve the LP, if the lp solve depth and frequency demand solving
4239 * - solve the root LP, if the LP solve frequency is set to 0
4240 * - solve the root LP, if there are continuous variables present
4241 * - don't solve the node if its cut off by the pseudo objective value anyway
4242 */
4243 focusnodehaslp = (set->lp_solvedepth == -1 || actdepth <= set->lp_solvedepth);
4244 focusnodehaslp = focusnodehaslp && (set->lp_solvefreq >= 1 && actdepth % set->lp_solvefreq == 0);
4245 focusnodehaslp = focusnodehaslp || (actdepth == 0 && set->lp_solvefreq == 0);
4246 focusnodehaslp = focusnodehaslp && SCIPsetIsLT(set, SCIPlpGetPseudoObjval(lp, set, transprob), primal->cutoffbound);
4247 focusnodehaslp = set->reopt_enable ? focusnodehaslp && SCIPreoptGetSolveLP(reopt, set, focusnode) : focusnodehaslp;
4248 SCIPtreeSetFocusNodeLP(tree, focusnodehaslp);
4249
4250 /* external node solving loop:
4251 * - propagate domains
4252 * - solve SCIP_LP
4253 * - enforce constraints
4254 * if a constraint handler adds constraints to enforce its own constraints, both, propagation and LP solving
4255 * is applied again (if applicable on current node); however, if the new constraints don't have the enforce flag set,
4256 * it is possible, that the current infeasible solution is not cut off; in this case, we have to declare the solution
4257 * infeasible and perform a branching
4258 */
4259 lastdomchgcount = stat->domchgcount;
4260 lastlpcount = stat->lpcount;
4261 initiallpsolved = FALSE;
4262 fullseparation = TRUE;
4263 heurtiming = SCIP_HEURTIMING_BEFORENODE;
4264 nlperrors = 0;
4265 stat->npricerounds = 0;
4266 stat->nseparounds = 0;
4267 solverelaxagain = TRUE;
4268 solvelpagain = TRUE;
4269 propagateagain = TRUE;
4270 fullpropagation = TRUE;
4271 forcedlpsolve = FALSE;
4272 nloops = 0;
4273
4274 while( !(*cutoff) && !(*postpone) && (solverelaxagain || solvelpagain || propagateagain) && nlperrors < MAXNLPERRORS && !(*restart) )
4275 {
4276 SCIP_Bool lperror;
4277 SCIP_Bool solverelax;
4278 SCIP_Bool solvelp;
4279 SCIP_Bool propagate;
4280 SCIP_Bool forcedenforcement;
4281 SCIP_Bool relaxcalled;
4282
4283 assert(SCIPsepastoreGetNCuts(sepastore) == 0);
4284
4285 *unbounded = FALSE;
4286 *infeasible = FALSE;
4287 foundsol = FALSE;
4288
4289 nloops++;
4290 lperror = FALSE;
4291 lpsolved = FALSE;
4292 relaxcalled = FALSE;
4293 forcedenforcement = FALSE;
4294 afterlpproplps = -1L;
4295
4296 while( !lperror && !(*cutoff) && (propagateagain || solvelpagain || solverelaxagain
4297 || (afterlpproplps < stat->nnodelps && lpsolved) || relaxcalled) )
4298 {
4299 solverelax = solverelaxagain;
4300 solverelaxagain = FALSE;
4301 solvelp = solvelpagain;
4302 solvelpagain = FALSE;
4303 propagate = propagateagain;
4304 propagateagain = FALSE;
4305
4306 /* update lower bound with the pseudo objective value, and cut off node by bounding */
4307 SCIP_CALL( applyBounding(blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, eventqueue,
4308 conflict, cliquetable, cutoff) );
4309
4310 /* propagate domains before lp solving and solve relaxation and lp */
4311 SCIPsetDebugMsg(set, " -> node solving loop: call propagators that are applicable before%s LP is solved\n",
4312 lpsolved ? " and after" : "");
4313 SCIP_CALL( propAndSolve(blkmem, set, messagehdlr, stat, mem, origprob, transprob, primal, tree, reopt, lp,
4314 relaxation, pricestore, sepastore, branchcand, cutpool, delayedcutpool, conflict, conflictstore, eventfilter,
4315 eventqueue, cliquetable, focusnode, actdepth, propagate, solvelp, solverelax, forcedlpsolve, initiallpsolved,
4316 fullseparation, &afterlpproplps, &heurtiming, &nlperrors, &fullpropagation, &propagateagain, &lpsolved, &relaxcalled,
4317 &solvelpagain, &solverelaxagain, cutoff, postpone, unbounded, stopped, &lperror, &pricingaborted, &forcedenforcement) );
4318 initiallpsolved |= lpsolved;
4319
4320 /* time or solution limit was hit and we already created a dummy child node to terminate fast */
4321 if( *stopped )
4322 {
4323 /* reset LP feastol to normal value, in case someone tightened it during node solving */
4325 return SCIP_OKAY;
4326 }
4327 }
4328 fullseparation = FALSE;
4329
4330 /* update the cutoff, propagateagain, and solverelaxagain status of current solving loop */
4331 updateLoopStatus(set, stat, tree, actdepth, cutoff, &propagateagain, &solverelaxagain);
4332
4333 /* call primal heuristics that should be applied after the LP relaxation of the node was solved;
4334 * if this is the first loop of the root node, call also AFTERNODE heuristics already here, since they might help
4335 * to improve the primal bound, thereby producing additional reduced cost strengthenings and strong branching
4336 * bound fixings which also might lead to a restart
4337 */
4338 if( !(*postpone) && (!(*cutoff) || SCIPtreeGetNNodes(tree) > 0) )
4339 {
4340 if( actdepth == 0 && !(*afternodeheur) )
4341 {
4342 SCIP_CALL( SCIPprimalHeuristics(set, stat, transprob, primal, tree, lp, NULL,
4343 SCIP_HEURTIMING_AFTERLPLOOP | SCIP_HEURTIMING_AFTERNODE, *cutoff, &foundsol, unbounded) );
4344 *afternodeheur = TRUE; /* the AFTERNODE heuristics should not be called again after the node */
4345 }
4346 else if( lpsolved || SCIPrelaxationIsSolValid(relaxation) )
4347 {
4348 SCIP_CALL( SCIPprimalHeuristics(set, stat, transprob, primal, tree, lp, NULL, SCIP_HEURTIMING_AFTERLPLOOP,
4349 *cutoff, &foundsol, unbounded) );
4350 }
4351 assert(BMSgetNUsedBufferMemory(mem->buffer) == 0);
4352
4353 /* heuristics might have found a solution or set the cutoff bound such that the current node is cut off */
4354 SCIP_CALL( applyBounding(blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, eventqueue, conflict, cliquetable, cutoff) );
4355 }
4356
4357 /* check if heuristics leave us with an invalid LP */
4358 if( lp->resolvelperror )
4359 {
4360 if( forcedlpsolve )
4361 {
4362 SCIPerrorMessage("(node %" SCIP_LONGINT_FORMAT ") unresolved numerical troubles in LP %" SCIP_LONGINT_FORMAT " cannot be dealt with\n",
4363 stat->nnodes, stat->nlps);
4364 return SCIP_LPERROR;
4365 }
4367 lp->resolvelperror = FALSE;
4368 nlperrors++;
4369 SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
4370 "(node %" SCIP_LONGINT_FORMAT ") unresolved numerical troubles in LP %" SCIP_LONGINT_FORMAT " -- using pseudo solution instead (loop %d)\n",
4371 stat->nnodes, stat->nlps, nlperrors);
4372 }
4373
4374 if( pricingaborted && !(*cutoff) && SCIPlpGetSolstat(lp) != SCIP_LPSOLSTAT_OPTIMAL )
4375 {
4377
4378 /* if we just ran into the time limit this is not really a numerical trouble;
4379 * however, if this is not the case, we print messages about numerical troubles in the current LP
4380 */
4381 if( !SCIPsolveIsStopped(set, stat, FALSE) )
4382 {
4383 if( forcedlpsolve )
4384 {
4385 SCIPerrorMessage("(node %" SCIP_LONGINT_FORMAT ") unresolved numerical troubles in LP %" SCIP_LONGINT_FORMAT " cannot be dealt with\n",
4386 stat->nnodes, stat->nlps);
4387 return SCIP_LPERROR;
4388 }
4389 nlperrors++;
4390 SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL,
4391 "(node %" SCIP_LONGINT_FORMAT ") unresolved numerical troubles in LP %" SCIP_LONGINT_FORMAT " -- using pseudo solution instead (loop %d)\n",
4392 stat->nnodes, stat->nlps, nlperrors);
4393 }
4394 }
4395
4396 /* if an improved solution was found, propagate and solve the relaxations again */
4397 if( foundsol && !(*cutoff) )
4398 {
4399 propagateagain = TRUE;
4400 solvelpagain = TRUE;
4401 solverelaxagain = TRUE;
4402 markRelaxsUnsolved(set, relaxation);
4403 }
4404
4405 /* check for immediate restart */
4406 *restart = *restart || (actdepth == 0 && restartAllowed(set, stat) && (stat->userrestart
4407 || (stat->nrootintfixingsrun > set->presol_immrestartfac * (transprob->nvars - transprob->ncontvars)
4408 && (stat->nruns == 1 || transprob->nvars <= (1.0-set->presol_restartminred) * stat->prevrunnvars))) );
4409
4410 /* enforce constraints */
4411 branched = FALSE;
4412 if( !(*postpone) && !(*restart) && !(*cutoff) && !solverelaxagain && !solvelpagain && !propagateagain )
4413 {
4414 /* if the solution changed since the last enforcement, we have to completely reenforce it; otherwise, we
4415 * only have to enforce the additional constraints added in the last enforcement, but keep the infeasible
4416 * flag TRUE in order to not declare the infeasible solution feasible due to disregarding the already
4417 * enforced constraints
4418 */
4419 if( lastdomchgcount != stat->domchgcount || lastlpcount != stat->lpcount )
4420 {
4421 lastdomchgcount = stat->domchgcount;
4422 lastlpcount = stat->lpcount;
4423 *infeasible = FALSE;
4424 }
4425
4426 /* call constraint enforcement */
4427 SCIP_CALL( enforceConstraints(blkmem, set, messagehdlr, stat, transprob, primal, tree, lp, relaxation, sepastore,
4428 branchcand, &branched, cutoff, infeasible, &propagateagain, &solvelpagain, &solverelaxagain,
4429 forcedenforcement) );
4430 assert(branched == (tree->nchildren > 0));
4431 assert(!branched || (!(*cutoff) && *infeasible && !propagateagain && !solvelpagain));
4432 assert(!(*cutoff) || (!branched && *infeasible && !propagateagain && !solvelpagain));
4433 assert(*infeasible || (!branched && !(*cutoff) && !propagateagain && !solvelpagain));
4434 assert(!propagateagain || (!branched && !(*cutoff) && *infeasible));
4435 assert(!solvelpagain || (!branched && !(*cutoff) && *infeasible));
4436
4437 assert(BMSgetNUsedBufferMemory(mem->buffer) == 0);
4438
4439 /* apply found cuts */
4440 SCIP_CALL( applyCuts(blkmem, set, stat, transprob, origprob, tree, reopt, lp, relaxation, sepastore, branchcand,
4441 eventqueue, eventfilter, cliquetable, (actdepth == 0), SCIP_EFFICIACYCHOICE_LP, cutoff, &propagateagain,
4442 &solvelpagain, &solverelaxagain) );
4443
4444 /* update lower bound with the pseudo objective value, and cut off node by bounding */
4445 SCIP_CALL( applyBounding(blkmem, set, stat, transprob, origprob, primal, tree, reopt, lp, branchcand, eventqueue, conflict, cliquetable, cutoff) );
4446
4447 /* update the cutoff, propagateagain, and solverelaxagain status of current solving loop */
4448 updateLoopStatus(set, stat, tree, actdepth, cutoff, &propagateagain, &solverelaxagain);
4449 }
4450 assert(SCIPsepastoreGetNCuts(sepastore) == 0);
4451
4452 /* The enforcement detected no infeasibility, so, no branching was performed,
4453 * but the pricing was aborted and the current feasible solution does not have to be the
4454 * best solution in the current subtree --> we have to do a pseudo branching,
4455 * so we set infeasible TRUE and add the current solution to the solution pool
4456 */
4457 if( pricingaborted && !(*infeasible) && !(*cutoff) && !(*postpone) && !(*restart) )
4458 {
4459 SCIP_Longint oldnbestsolsfound = primal->nbestsolsfound;
4460 SCIP_SOL* sol;
4461 SCIP_Bool stored;
4462
4463 /* in case the relaxation was enforced add this solution, otherwise decide between LP and pseudosol */
4465 || SCIPsetIsGT(set, SCIPrelaxationGetSolObj(relaxation), SCIPlpGetObjval(lp, set, transprob))) )
4466 {
4467 SCIP_SOL* relaxsol;
4468
4469 SCIP_CALL( SCIPsolCreateRelaxSol(&relaxsol, blkmem, set, stat, primal, tree, relaxation, NULL) );
4470
4471 SCIP_CALL( SCIPprimalTrySol(primal, blkmem, set, messagehdlr, stat, origprob, transprob, tree, reopt, lp,
4472 eventqueue, eventfilter, relaxsol, FALSE, FALSE, TRUE, TRUE, TRUE,
4473 &stored) );
4474
4475 SCIP_CALL( SCIPsolFree(&relaxsol, blkmem, primal) );
4476
4477 if( stored )
4478 {
4479 stat->nrelaxsolsfound++;
4480
4481 if( primal->nbestsolsfound != oldnbestsolsfound )
4482 {
4483 stat->nrelaxbestsolsfound++;
4485 }
4486 }
4487 }
4488 else
4489 {
4490 SCIP_CALL( SCIPsolCreateCurrentSol(&sol, blkmem, set, stat, transprob, primal, tree, lp, NULL) );
4491 SCIP_CALL( SCIPprimalTrySolFree(primal, blkmem, set, messagehdlr, stat, origprob, transprob, tree, reopt, lp,
4492 eventqueue, eventfilter, &sol, FALSE, FALSE, TRUE, TRUE, TRUE, &stored) );
4493
4494 if( stored )
4495 {
4496 stat->nlpsolsfound++;
4497
4498 if( primal->nbestsolsfound != oldnbestsolsfound )
4499 {
4500 stat->nlpbestsolsfound++;
4502 }
4503 }
4504 }
4505
4506 *infeasible = TRUE;
4507 }
4508
4509 /* if the node is infeasible, but no constraint handler could resolve the infeasibility
4510 * -> branch on LP, external candidates, or the pseudo solution
4511 * -> e.g. select non-fixed binary or integer variable x with value x', create three
4512 * sons: x <= x'-1, x = x', and x >= x'+1.
4513 * In the left and right branch, the current solution is cut off. In the middle
4514 * branch, the constraints can hopefully reduce domains of other variables to cut
4515 * off the current solution.
4516 * In LP branching, we cannot allow adding constraints, because this does not necessary change the LP and can
4517 * therefore lead to an infinite loop.
4518 */
4519 wasforcedlpsolve = forcedlpsolve;
4520 forcedlpsolve = FALSE;
4521 if( (*infeasible) && !(*cutoff) && !(*postpone) && !(*restart)
4522 && (!(*unbounded) || SCIPbranchcandGetNExternCands(branchcand) > 0 || SCIPbranchcandGetNPseudoCands(branchcand) > 0)
4523 && !solverelaxagain && !solvelpagain && !propagateagain && !branched )
4524 {
4525 SCIP_RESULT result = SCIP_DIDNOTRUN;
4526 int nlpcands = 0;
4527
4528 if( SCIPtreeHasFocusNodeLP(tree) )
4529 {
4530 SCIP_CALL( SCIPbranchcandGetLPCands(branchcand, set, stat, lp, NULL, NULL, NULL, &nlpcands, NULL, NULL) );
4531 }
4532
4533 if ( nlpcands > 0 || SCIPbranchcandGetNExternCands(branchcand) > 0 )
4534 {
4535 /* If there are LP candidates and their maximal priority is at least the maximal priority of the external
4536 * candidates, then branch on the LP candidates. Note that due to implicit integer variables,
4537 * SCIPbranchcandGetLPMaxPrio(branchcand) might be finite and SCIPbranchcandGetNPrioLPCands(branchcand) > 0,
4538 * but nlpcands == 0. */
4539 if ( SCIPbranchcandGetLPMaxPrio(branchcand) >= SCIPbranchcandGetExternMaxPrio(branchcand) && nlpcands > 0 )
4540 {
4541 assert( SCIPbranchcandGetNPrioLPCands(branchcand) > 0 );
4542 assert( nlpcands > 0 );
4543
4544 /* branch on LP solution */
4545 SCIPsetDebugMsg(set, "infeasibility in depth %d was not resolved: branch on LP solution with %d fractionals\n",
4546 SCIPnodeGetDepth(focusnode), nlpcands);
4547 SCIP_CALL( SCIPbranchExecLP(blkmem, set, stat, transprob, origprob, tree, reopt, lp, sepastore, branchcand,
4548 eventqueue, primal->cutoffbound, FALSE, &result) );
4549 assert(BMSgetNUsedBufferMemory(mem->buffer) == 0);
4550 assert(result != SCIP_DIDNOTRUN && result != SCIP_DIDNOTFIND);
4551 }
4552 else
4553 {
4554 assert( SCIPbranchcandGetNPrioExternCands(branchcand) > 0 );
4555 assert( SCIPbranchcandGetNExternCands(branchcand) > 0 );
4556
4557 /* branch on external candidates */
4558 SCIPsetDebugMsg(set, "infeasibility in depth %d was not resolved: branch on %d external branching candidates.\n",
4559 SCIPnodeGetDepth(focusnode), SCIPbranchcandGetNExternCands(branchcand));
4560 SCIP_CALL( SCIPbranchExecExtern(blkmem, set, stat, transprob, origprob, tree, reopt, lp, sepastore, branchcand,
4561 eventqueue, primal->cutoffbound, TRUE, &result) );
4562 assert(BMSgetNUsedBufferMemory(mem->buffer) == 0);
4563 }
4564 }
4565
4566 if( result == SCIP_DIDNOTRUN || result == SCIP_DIDNOTFIND )
4567 {
4568 /* branch on pseudo solution */
4569 SCIPsetDebugMsg(set, "infeasibility in depth %d was not resolved: branch on pseudo solution with %d unfixed integers\n",
4570 SCIPnodeGetDepth(focusnode), SCIPbranchcandGetNPseudoCands(branchcand));
4571 SCIP_CALL( SCIPbranchExecPseudo(blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
4572 primal->cutoffbound, TRUE, &result) );
4573 assert(BMSgetNUsedBufferMemory(mem->buffer) == 0);
4574 }
4575
4576 /* SCIP cannot guarantee convergence if it is necessary to branch on unbounded variables */
4577 if( result == SCIP_BRANCHED )
4578 {
4579 SCIP_VAR* var = stat->lastbranchvar;
4580
4581 if( var != NULL && !stat->branchedunbdvar && SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS
4583 {
4584 SCIPmessagePrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_NORMAL,
4585 "Starting spatial branch-and-bound on unbounded variable <%s> ([%g,%g]) - cannot guarantee finite termination.\n",
4587 stat->branchedunbdvar = TRUE;
4588 }
4589 }
4590
4591 switch( result )
4592 {
4593 case SCIP_CUTOFF:
4594 assert(tree->nchildren == 0);
4595 *cutoff = TRUE;
4596 SCIPsetDebugMsg(set, " -> branching rule detected cutoff\n");
4597 break;
4598 case SCIP_CONSADDED:
4599 assert(tree->nchildren == 0);
4600 if( nlpcands > 0 )
4601 {
4602 SCIPerrorMessage("LP branching rule added constraint, which was not allowed this time\n");
4603 return SCIP_INVALIDRESULT;
4604 }
4605 propagateagain = TRUE;
4606 solvelpagain = TRUE;
4607 solverelaxagain = TRUE;
4608 markRelaxsUnsolved(set, relaxation);
4609 break;
4610 case SCIP_REDUCEDDOM:
4611 assert(tree->nchildren == 0);
4612 propagateagain = TRUE;
4613 solvelpagain = TRUE;
4614 solverelaxagain = TRUE;
4615 markRelaxsUnsolved(set, relaxation);
4616 break;
4617 case SCIP_SEPARATED:
4618 assert(tree->nchildren == 0);
4619 assert(SCIPsepastoreGetNCuts(sepastore) > 0);