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