Scippy

SCIP

Solving Constraint Integer Programs

sepastore.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-2022 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file sepastore.c
17  * @ingroup OTHER_CFILES
18  * @brief methods for storing separated cuts
19  * @author Tobias Achterberg
20  * @author Marc Pfetsch
21  * @author Leona Gottwald
22  */
23 
24 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
25 
26 #include <assert.h>
27 
28 #include "scip/def.h"
29 #include "scip/set.h"
30 #include "scip/stat.h"
31 #include "scip/lp.h"
32 #include "scip/var.h"
33 #include "scip/tree.h"
34 #include "scip/reopt.h"
35 #include "scip/sepastore.h"
36 #include "scip/event.h"
37 #include "scip/sepa.h"
38 #include "scip/cons.h"
39 #include "scip/debug.h"
40 #include "scip/scip.h"
41 #include "scip/cuts.h"
42 #include "scip/cutsel.h"
43 #include "scip/struct_event.h"
44 #include "scip/struct_sepastore.h"
45 #include "scip/misc.h"
46 
47 
48 
49 /*
50  * dynamic memory arrays
51  */
52 
53 /** resizes cuts and score arrays to be able to store at least num entries */
54 static
56  SCIP_SEPASTORE* sepastore, /**< separation storage */
57  SCIP_SET* set, /**< global SCIP settings */
58  int num /**< minimal number of slots in array */
59  )
60 {
61  assert(sepastore != NULL);
62  assert(set != NULL);
63 
64  if( num > sepastore->cutssize )
65  {
66  int newsize;
67 
68  newsize = SCIPsetCalcMemGrowSize(set, num);
69  SCIP_ALLOC( BMSreallocMemoryArray(&sepastore->cuts, newsize) );
70  sepastore->cutssize = newsize;
71  }
72  assert(num <= sepastore->cutssize);
73 
74  return SCIP_OKAY;
75 }
76 
77 /** creates separation storage */
79  SCIP_SEPASTORE** sepastore, /**< pointer to store separation storage */
80  BMS_BLKMEM* blkmem, /**< block memory */
81  SCIP_SET* set /**< global SCIP settings */
82  )
83 {
84  assert(sepastore != NULL);
85 
86  SCIP_ALLOC( BMSallocMemory(sepastore) );
87 
88  (*sepastore)->cuts = NULL;
89  (*sepastore)->cutssize = 0;
90  (*sepastore)->ncuts = 0;
91  (*sepastore)->nforcedcuts = 0;
92  (*sepastore)->ncutsadded = 0;
93  (*sepastore)->ncutsaddedviapool = 0;
94  (*sepastore)->ncutsaddeddirect = 0;
95  (*sepastore)->ncutsfoundround = 0;
96  (*sepastore)->ncutsapplied = 0;
97  (*sepastore)->initiallp = FALSE;
98  (*sepastore)->forcecuts = FALSE;
99 
100  SCIP_CALL( SCIPrandomCreate(&(*sepastore)->randnumgen, blkmem, (unsigned int)SCIPsetInitializeRandomSeed(set, 0x5EED)) );
101 
102  return SCIP_OKAY;
103 }
104 
105 /** frees separation storage */
107  SCIP_SEPASTORE** sepastore, /**< pointer to store separation storage */
108  BMS_BLKMEM* blkmem /**< block memory */
109  )
110 {
111  assert(sepastore != NULL);
112  assert(*sepastore != NULL);
113  assert((*sepastore)->ncuts == 0);
114 
115  SCIPrandomFree(&(*sepastore)->randnumgen, blkmem);
116  BMSfreeMemoryArrayNull(&(*sepastore)->cuts);
117  BMSfreeMemory(sepastore);
118 
119  return SCIP_OKAY;
120 }
121 
122 /** informs separation storage that the setup of the initial LP starts now */
124  SCIP_SEPASTORE* sepastore /**< separation storage */
125  )
126 {
127  assert(sepastore != NULL);
128  assert(!sepastore->initiallp);
129  assert(sepastore->ncuts == 0);
130 
131  sepastore->initiallp = TRUE;
132 }
133 
134 /** informs separation storage that the setup of the initial LP is now finished */
136  SCIP_SEPASTORE* sepastore /**< separation storage */
137  )
138 {
139  assert(sepastore != NULL);
140  assert(sepastore->initiallp);
141  assert(sepastore->ncuts == 0);
142 
143  sepastore->initiallp = FALSE;
144 }
145 
146 /** informs separation storage that the following cuts should be used in any case */
148  SCIP_SEPASTORE* sepastore /**< separation storage */
149  )
150 {
151  assert(sepastore != NULL);
152  assert(!sepastore->forcecuts);
153 
154  sepastore->forcecuts = TRUE;
155 }
156 
157 /** informs separation storage that the following cuts should no longer be used in any case */
159  SCIP_SEPASTORE* sepastore /**< separation storage */
160  )
161 {
162  assert(sepastore != NULL);
163  assert(sepastore->forcecuts);
164 
165  sepastore->forcecuts = FALSE;
166 }
167 
168 /** checks cut for redundancy due to activity bounds */
169 static
171  SCIP_SEPASTORE* sepastore, /**< separation storage */
172  SCIP_SET* set, /**< global SCIP settings */
173  SCIP_STAT* stat, /**< problem statistics data */
174  SCIP_ROW* cut /**< separated cut */
175  )
176 {
177  SCIP_Real minactivity;
178  SCIP_Real maxactivity;
179  SCIP_Real lhs;
180  SCIP_Real rhs;
181 
182  assert(sepastore != NULL);
183  assert(cut != NULL);
184 
185  /* modifiable cuts cannot be declared redundant, since we don't know all coefficients */
186  if( SCIProwIsModifiable(cut) )
187  return FALSE;
188 
189  /* check for activity redundancy */
190  lhs = SCIProwGetLhs(cut);
191  rhs = SCIProwGetRhs(cut);
192  minactivity = SCIProwGetMinActivity(cut, set, stat);
193  maxactivity = SCIProwGetMaxActivity(cut, set, stat);
194 
195  if( (SCIPsetIsInfinity(set, -lhs) || SCIPsetIsLE(set, lhs, minactivity)) &&
196  (SCIPsetIsInfinity(set, rhs) || SCIPsetIsLE(set, maxactivity, rhs)) )
197  {
198  SCIPsetDebugMsg(set, "ignoring activity redundant cut <%s> (sides=[%g,%g], act=[%g,%g])\n",
199  SCIProwGetName(cut), lhs, rhs, minactivity, maxactivity);
200  /*SCIPdebug(SCIProwPrint(cut, set->scip->messagehdlr, NULL));*/
201  return TRUE;
202  }
203 
204  return FALSE;
205 }
206 
207 /** checks cut for redundancy or infeasibility due to activity bounds */
208 static
210  SCIP_SEPASTORE* sepastore, /**< separation storage */
211  SCIP_SET* set, /**< global SCIP settings */
212  SCIP_STAT* stat, /**< problem statistics data */
213  SCIP_ROW* cut, /**< separated cut */
214  SCIP_Bool* infeasible /**< pointer to store whether the cut has been detected to be infeasible */
215  )
216 {
217  SCIP_Real minactivity;
218  SCIP_Real maxactivity;
219  SCIP_Real lhs;
220  SCIP_Real rhs;
221 
222  assert(sepastore != NULL);
223  assert(cut != NULL);
224  assert(infeasible != NULL);
225 
226  *infeasible = FALSE;
227 
228  /* modifiable cuts cannot be declared redundant or infeasible, since we don't know all coefficients */
229  if( SCIProwIsModifiable(cut) )
230  return FALSE;
231 
232  /* check for activity redundancy */
233  lhs = SCIProwGetLhs(cut);
234  rhs = SCIProwGetRhs(cut);
235  minactivity = SCIProwGetMinActivity(cut, set, stat);
236  maxactivity = SCIProwGetMaxActivity(cut, set, stat);
237 
238  if( (SCIPsetIsInfinity(set, -lhs) || SCIPsetIsLE(set, lhs, minactivity)) &&
239  (SCIPsetIsInfinity(set, rhs) || SCIPsetIsLE(set, maxactivity, rhs)) )
240  {
241  SCIPsetDebugMsg(set, "ignoring activity redundant cut <%s> (sides=[%g,%g], act=[%g,%g])\n",
242  SCIProwGetName(cut), lhs, rhs, minactivity, maxactivity);
243  /*SCIPdebug(SCIProwPrint(cut, set->scip->messagehdlr, NULL));*/
244  return TRUE;
245  }
246 
247  if( (!SCIPsetIsInfinity(set, rhs) && SCIPsetIsFeasPositive(set, minactivity - rhs)) ||
248  (!SCIPsetIsInfinity(set, -lhs) && SCIPsetIsFeasNegative(set, maxactivity - lhs)) )
249  {
250  SCIPsetDebugMsg(set, "cut <%s> is infeasible (sides=[%g,%g], act=[%g,%g])\n",
251  SCIProwGetName(cut), lhs, rhs, minactivity, maxactivity);
252  /*SCIPdebug(SCIProwPrint(cut, set->scip->messagehdlr, NULL));*/
253  *infeasible = TRUE;
254  return TRUE;
255  }
256 
257  return FALSE;
258 }
259 
260 /** checks whether a cut with only one variable can be applied as boundchange
261  *
262  * This is the case if the bound change would prove infeasibility (w.r.t feastol), or if the new bound is at least
263  * epsilon better than the old bound. In the latter case, also the opposite bound has to be taken into account.
264  */
265 static
267  SCIP_SET* set, /**< global SCIP settings */
268  SCIP_ROW* cut /**< cut with a single variable */
269  )
270 {
271  SCIP_COL** cols;
272  SCIP_Real* vals;
273  SCIP_VAR* var;
274  SCIP_Real lhs;
275  SCIP_Real rhs;
276  SCIP_Bool local;
277  SCIP_Real oldlb;
278  SCIP_Real oldub;
279 
280  assert(set != NULL);
281  assert(cut != NULL);
282  assert(!SCIProwIsModifiable(cut));
283  assert(SCIProwGetNNonz(cut) == 1);
284 
285  /* get the single variable and its coefficient of the cut */
286  cols = SCIProwGetCols(cut);
287  assert(cols != NULL);
288 
289  var = SCIPcolGetVar(cols[0]);
290  vals = SCIProwGetVals(cut);
291  assert(vals != NULL);
292  assert(!SCIPsetIsZero(set, vals[0]));
293 
294  /* if the coefficient is nearly zero, we better ignore this cut for numerical reasons */
295  if( SCIPsetIsFeasZero(set, vals[0]) )
296  return FALSE;
297 
298  local = SCIProwIsLocal(cut);
299 
300  oldlb = local ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
301  oldub = local ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
302 
303  /* get the left hand side of the cut and convert it to a bound */
304  lhs = SCIProwGetLhs(cut);
305  if( !SCIPsetIsInfinity(set, -lhs) )
306  {
307  lhs -= SCIProwGetConstant(cut);
308  if( vals[0] > 0.0 )
309  {
310  /* coefficient is positive -> lhs corresponds to lower bound */
311  SCIP_Real newlb;
312 
313  newlb = lhs/vals[0];
314  SCIPvarAdjustLb(var, set, &newlb);
315 
316  /* bound changes that improve the bound sufficiently are applicable */
317  if( SCIPsetIsFeasGT(set, newlb, oldub) || SCIPsetIsGT(set, MIN(newlb, oldub), oldlb) )
318  return TRUE;
319  }
320  else
321  {
322  /* coefficient is negative -> lhs corresponds to upper bound */
323  SCIP_Real newub;
324 
325  newub = lhs/vals[0];
326  SCIPvarAdjustUb(var, set, &newub);
327 
328  /* bound changes that improve the bound sufficiently are applicable */
329  if( SCIPsetIsFeasLT(set, newub, oldlb) || SCIPsetIsLT(set, MAX(newub, oldlb), oldub) )
330  return TRUE;
331  }
332  }
333 
334  /* get the right hand side of the cut and convert it to a bound */
335  rhs = SCIProwGetRhs(cut);
336  if( !SCIPsetIsInfinity(set, rhs) )
337  {
338  rhs -= SCIProwGetConstant(cut);
339  if( vals[0] > 0.0 )
340  {
341  /* coefficient is positive -> rhs corresponds to upper bound */
342  SCIP_Real newub;
343 
344  newub = rhs/vals[0];
345  SCIPvarAdjustUb(var, set, &newub);
346 
347  /* bound changes that improve the bound sufficiently are applicable */
348  if( SCIPsetIsFeasLT(set, newub, oldlb) || SCIPsetIsLT(set, MAX(newub, oldlb), oldub) )
349  return TRUE;
350  }
351  else
352  {
353  /* coefficient is negative -> rhs corresponds to lower bound */
354  SCIP_Real newlb;
355 
356  newlb = rhs/vals[0];
357  SCIPvarAdjustLb(var, set, &newlb);
358 
359  /* bound changes that improve the bound sufficiently are applicable */
360  if( SCIPsetIsFeasGT(set, newlb, oldub) || SCIPsetIsGT(set, MIN(newlb, oldub), oldlb) )
361  return TRUE;
362  }
363  }
364 
365  return FALSE;
366 }
367 
368 /** removes a non-forced cut from the separation storage */
369 static
371  SCIP_SEPASTORE* sepastore, /**< separation storage */
372  BMS_BLKMEM* blkmem, /**< block memory */
373  SCIP_SET* set, /**< global SCIP settings */
374  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
375  SCIP_EVENTFILTER* eventfilter, /**< event filter for global events */
376  SCIP_LP* lp, /**< LP data */
377  int pos /**< position of cut to delete */
378  )
379 {
380  assert(sepastore != NULL);
381  assert(sepastore->cuts != NULL);
382  assert(sepastore->nforcedcuts <= pos && pos < sepastore->ncuts);
383 
384  /* check, if the row deletions from separation storage events are tracked if so, issue ROWDELETEDSEPA event */
385  if( eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWDELETEDSEPA) != 0 )
386  {
387  SCIP_EVENT* event;
388 
389  SCIP_CALL( SCIPeventCreateRowDeletedSepa(&event, blkmem, sepastore->cuts[pos]) );
390  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) );
391  }
392 
393  /* release the row */
394  if( !sepastore->initiallp )
395  {
396  sepastore->ncutsadded--;
397  if( sepastore->cuts[pos]->fromcutpool )
398  sepastore->ncutsaddedviapool--;
399  else
400  sepastore->ncutsaddeddirect--;
401 
402  if( (SCIP_ROWORIGINTYPE) sepastore->cuts[pos]->origintype == SCIP_ROWORIGINTYPE_SEPA )
403  {
404  SCIP_SEPA* sepa;
405  sepa = SCIProwGetOriginSepa(sepastore->cuts[pos]);
406  SCIPsepaDecNCutsAdded(sepa, sepastore->cuts[pos]->fromcutpool);
407  }
408  }
409  SCIP_CALL( SCIProwRelease(&sepastore->cuts[pos], blkmem, set, lp) );
410 
411  /* move last cut to the empty position */
412  sepastore->cuts[pos] = sepastore->cuts[sepastore->ncuts-1];
413  sepastore->ncuts--;
414 
415  return SCIP_OKAY;
416 }
417 
418 /** adds cut to separation storage and captures it */
420  SCIP_SEPASTORE* sepastore, /**< separation storage */
421  BMS_BLKMEM* blkmem, /**< block memory */
422  SCIP_SET* set, /**< global SCIP settings */
423  SCIP_STAT* stat, /**< problem statistics data */
424  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
425  SCIP_EVENTFILTER* eventfilter, /**< event filter for global events */
426  SCIP_LP* lp, /**< LP data */
427  SCIP_ROW* cut, /**< separated cut */
428  SCIP_Bool forcecut, /**< should the cut be forced to enter the LP? */
429  SCIP_Bool root, /**< are we at the root node? */
430  SCIP_Bool* infeasible /**< pointer to store whether the cut is infeasible */
431  )
432 {
433  SCIP_Bool redundant;
434  int pos;
435 
436  assert(sepastore != NULL);
437  assert(sepastore->nforcedcuts <= sepastore->ncuts);
438  assert(set != NULL);
439  assert(cut != NULL);
440  assert(!SCIPsetIsInfinity(set, -SCIProwGetLhs(cut)) || !SCIPsetIsInfinity(set, SCIProwGetRhs(cut)));
441  assert(eventqueue != NULL);
442  assert(eventfilter != NULL);
443 
444  /* debug: check cut for feasibility */
445  SCIP_CALL( SCIPdebugCheckRow(set, cut) ); /*lint !e506 !e774*/
446 
447  /* the cut will be forced to enter the LP if the dual must be collected and the initial LP is being constructed */
448  forcecut = forcecut || (set->lp_alwaysgetduals && sepastore->initiallp);
449 
450  /* in the root node, every local cut is a global cut, and global cuts are nicer in many ways ... */
451  if( root && SCIProwIsLocal(cut) )
452  {
453  SCIPsetDebugMsg(set, "change local flag of cut <%s> to FALSE due to addition in root node\n", SCIProwGetName(cut));
454 
456 
457  assert(!SCIProwIsLocal(cut));
458  }
459 
460  /* check cut for redundancy or infeasibility */
461  redundant = sepastoreIsCutRedundantOrInfeasible(sepastore, set, stat, cut, infeasible);
462  /* Note that we add infeasible rows in any case, since we cannot be sure whether the return values are handled
463  * correctly. In this way, the LP becomes infeasible. */
464 
465  /* in each separation round, make sure that at least one (even redundant) cut enters the LP to avoid cycling */
466  if( !forcecut && sepastore->ncuts > 0 && redundant )
467  return SCIP_OKAY;
468 
469  /* if only one cut is currently present in sepastore, it could be redundant; in this case, it can now be removed
470  * again, because now a non redundant cut enters the sepastore */
471  if( sepastore->ncuts == 1 && sepastoreIsCutRedundant(sepastore, set, stat, sepastore->cuts[0]) )
472  {
473  /* check, if the row deletions from separation storage events are tracked if so, issue ROWDELETEDSEPA event */
474  if( eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWDELETEDSEPA) != 0 )
475  {
476  SCIP_EVENT* event;
477 
478  SCIP_CALL( SCIPeventCreateRowDeletedSepa(&event, blkmem, sepastore->cuts[0]) );
479  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) );
480  }
481  /* update statistics of total number of found cuts */
482  if( !sepastore->initiallp )
483  {
484  sepastore->ncutsadded--;
485  if( sepastore->cuts[0]->fromcutpool )
486  sepastore->ncutsaddedviapool--;
487  else
488  sepastore->ncutsaddeddirect--;
489 
491  {
492  SCIP_SEPA* sepa;
493  sepa = SCIProwGetOriginSepa(sepastore->cuts[0]);
494  SCIPsepaDecNCutsAdded(sepa, sepastore->cuts[0]->fromcutpool);
495  }
496  }
497 
498  SCIP_CALL( SCIProwRelease(&sepastore->cuts[0], blkmem, set, lp) );
499  sepastore->ncuts = 0;
500  sepastore->nforcedcuts = 0;
501  }
502 
503  /* a cut is forced to enter the LP if
504  * - we construct the initial LP, or
505  * - it has infinite score factor, or
506  * - it is a bound change that can be applied
507  * if it is a non-forced cut and no cuts should be added, abort
508  */
509  forcecut = forcecut || sepastore->initiallp || sepastore->forcecuts || (!SCIProwIsModifiable(cut) && SCIProwGetNNonz(cut) == 1 && sepastoreIsBdchgApplicable(set, cut));
510  if( !forcecut && SCIPsetGetSepaMaxcuts(set, root) == 0 )
511  return SCIP_OKAY;
512 
513  /* get enough memory to store the cut */
514  SCIP_CALL( sepastoreEnsureCutsMem(sepastore, set, sepastore->ncuts+1) );
515  assert(sepastore->ncuts < sepastore->cutssize);
516 
517  SCIPsetDebugMsg(set, "adding cut <%s> to separation storage of size %d (forcecut=%u, len=%d)\n",
518  SCIProwGetName(cut), sepastore->ncuts, forcecut, SCIProwGetNNonz(cut));
519  /*SCIP_CALL( SCIPprintRow(set->scip, cut, NULL) );*/
520 
521  /* capture the cut */
522  SCIProwCapture(cut);
523 
524  /* add cut to arrays */
525  if( forcecut )
526  {
527  /* make room at the beginning of the array for forced cut */
528  pos = sepastore->nforcedcuts;
529  sepastore->cuts[sepastore->ncuts] = sepastore->cuts[pos];
530  sepastore->nforcedcuts++;
531  }
532  else
533  pos = sepastore->ncuts;
534 
535  sepastore->cuts[pos] = cut;
536 
537  /* update statistics of total number of found cuts */
538  if( !sepastore->initiallp )
539  {
540  sepastore->ncutsadded++;
541  sepastore->ncutsfoundround++;
542  if( cut->fromcutpool )
543  sepastore->ncutsaddedviapool++;
544  else
545  sepastore->ncutsaddeddirect++;
546 
548  {
549  SCIP_SEPA* sepa;
550 
551  sepa = SCIProwGetOriginSepa(cut);
553  }
554  }
555  sepastore->ncuts++;
556 
557  /* check, if the row addition to separation storage events are tracked if so, issue ROWADDEDSEPA event */
558  if( eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWADDEDSEPA) != 0 )
559  {
560  SCIP_EVENT* event;
561 
562  SCIP_CALL( SCIPeventCreateRowAddedSepa(&event, blkmem, cut) );
563  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) );
564  }
565 
566  /* If the duals need to be collected, then the infeasible flag is set to FALSE. This ensures that the LP is solved */
567  if( set->lp_alwaysgetduals && sepastore->initiallp )
568  (*infeasible) = FALSE;
569 
570  return SCIP_OKAY;
571 }
572 
573 /** applies a lower bound change */
574 static
576  SCIP_SEPASTORE* sepastore, /**< separation storage */
577  BMS_BLKMEM* blkmem, /**< block memory */
578  SCIP_SET* set, /**< global SCIP settings */
579  SCIP_STAT* stat, /**< problem statistics */
580  SCIP_PROB* transprob, /**< transformed problem */
581  SCIP_PROB* origprob, /**< original problem */
582  SCIP_TREE* tree, /**< branch and bound tree */
583  SCIP_REOPT* reopt, /**< reoptimization data structure */
584  SCIP_LP* lp, /**< LP data */
585  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
586  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
587  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
588  SCIP_VAR* var, /**< problem variable */
589  SCIP_Real bound, /**< new lower bound of variable */
590  SCIP_Bool local, /**< is it a local bound change? (otherwise global) */
591  SCIP_Bool* applied, /**< pointer to store whether the domain change was applied */
592  SCIP_Bool* cutoff /**< pointer to store TRUE, if an infeasibility has been detected */
593  )
594 {
595  assert(sepastore != NULL);
596  assert(cutoff != NULL);
597  assert(applied != NULL);
598 
599  /* adjust bound to the one that would be applied, so the SCIPsetIsGT check below is more reliable */
600  SCIPvarAdjustLb(var, set, &bound);
601 
602  if( local )
603  {
604  /* apply the local bound change or detect a cutoff */
605  if( SCIPsetIsGT(set, bound, SCIPvarGetLbLocal(var)) )
606  {
607  SCIPsetDebugMsg(set, " -> applying bound change: <%s>: [%.15g,%.15g] -> [%.15g,%.15g]\n",
609 
610  /* changing the lower bound to a value >= SCIPinfinity should result in a cutoff,
611  * since "infinite" values in solutions are reserved for another meaning
612  */
613  if( !SCIPsetIsInfinity(set, bound) && SCIPsetIsFeasLE(set, bound, SCIPvarGetUbLocal(var)) )
614  {
615  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetCurrentNode(tree), blkmem, set, stat, transprob, origprob, tree,
616  reopt, lp, branchcand, eventqueue, cliquetable, var, bound, SCIP_BOUNDTYPE_LOWER, FALSE) );
617  }
618  else
619  *cutoff = TRUE;
620 
621  *applied = TRUE;
622  }
623  else
624  {
625  SCIPsetDebugMsg(set, " -> ignoring bound change: <%s>: [%.15g,%.15g] -> [%.15g,%.15g]\n",
627  }
628  }
629  else
630  {
631  /* apply the global bound change or detect a global cutoff which means we can cutoff the root node */
632  if( SCIPsetIsGT(set, bound, SCIPvarGetLbGlobal(var)) )
633  {
634  SCIPsetDebugMsg(set, " -> applying global bound change: <%s>: [%.15g,%.15g] -> [%.15g,%.15g]\n",
636 
637  /* changing the lower bound to a value >= SCIPinfinity should result in a cutoff,
638  * since "infinite" values in solutions are reserved for another meaning
639  */
640  if( !SCIPsetIsInfinity(set, bound) && SCIPsetIsFeasLE(set, bound, SCIPvarGetUbGlobal(var)) )
641  {
642  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, tree, reopt,
643  lp, branchcand, eventqueue, cliquetable, var, bound, SCIP_BOUNDTYPE_LOWER, FALSE) );
644  }
645  else
646  {
647  /* we are done with solving since a global bound change is infeasible */
648  SCIP_CALL( SCIPnodeCutoff(SCIPtreeGetRootNode(tree), set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
649  *cutoff = TRUE;
650  }
651 
652  *applied = TRUE;
653  }
654  else
655  {
656  SCIPsetDebugMsg(set, " -> ignoring global bound change: <%s>: [%.15g,%.15g] -> [%.15g,%.15g]\n",
658  }
659  }
660 
661  return SCIP_OKAY;
662 }
663 
664 /** applies an upper bound change */
665 static
667  SCIP_SEPASTORE* sepastore, /**< separation storage */
668  BMS_BLKMEM* blkmem, /**< block memory */
669  SCIP_SET* set, /**< global SCIP settings */
670  SCIP_STAT* stat, /**< problem statistics */
671  SCIP_PROB* transprob, /**< transformed problem */
672  SCIP_PROB* origprob, /**< original problem */
673  SCIP_TREE* tree, /**< branch and bound tree */
674  SCIP_REOPT* reopt, /**< reoptimization data structure */
675  SCIP_LP* lp, /**< LP data */
676  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
677  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
678  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
679  SCIP_VAR* var, /**< problem variable */
680  SCIP_Real bound, /**< new upper bound of variable */
681  SCIP_Bool local, /**< is it a local bound change? (otherwise global) */
682  SCIP_Bool* applied, /**< pointer to store whether the domain change was applied */
683  SCIP_Bool* cutoff /**< pointer to store TRUE, if an infeasibility has been detected */
684  )
685 {
686  assert(sepastore != NULL);
687  assert(cutoff != NULL);
688  assert(applied != NULL);
689 
690  /* adjust bound to the one that would be applied, so the SCIPsetIsGT check below is more reliable */
691  SCIPvarAdjustUb(var, set, &bound);
692 
693  if( local )
694  {
695  /* apply the local bound change or detect a cutoff */
696  if( SCIPsetIsLT(set, bound, SCIPvarGetUbLocal(var)) )
697  {
698  SCIPsetDebugMsg(set, " -> applying bound change: <%s>: [%.15g,%.15g] -> [%.15g,%.15g]\n",
700 
701  /* changing the upper bound to a value <= -SCIPinfinity should result in a cutoff,
702  * since "infinite" values in solutions are reserved for another meaning
703  */
704  if( !SCIPsetIsInfinity(set, -bound) && SCIPsetIsFeasGE(set, bound, SCIPvarGetLbLocal(var)) )
705  {
706  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetCurrentNode(tree), blkmem, set, stat, transprob, origprob, tree,
707  reopt, lp, branchcand, eventqueue, cliquetable, var, bound, SCIP_BOUNDTYPE_UPPER, FALSE) );
708  }
709  else
710  *cutoff = TRUE;
711 
712  *applied = TRUE;
713  }
714  else
715  {
716  SCIPsetDebugMsg(set, " -> ignoring bound change: <%s>: [%.15g,%.15g] -> [%.15g,%.15g]\n",
718  }
719  }
720  else
721  {
722  /* apply the global bound change or detect a global cutoff which means we can cutoff the root node */
723  if( SCIPsetIsLT(set, bound, SCIPvarGetUbGlobal(var)) )
724  {
725  SCIPsetDebugMsg(set, " -> applying global bound change: <%s>: [%.15g,%.15g] -> [%.15g,%.15g]\n",
727 
728  /* changing the upper bound to a value <= -SCIPinfinity should result in a cutoff,
729  * since "infinite" values in solutions are reserved for another meaning
730  */
731  if( !SCIPsetIsInfinity(set, -bound) && SCIPsetIsFeasGE(set, bound, SCIPvarGetLbGlobal(var)) )
732  {
733  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, tree, reopt,
734  lp, branchcand, eventqueue, cliquetable, var, bound, SCIP_BOUNDTYPE_UPPER, FALSE) );
735  }
736  else
737  {
738  /* we are done with solving since a global bound change is infeasible */
739  SCIP_CALL( SCIPnodeCutoff(SCIPtreeGetRootNode(tree), set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
740  *cutoff = TRUE;
741  }
742 
743  *applied = TRUE;
744  }
745  else
746  {
747  SCIPsetDebugMsg(set, " -> ignoring global bound change: <%s>: [%.15g,%.15g] -> [%.15g,%.15g]\n",
749  }
750  }
751 
752  return SCIP_OKAY;
753 }
754 
755 /** applies a cut that is a bound change directly as bound change instead of adding it as row to the LP */
756 static
758  SCIP_SEPASTORE* sepastore, /**< separation storage */
759  BMS_BLKMEM* blkmem, /**< block memory */
760  SCIP_SET* set, /**< global SCIP settings */
761  SCIP_STAT* stat, /**< problem statistics */
762  SCIP_PROB* transprob, /**< transformed problem */
763  SCIP_PROB* origprob, /**< original problem */
764  SCIP_TREE* tree, /**< branch and bound tree */
765  SCIP_REOPT* reopt, /**< reoptimization data structure */
766  SCIP_LP* lp, /**< LP data */
767  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
768  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
769  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
770  SCIP_ROW* cut, /**< cut with a single variable */
771  SCIP_Bool* applied, /**< pointer to store whether the domain change was applied */
772  SCIP_Bool* cutoff /**< pointer to store whether an empty domain was created */
773  )
774 {
775  SCIP_COL** cols;
776  SCIP_Real* vals;
777  SCIP_VAR* var;
778  SCIP_Real lhs;
779  SCIP_Real rhs;
780  SCIP_Bool local;
781 
782  assert(sepastore != NULL);
783  assert(!SCIProwIsModifiable(cut));
784  assert(SCIProwGetNNonz(cut) == 1);
785  assert(cutoff != NULL);
786  assert(applied != NULL);
787 
788  *applied = FALSE;
789  *cutoff = FALSE;
790 
791  /* get the single variable and its coefficient of the cut */
792  cols = SCIProwGetCols(cut);
793  assert(cols != NULL);
794 
795  var = SCIPcolGetVar(cols[0]);
796  vals = SCIProwGetVals(cut);
797  assert(vals != NULL);
798  assert(!SCIPsetIsZero(set, vals[0]));
799 
800  /* if the coefficient is nearly zero, we better ignore this cut for numerical reasons */
801  if( SCIPsetIsFeasZero(set, vals[0]) )
802  return SCIP_OKAY;
803 
804  local = SCIProwIsLocal(cut);
805 
806  /* get the left hand side of the cut and convert it to a bound */
807  lhs = SCIProwGetLhs(cut);
808  if( !SCIPsetIsInfinity(set, -lhs) )
809  {
810  lhs -= SCIProwGetConstant(cut);
811  if( vals[0] > 0.0 )
812  {
813  /* coefficient is positive -> lhs corresponds to lower bound */
814  SCIP_CALL( sepastoreApplyLb(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
815  cliquetable, var, lhs/vals[0], local, applied, cutoff) );
816  }
817  else
818  {
819  /* coefficient is negative -> lhs corresponds to upper bound */
820  SCIP_CALL( sepastoreApplyUb(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
821  cliquetable, var, lhs/vals[0], local, applied, cutoff) );
822  }
823  }
824 
825  /* get the right hand side of the cut and convert it to a bound */
826  rhs = SCIProwGetRhs(cut);
827  if( !SCIPsetIsInfinity(set, rhs) )
828  {
829  rhs -= SCIProwGetConstant(cut);
830  if( vals[0] > 0.0 )
831  {
832  /* coefficient is positive -> rhs corresponds to upper bound */
833  SCIP_CALL( sepastoreApplyUb(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
834  cliquetable, var, rhs/vals[0], local, applied, cutoff) );
835  }
836  else
837  {
838  /* coefficient is negative -> rhs corresponds to lower bound */
839  SCIP_CALL( sepastoreApplyLb(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
840  cliquetable, var, rhs/vals[0], local, applied, cutoff) );
841  }
842  }
843 
844  /* count the bound change as applied cut */
845  if( *applied && !sepastore->initiallp )
846  sepastore->ncutsapplied++;
847 
848  return SCIP_OKAY;
849 }
850 
851 /** applies the given cut to the LP and updates the orthogonalities and scores of remaining cuts */
852 static
854  SCIP_SEPASTORE* sepastore, /**< separation storage */
855  BMS_BLKMEM* blkmem, /**< block memory */
856  SCIP_SET* set, /**< global SCIP settings */
857  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
858  SCIP_EVENTFILTER* eventfilter, /**< global event filter */
859  SCIP_LP* lp, /**< LP data */
860  SCIP_ROW* cut, /**< cut to apply to the LP */
861  int depth, /**< depth of current node */
862  int* ncutsapplied /**< pointer to count the number of applied cuts */
863  )
864 {
865  assert(sepastore != NULL);
866  assert(ncutsapplied != NULL);
867 
868  /* a row could have been added twice to the separation store; add it only once! */
869  if( !SCIProwIsInLP(cut) )
870  {
871  /* add cut to the LP and capture it */
872  SCIP_CALL( SCIPlpAddRow(lp, blkmem, set, eventqueue, eventfilter, cut, depth) );
873 
874  /* update statistics -> only if we are not in the initial lp (cuts are only counted if added during run) */
875  if( !sepastore->initiallp )
876  {
877  sepastore->ncutsapplied++;
878 
879  /* increase count of applied cuts for origins of row */
880  /* TODO: adjust conshdlr statistics to mirror cut statistics */
881  switch ( (SCIP_ROWORIGINTYPE) cut->origintype )
882  {
884  assert( cut->origin != NULL );
886  break;
888  assert( cut->origin != NULL );
890  break;
892  assert( cut->origin != NULL );
894  break;
897  /* do nothing - cannot update statistics */
898  break;
899  default:
900  SCIPerrorMessage("unknown type of row origin.\n");
901  return SCIP_INVALIDDATA;
902  }
903  }
904 
905  (*ncutsapplied)++;
906  }
907 
908  return SCIP_OKAY;
909 }
910 
911 /** adds cuts to the LP and clears separation storage */
913  SCIP_SEPASTORE* sepastore, /**< separation storage */
914  BMS_BLKMEM* blkmem, /**< block memory */
915  SCIP_SET* set, /**< global SCIP settings */
916  SCIP_STAT* stat, /**< problem statistics */
917  SCIP_PROB* transprob, /**< transformed problem */
918  SCIP_PROB* origprob, /**< original problem */
919  SCIP_TREE* tree, /**< branch and bound tree */
920  SCIP_REOPT* reopt, /**< reoptimization data structure */
921  SCIP_LP* lp, /**< LP data */
922  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
923  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
924  SCIP_EVENTFILTER* eventfilter, /**< global event filter */
925  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
926  SCIP_Bool root, /**< are we at the root node? */
927  SCIP_EFFICIACYCHOICE efficiacychoice, /**< type of solution to base efficiacy computation on */
928  SCIP_Bool* cutoff /**< pointer to store whether an empty domain was created */
929  )
930 {
931  SCIP_NODE* node;
932  int maxsepacuts;
933  int ncutsapplied;
934  int nselectedcuts;
935  int depth;
936  int i;
937 
938  assert(sepastore != NULL);
939  assert(set != NULL);
940  assert(tree != NULL);
941  assert(lp != NULL);
942  assert(cutoff != NULL);
943 
944  SCIP_UNUSED(efficiacychoice);
945 
946  SCIPsetDebugMsg(set, "selecting from %d cuts\n", sepastore->ncuts);
947 
948  /* get maximal number of cuts to add to the LP */
949  maxsepacuts = SCIPsetGetSepaMaxcuts(set, root);
950 
951  /* if all cuts are forced cuts, no selection is required */
952  if( sepastore->nforcedcuts >= MIN(sepastore->ncuts, maxsepacuts) )
953  {
954  nselectedcuts = sepastore->nforcedcuts;
955  }
956  else
957  {
958  /* call cut selection algorithms */
959  nselectedcuts = 0;
960  SCIP_CALL( SCIPcutselsSelect(set, sepastore->cuts, sepastore->ncuts, sepastore->nforcedcuts, root, sepastore->initiallp, maxsepacuts,
961  &nselectedcuts) );
962  assert(nselectedcuts + sepastore->nforcedcuts <= maxsepacuts);
963 
964  /* note that cut selector statistics are updated here also when in probing mode; this may lead to an offset with
965  * separator/constraint handler statistics */
966  /* @todo do not update cutselector statistics if SCIPtreeProbing(scip->tree) */
967  nselectedcuts += sepastore->nforcedcuts;
968  }
969 
970  /*
971  * apply all selected cuts
972  */
973  ncutsapplied = 0;
974  *cutoff = FALSE;
975 
976  node = SCIPtreeGetCurrentNode(tree);
977  assert(node != NULL);
978 
979  /* get depth of current node */
980  depth = SCIPnodeGetDepth(node);
981 
982  for( i = 0; i < nselectedcuts && !(*cutoff); i++ )
983  {
984  SCIP_ROW* cut;
985 
986  cut = sepastore->cuts[i];
987 
988  if( i < sepastore->nforcedcuts || SCIPsetIsFeasPositive(set, SCIProwGetLPEfficacy(cut, set, stat, lp)) )
989  {
990  SCIP_Bool applied = FALSE;
991 
992  /* if the cut is a bound change (i.e. a row with only one variable), add it as bound change instead of LP row */
993  if( !SCIProwIsModifiable(cut) && SCIProwGetNNonz(cut) == 1 )
994  {
995  SCIPsetDebugMsg(set, " -> applying forced cut <%s> as boundchange\n", SCIProwGetName(cut));
996  SCIP_CALL( sepastoreApplyBdchg(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
997  eventqueue, cliquetable, cut, &applied, cutoff) );
998  assert(applied || !sepastoreIsBdchgApplicable(set, cut));
999  }
1000 
1001  if( !applied )
1002  {
1003  /* add cut to the LP and update orthogonalities */
1004  SCIPsetDebugMsg(set, " -> applying%s cut <%s>\n", (i < sepastore->nforcedcuts) ? " forced" : "", SCIProwGetName(cut));
1005  /*SCIPdebug( SCIProwPrint(cut, set->scip->messagehdlr, NULL));*/
1006  SCIP_CALL( sepastoreApplyCut(sepastore, blkmem, set, eventqueue, eventfilter, lp, cut, depth, &ncutsapplied) );
1007  }
1008  }
1009  }
1010 
1011  /* clear the separation storage and reset statistics for separation round */
1012  SCIP_CALL( SCIPsepastoreClearCuts(sepastore, blkmem, set, eventqueue, eventfilter, lp) );
1013 
1014  return SCIP_OKAY;
1015 }
1016 
1017 /** clears the separation storage without adding the cuts to the LP */
1019  SCIP_SEPASTORE* sepastore, /**< separation storage */
1020  BMS_BLKMEM* blkmem, /**< block memory */
1021  SCIP_SET* set, /**< global SCIP settings */
1022  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1023  SCIP_EVENTFILTER* eventfilter, /**< event filter for global events */
1024  SCIP_LP* lp /**< LP data */
1025  )
1026 {
1027  int c;
1028 
1029  assert(sepastore != NULL);
1030 
1031  SCIPsetDebugMsg(set, "clearing %d cuts\n", sepastore->ncuts);
1032 
1033  /* release cuts */
1034  for( c = 0; c < sepastore->ncuts; ++c )
1035  {
1036  /* check, if the row deletions from separation storage events are tracked if so, issue ROWDELETEDSEPA event */
1037  if( eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWDELETEDSEPA) != 0 )
1038  {
1039  SCIP_EVENT* event;
1040 
1041  SCIP_CALL( SCIPeventCreateRowDeletedSepa(&event, blkmem, sepastore->cuts[c]) );
1042  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) );
1043  }
1044 
1045  SCIP_CALL( SCIProwRelease(&sepastore->cuts[c], blkmem, set, lp) );
1046  }
1047 
1048  /* reset counters */
1049  sepastore->ncuts = 0;
1050  sepastore->nforcedcuts = 0;
1051  sepastore->ncutsfoundround = 0;
1052 
1053  /* if we have just finished the initial LP construction, free the (potentially large) cuts array */
1054  if( sepastore->initiallp )
1055  {
1056  BMSfreeMemoryArrayNull(&sepastore->cuts);
1057  sepastore->cutssize = 0;
1058  }
1059 
1060  return SCIP_OKAY;
1061 }
1062 
1063 /** removes cuts that are inefficacious w.r.t. the current LP solution from separation storage without adding the cuts to the LP */
1065  SCIP_SEPASTORE* sepastore, /**< separation storage */
1066  BMS_BLKMEM* blkmem, /**< block memory */
1067  SCIP_SET* set, /**< global SCIP settings */
1068  SCIP_STAT* stat, /**< problem statistics data */
1069  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1070  SCIP_EVENTFILTER* eventfilter, /**< event filter for global events */
1071  SCIP_LP* lp, /**< LP data */
1072  SCIP_Bool root, /**< are we at the root node? */
1073  SCIP_EFFICIACYCHOICE efficiacychoice /**< type of solution to base efficiacy computation on */
1074  )
1075 {
1076  int cnt = 0;
1077  int c;
1078 
1079  assert( sepastore != NULL );
1080 
1081  /* check non-forced cuts only */
1082  c = sepastore->nforcedcuts;
1083  while( c < sepastore->ncuts )
1084  {
1085  SCIP_Real cutefficacy;
1086 
1087  /* calculate cut's efficacy */
1088  switch ( efficiacychoice )
1089  {
1091  cutefficacy = SCIProwGetLPEfficacy(sepastore->cuts[c], set, stat, lp);
1092  break;
1094  cutefficacy = SCIProwGetRelaxEfficacy(sepastore->cuts[c], set, stat);
1095  break;
1097  cutefficacy = SCIProwGetNLPEfficacy(sepastore->cuts[c], set, stat);
1098  break;
1099  default:
1100  SCIPerrorMessage("Invalid efficiacy choice.\n");
1101  return SCIP_INVALIDCALL;
1102  }
1103 
1104  if( !SCIPsetIsEfficacious(set, root, cutefficacy) )
1105  {
1106  SCIP_CALL( sepastoreDelCut(sepastore, blkmem, set, eventqueue, eventfilter, lp, c) );
1107  ++cnt;
1108  }
1109  else
1110  ++c;
1111  }
1112  SCIPsetDebugMsg(set, "removed %d non-efficacious cuts\n", cnt);
1113 
1114  return SCIP_OKAY;
1115 }
1116 
1117 /** indicates whether a cut is applicable
1118  *
1119  * A cut is applicable if it is modifiable, not a bound change, or a bound change that changes bounds by at least epsilon.
1120  */
1122  SCIP_SET* set, /**< global SCIP settings */
1123  SCIP_ROW* cut /**< cut to check */
1124  )
1125 {
1126  return SCIProwIsModifiable(cut) || SCIProwGetNNonz(cut) != 1 || sepastoreIsBdchgApplicable(set, cut);
1127 }
1128 
1129 /** get cuts in the separation storage */
1131  SCIP_SEPASTORE* sepastore /**< separation storage */
1132  )
1133 {
1134  assert(sepastore != NULL);
1135 
1136  return sepastore->cuts;
1137 }
1138 
1139 /** get number of cuts in the separation storage */
1141  SCIP_SEPASTORE* sepastore /**< separation storage */
1142  )
1143 {
1144  assert(sepastore != NULL);
1145 
1146  return sepastore->ncuts;
1147 }
1148 
1149 /** gets the total number of cutting planes added to the separation storage;
1150  * this is equal to the sum of added cuts directly and via the pool. */
1152  SCIP_SEPASTORE* sepastore /**< separation storage */
1153  )
1154 {
1155  assert(sepastore != NULL);
1156 
1157  return sepastore->ncutsadded;
1158 }
1159 
1160 /** gets the number of cutting planes added to the separation storage from the cut pool */
1162  SCIP_SEPASTORE* sepastore /**< separation storage */
1163  )
1164 {
1165  assert(sepastore != NULL);
1166 
1167  return sepastore->ncutsaddedviapool;
1168 }
1169 
1170 /** gets the number of cutting planes added to the separation storage directly */
1172  SCIP_SEPASTORE* sepastore /**< separation storage */
1173  )
1174 {
1175  assert(sepastore != NULL);
1176 
1177  return sepastore->ncutsaddeddirect;
1178 }
1179 
1180 /** get number of cuts found so far in current separation round */
1182  SCIP_SEPASTORE* sepastore /**< separation storage */
1183  )
1184 {
1185  assert(sepastore != NULL);
1186 
1187  return sepastore->ncutsfoundround;
1188 }
1189 
1190 /** gets the total number of cutting planes applied to the LP */
1192  SCIP_SEPASTORE* sepastore /**< separation storage */
1193  )
1194 {
1195  assert(sepastore != NULL);
1196 
1197  return sepastore->ncutsapplied;
1198 }
internal methods for separators
SCIP_Bool SCIPsetIsInfinity(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6206
static SCIP_RETCODE sepastoreApplyLb(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, SCIP_VAR *var, SCIP_Real bound, SCIP_Bool local, SCIP_Bool *applied, SCIP_Bool *cutoff)
Definition: sepastore.c:575
internal methods for managing events
SCIP_Bool SCIPsetIsLE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6264
SCIP_Bool SCIPsetIsFeasZero(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6714
void * origin
Definition: struct_lp.h:216
#define BMSfreeMemoryArrayNull(ptr)
Definition: memory.h:141
internal methods for branch and bound tree
SCIP_SEPA * SCIProwGetOriginSepa(SCIP_ROW *row)
Definition: lp.c:17442
unsigned int SCIPsetInitializeRandomSeed(SCIP_SET *set, unsigned int initialseedvalue)
Definition: set.c:7400
enum SCIP_Efficiacychoice SCIP_EFFICIACYCHOICE
static SCIP_RETCODE sepastoreApplyBdchg(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, SCIP_ROW *cut, SCIP_Bool *applied, SCIP_Bool *cutoff)
Definition: sepastore.c:757
SCIP_RETCODE SCIPeventqueueAdd(SCIP_EVENTQUEUE *eventqueue, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_PRIMAL *primal, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTFILTER *eventfilter, SCIP_EVENT **event)
Definition: event.c:2231
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17910
enum SCIP_RowOriginType SCIP_ROWORIGINTYPE
Definition: type_lp.h:69
unsigned int origintype
Definition: struct_lp.h:256
SCIP_ROW ** SCIPsepastoreGetCuts(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1130
static long bound
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:17179
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17966
void SCIProwCapture(SCIP_ROW *row)
Definition: lp.c:5334
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:17317
void SCIPsepastoreStartForceCuts(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:147
int SCIPsepastoreGetNCutsApplied(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1191
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:17258
#define FALSE
Definition: def.h:87
methods for the aggregation rows
datastructures for managing events
internal methods for cut selectors
SCIP_Bool SCIPsetIsZero(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6318
#define TRUE
Definition: def.h:86
#define SCIPdebugCheckRow(set, row)
Definition: debug.h:266
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
SCIP_Real SCIProwGetLPEfficacy(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp)
Definition: lp.c:6803
int SCIPsetCalcMemGrowSize(SCIP_SET *set, int num)
Definition: set.c:5785
#define SCIP_UNUSED(x)
Definition: def.h:438
SCIP_Real SCIProwGetNLPEfficacy(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat)
Definition: lp.c:6959
static SCIP_Bool sepastoreIsCutRedundant(SCIP_SEPASTORE *sepastore, SCIP_SET *set, SCIP_STAT *stat, SCIP_ROW *cut)
Definition: sepastore.c:170
int SCIPnodeGetDepth(SCIP_NODE *node)
Definition: tree.c:7444
#define BMSfreeMemory(ptr)
Definition: memory.h:138
void SCIPvarAdjustLb(SCIP_VAR *var, SCIP_SET *set, SCIP_Real *lb)
Definition: var.c:6513
internal methods for LP management
Definition: heur_padm.c:123
int SCIPsetGetSepaMaxcuts(SCIP_SET *set, SCIP_Bool root)
Definition: set.c:5924
void SCIPsepaDecNCutsAdded(SCIP_SEPA *sepa, SCIP_Bool fromcutpool)
Definition: sepa.c:1007
SCIP_ROW ** cuts
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17489
SCIP_Bool SCIPsetIsEfficacious(SCIP_SET *set, SCIP_Bool root, SCIP_Real efficacy)
Definition: set.c:7068
unsigned int fromcutpool
Definition: struct_lp.h:240
SCIP_RETCODE SCIPnodeCutoff(SCIP_NODE *node, SCIP_SET *set, SCIP_STAT *stat, SCIP_TREE *tree, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_REOPT *reopt, SCIP_LP *lp, BMS_BLKMEM *blkmem)
Definition: tree.c:1179
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17920
SCIP_RETCODE SCIPeventCreateRowDeletedSepa(SCIP_EVENT **event, BMS_BLKMEM *blkmem, SCIP_ROW *row)
Definition: event.c:866
SCIP_Bool SCIPsetIsLT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6246
SCIP_Bool SCIPsepastoreIsCutApplicable(SCIP_SET *set, SCIP_ROW *cut)
Definition: sepastore.c:1121
#define SCIP_EVENTTYPE_ROWADDEDSEPA
Definition: type_event.h:99
int SCIPsepastoreGetNCutsAddedViaPool(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1161
static SCIP_RETCODE sepastoreApplyCut(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_LP *lp, SCIP_ROW *cut, int depth, int *ncutsapplied)
Definition: sepastore.c:853
#define SCIPerrorMessage
Definition: pub_message.h:55
SCIP_RETCODE SCIPsepastoreCreate(SCIP_SEPASTORE **sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set)
Definition: sepastore.c:78
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:17367
SCIP_EVENTTYPE eventmask
Definition: struct_event.h:189
SCIP_RETCODE SCIProwChgLocal(SCIP_ROW *row, SCIP_Bool local)
Definition: lp.c:5725
int SCIPsepastoreGetNCuts(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1140
SCIP_RETCODE SCIPsepastoreRemoveInefficaciousCuts(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_LP *lp, SCIP_Bool root, SCIP_EFFICIACYCHOICE efficiacychoice)
Definition: sepastore.c:1064
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17251
SCIP_RETCODE SCIPcutselsSelect(SCIP_SET *set, SCIP_ROW **cuts, int ncuts, int nforcedcuts, SCIP_Bool root, SCIP_Bool initiallp, int maxnselectedcuts, int *nselectedcuts)
Definition: cutsel.c:160
SCIP_RETCODE SCIPlpAddRow(SCIP_LP *lp, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_ROW *row, int depth)
Definition: lp.c:9504
internal miscellaneous methods
#define NULL
Definition: lpi_spx1.cpp:155
void SCIPrandomFree(SCIP_RANDNUMGEN **randnumgen, BMS_BLKMEM *blkmem)
Definition: misc.c:9987
internal methods for global SCIP settings
#define SCIP_CALL(x)
Definition: def.h:384
SCIP_Bool SCIPsetIsFeasGE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6692
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17268
internal methods for storing separated cuts
SCIP_Bool SCIProwIsModifiable(SCIP_ROW *row)
Definition: lp.c:17377
SCIP_Bool SCIPsetIsFeasLE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6648
static SCIP_RETCODE sepastoreDelCut(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_LP *lp, int pos)
Definition: sepastore.c:370
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:17204
SCIP_RETCODE SCIProwRelease(SCIP_ROW **row, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_LP *lp)
Definition: lp.c:5347
data structures and methods for collecting reoptimization information
internal methods for problem variables
void SCIPsepaIncNCutsAdded(SCIP_SEPA *sepa, SCIP_Bool fromcutpool)
Definition: sepa.c:984
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:17214
#define SCIP_Bool
Definition: def.h:84
static SCIP_Bool sepastoreIsCutRedundantOrInfeasible(SCIP_SEPASTORE *sepastore, SCIP_SET *set, SCIP_STAT *stat, SCIP_ROW *cut, SCIP_Bool *infeasible)
Definition: sepastore.c:209
static SCIP_RETCODE sepastoreApplyUb(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, SCIP_VAR *var, SCIP_Real bound, SCIP_Bool local, SCIP_Bool *applied, SCIP_Bool *cutoff)
Definition: sepastore.c:666
#define MAX(x, y)
Definition: tclique_def.h:83
void SCIPconshdlrIncNAppliedCuts(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4874
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8105
methods for debugging
#define SCIPsetDebugMsg
Definition: set.h:1761
#define SCIP_EVENTTYPE_ROWDELETEDSEPA
Definition: type_event.h:100
int SCIPsepastoreGetNCutsAdded(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1151
static SCIP_RETCODE sepastoreEnsureCutsMem(SCIP_SEPASTORE *sepastore, SCIP_SET *set, int num)
Definition: sepastore.c:55
static SCIP_Bool sepastoreIsBdchgApplicable(SCIP_SET *set, SCIP_ROW *cut)
Definition: sepastore.c:266
void SCIPsepastoreEndInitialLP(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:135
SCIP_Real SCIProwGetRelaxEfficacy(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat)
Definition: lp.c:6919
SCIP_Bool SCIPsetIsFeasLT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6626
void SCIPsepastoreStartInitialLP(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:123
SCIP_Real SCIProwGetMaxActivity(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat)
Definition: lp.c:6614
SCIP_Real SCIProwGetConstant(SCIP_ROW *row)
Definition: lp.c:17224
void SCIPsepaIncNCutsApplied(SCIP_SEPA *sepa, SCIP_Bool fromcutpool)
Definition: sepa.c:962
SCIP_Real SCIProwGetMinActivity(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat)
Definition: lp.c:6593
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:17008
SCIP_NODE * SCIPtreeGetRootNode(SCIP_TREE *tree)
Definition: tree.c:8444
SCIP_RETCODE SCIPnodeAddBoundchg(SCIP_NODE *node, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, SCIP_VAR *var, SCIP_Real newbound, SCIP_BOUNDTYPE boundtype, SCIP_Bool probingchange)
Definition: tree.c:2078
int SCIPsepastoreGetNCutsAddedDirect(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1171
SCIP_NODE * SCIPtreeGetCurrentNode(SCIP_TREE *tree)
Definition: tree.c:8377
SCIP_RETCODE SCIPsepastoreApplyCuts(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_CLIQUETABLE *cliquetable, SCIP_Bool root, SCIP_EFFICIACYCHOICE efficiacychoice, SCIP_Bool *cutoff)
Definition: sepastore.c:912
SCIP_Bool SCIPsetIsGT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6282
#define SCIP_Real
Definition: def.h:177
internal methods for problem statistics
SCIP_Bool SCIPsetIsFeasPositive(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6725
int SCIPsepastoreGetNCutsFoundRound(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1181
SCIP_RETCODE SCIPrandomCreate(SCIP_RANDNUMGEN **randnumgen, BMS_BLKMEM *blkmem, unsigned int initialseed)
Definition: misc.c:9971
#define BMSallocMemory(ptr)
Definition: memory.h:111
#define BMSreallocMemoryArray(ptr, num)
Definition: memory.h:120
internal methods for constraints and constraint handlers
SCIP_Bool SCIPsetIsFeasGT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6670
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17976
void SCIPvarAdjustUb(SCIP_VAR *var, SCIP_SET *set, SCIP_Real *ub)
Definition: var.c:6530
SCIP_Bool initiallp
datastructures for storing conflicts
common defines and data types used in all packages of SCIP
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:430
SCIP_RETCODE SCIPsepastoreClearCuts(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_LP *lp)
Definition: sepastore.c:1018
#define SCIP_ALLOC(x)
Definition: def.h:395
SCIP_Bool forcecuts
void SCIPsepastoreEndForceCuts(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:158
SCIP_RETCODE SCIPsepastoreFree(SCIP_SEPASTORE **sepastore, BMS_BLKMEM *blkmem)
Definition: sepastore.c:106
SCIP_RETCODE SCIPsepastoreAddCut(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_LP *lp, SCIP_ROW *cut, SCIP_Bool forcecut, SCIP_Bool root, SCIP_Bool *infeasible)
Definition: sepastore.c:419
SCIP callable library.
SCIP_Bool SCIPsetIsFeasNegative(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6736
SCIP_RETCODE SCIPeventCreateRowAddedSepa(SCIP_EVENT **event, BMS_BLKMEM *blkmem, SCIP_ROW *row)
Definition: event.c:847