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-2018 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 email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file sepastore.c
17  * @brief methods for storing separated cuts
18  * @author Tobias Achterberg
19  * @author Marc Pfetsch
20  */
21 
22 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
23 
24 #include <assert.h>
25 
26 #include "scip/def.h"
27 #include "scip/set.h"
28 #include "scip/stat.h"
29 #include "scip/lp.h"
30 #include "scip/var.h"
31 #include "scip/tree.h"
32 #include "scip/reopt.h"
33 #include "scip/sepastore.h"
34 #include "scip/event.h"
35 #include "scip/sepa.h"
36 #include "scip/cons.h"
37 #include "scip/debug.h"
38 
39 #include "scip/struct_sepastore.h"
40 
41 
42 
43 /*
44  * dynamic memory arrays
45  */
46 
47 /** resizes cuts and score arrays to be able to store at least num entries */
48 static
50  SCIP_SEPASTORE* sepastore, /**< separation storage */
51  SCIP_SET* set, /**< global SCIP settings */
52  int num /**< minimal number of slots in array */
53  )
54 {
55  assert(sepastore != NULL);
56  assert(set != NULL);
57 
58  if( num > sepastore->cutssize )
59  {
60  int newsize;
61 
62  newsize = SCIPsetCalcMemGrowSize(set, num);
63  SCIP_ALLOC( BMSreallocMemoryArray(&sepastore->cuts, newsize) );
64  SCIP_ALLOC( BMSreallocMemoryArray(&sepastore->scores, newsize) );
65  sepastore->cutssize = newsize;
66  }
67  assert(num <= sepastore->cutssize);
68 
69  return SCIP_OKAY;
70 }
71 
72 
73 
74 
75 /** creates separation storage */
77  SCIP_SEPASTORE** sepastore /**< pointer to store separation storage */
78  )
79 {
80  assert(sepastore != NULL);
81 
82  SCIP_ALLOC( BMSallocMemory(sepastore) );
83 
84  (*sepastore)->cuts = NULL;
85  (*sepastore)->scores = NULL;
86  (*sepastore)->cutssize = 0;
87  (*sepastore)->ncuts = 0;
88  (*sepastore)->nforcedcuts = 0;
89  (*sepastore)->ncutsfound = 0;
90  (*sepastore)->ncutsfoundround = 0;
91  (*sepastore)->ncutsapplied = 0;
92  (*sepastore)->initiallp = FALSE;
93  (*sepastore)->forcecuts = FALSE;
94 
95  return SCIP_OKAY;
96 }
97 
98 /** frees separation storage */
100  SCIP_SEPASTORE** sepastore /**< pointer to store separation storage */
101  )
102 {
103  assert(sepastore != NULL);
104  assert(*sepastore != NULL);
105  assert((*sepastore)->ncuts == 0);
106 
107  BMSfreeMemoryArrayNull(&(*sepastore)->cuts);
108  BMSfreeMemoryArrayNull(&(*sepastore)->scores);
109  BMSfreeMemory(sepastore);
110 
111  return SCIP_OKAY;
112 }
113 
114 /** informs separation storage, that the setup of the initial LP starts now */
116  SCIP_SEPASTORE* sepastore /**< separation storage */
117  )
118 {
119  assert(sepastore != NULL);
120  assert(!sepastore->initiallp);
121  assert(sepastore->ncuts == 0);
122 
123  sepastore->initiallp = TRUE;
124 }
125 
126 /** informs separation storage, that the setup of the initial LP is now finished */
128  SCIP_SEPASTORE* sepastore /**< separation storage */
129  )
130 {
131  assert(sepastore != NULL);
132  assert(sepastore->initiallp);
133  assert(sepastore->ncuts == 0);
134 
135  sepastore->initiallp = FALSE;
136 }
137 
138 /** informs separation storage, that the following cuts should be used in any case */
140  SCIP_SEPASTORE* sepastore /**< separation storage */
141  )
142 {
143  assert(sepastore != NULL);
144  assert(!sepastore->forcecuts);
145 
146  sepastore->forcecuts = TRUE;
147 }
148 
149 /** informs separation storage, that the following cuts should no longer be used in any case */
151  SCIP_SEPASTORE* sepastore /**< separation storage */
152  )
153 {
154  assert(sepastore != NULL);
155  assert(sepastore->forcecuts);
156 
157  sepastore->forcecuts = FALSE;
158 }
159 
160 /** checks cut for redundancy due to activity bounds */
161 static
163  SCIP_SEPASTORE* sepastore, /**< separation storage */
164  SCIP_SET* set, /**< global SCIP settings */
165  SCIP_STAT* stat, /**< problem statistics data */
166  SCIP_ROW* cut /**< separated cut */
167  )
168 {
169  SCIP_Real minactivity;
170  SCIP_Real maxactivity;
171  SCIP_Real lhs;
172  SCIP_Real rhs;
173 
174  assert(sepastore != NULL);
175  assert(cut != NULL);
176 
177  /* modifiable cuts cannot be declared redundant, since we don't know all coefficients */
178  if( SCIProwIsModifiable(cut) )
179  return FALSE;
180 
181  /* check for activity redundancy */
182  lhs = SCIProwGetLhs(cut);
183  rhs = SCIProwGetRhs(cut);
184  minactivity = SCIProwGetMinActivity(cut, set, stat);
185  maxactivity = SCIProwGetMaxActivity(cut, set, stat);
186  if( (SCIPsetIsInfinity(set, -lhs) || SCIPsetIsLE(set, lhs, minactivity))
187  && (SCIPsetIsInfinity(set, rhs) || SCIPsetIsLE(set, maxactivity, rhs)) )
188  {
189  SCIPsetDebugMsg(set, "ignoring activity redundant cut <%s> (sides=[%g,%g], act=[%g,%g])\n",
190  SCIProwGetName(cut), lhs, rhs, minactivity, maxactivity);
191  /*SCIPdebug(SCIProwPrint(cut, set->scip->messagehdlr, NULL));*/
192  return TRUE;
193  }
194 
195  return FALSE;
196 }
197 
198 /** checks cut for redundancy or infeasibility due to activity bounds */
199 static
201  SCIP_SEPASTORE* sepastore, /**< separation storage */
202  SCIP_SET* set, /**< global SCIP settings */
203  SCIP_STAT* stat, /**< problem statistics data */
204  SCIP_ROW* cut, /**< separated cut */
205  SCIP_Bool* infeasible /**< pointer to store whether the cut has been detected to be infeasible */
206  )
207 {
208  SCIP_Real minactivity;
209  SCIP_Real maxactivity;
210  SCIP_Real lhs;
211  SCIP_Real rhs;
212 
213  assert(sepastore != NULL);
214  assert(cut != NULL);
215  assert(infeasible != NULL);
216 
217  *infeasible = FALSE;
218 
219  /* modifiable cuts cannot be declared redundant or infeasible, since we don't know all coefficients */
220  if( SCIProwIsModifiable(cut) )
221  return FALSE;
222 
223  /* check for activity redundancy */
224  lhs = SCIProwGetLhs(cut);
225  rhs = SCIProwGetRhs(cut);
226  minactivity = SCIProwGetMinActivity(cut, set, stat);
227  maxactivity = SCIProwGetMaxActivity(cut, set, stat);
228  if( (SCIPsetIsInfinity(set, -lhs) || SCIPsetIsLE(set, lhs, minactivity))
229  && (SCIPsetIsInfinity(set, rhs) || SCIPsetIsLE(set, maxactivity, rhs)) )
230  {
231  SCIPsetDebugMsg(set, "ignoring activity redundant cut <%s> (sides=[%g,%g], act=[%g,%g])\n",
232  SCIProwGetName(cut), lhs, rhs, minactivity, maxactivity);
233  /*SCIPdebug(SCIProwPrint(cut, set->scip->messagehdlr, NULL));*/
234  return TRUE;
235  }
236  if( (!SCIPsetIsInfinity(set, rhs) && SCIPsetIsFeasGT(set, minactivity, rhs))
237  || (!SCIPsetIsInfinity(set, -lhs) && SCIPsetIsFeasLT(set, maxactivity, lhs) ))
238  {
239  SCIPsetDebugMsg(set, "cut <%s> is infeasible (sides=[%g,%g], act=[%g,%g])\n",
240  SCIProwGetName(cut), lhs, rhs, minactivity, maxactivity);
241  /*SCIPdebug(SCIProwPrint(cut, set->scip->messagehdlr, NULL));*/
242  *infeasible = TRUE;
243  return TRUE;
244  }
245 
246  return FALSE;
247 }
248 
249 /** checks whether a cut with only one variable can be applied as boundchange
250  *
251  * This is the case if the bound change would prove infeasibility (w.r.t feastol),
252  * or if the new bound is at least epsilon better than the old bound.
253  * In the latter case, also the opposite bound has to be taken into account.
254  */
255 static
257  SCIP_SET* set, /**< global SCIP settings */
258  SCIP_ROW* cut /**< cut with a single variable */
259  )
260 {
261  SCIP_COL** cols;
262  SCIP_Real* vals;
263  SCIP_VAR* var;
264  SCIP_Real lhs;
265  SCIP_Real rhs;
266  SCIP_Bool local;
267  SCIP_Real oldlb;
268  SCIP_Real oldub;
269 
270  assert(set != NULL);
271  assert(!SCIProwIsModifiable(cut));
272  assert(SCIProwGetNNonz(cut) == 1);
273 
274  /* get the single variable and its coefficient of the cut */
275  cols = SCIProwGetCols(cut);
276  assert(cols != NULL);
277 
278  var = SCIPcolGetVar(cols[0]);
279  vals = SCIProwGetVals(cut);
280  assert(vals != NULL);
281  assert(!SCIPsetIsZero(set, vals[0]));
282 
283  /* if the coefficient is nearly zero, we better ignore this cut for numerical reasons */
284  if( SCIPsetIsFeasZero(set, vals[0]) )
285  return FALSE;
286 
287  local = SCIProwIsLocal(cut);
288 
289  oldlb = local ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var);
290  oldub = local ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var);
291 
292  /* get the left hand side of the cut and convert it to a bound */
293  lhs = SCIProwGetLhs(cut);
294  if( !SCIPsetIsInfinity(set, -lhs) )
295  {
296  lhs -= SCIProwGetConstant(cut);
297  if( vals[0] > 0.0 )
298  {
299  /* coefficient is positive -> lhs corresponds to lower bound */
300  SCIP_Real newlb;
301 
302  newlb = lhs/vals[0];
303  SCIPvarAdjustLb(var, set, &newlb);
304 
305  if( SCIPsetIsFeasGT(set, newlb, oldub) || SCIPsetIsGT(set, MIN(newlb, oldub), oldlb) )
306  return TRUE;
307  }
308  else
309  {
310  /* coefficient is negative -> lhs corresponds to upper bound */
311  SCIP_Real newub;
312 
313  newub = lhs/vals[0];
314  SCIPvarAdjustUb(var, set, &newub);
315 
316  if( SCIPsetIsFeasLT(set, newub, oldlb) || SCIPsetIsLT(set, MAX(newub, oldlb), oldub) )
317  return TRUE;
318  }
319  }
320 
321  /* get the right hand side of the cut and convert it to a bound */
322  rhs = SCIProwGetRhs(cut);
323  if( !SCIPsetIsInfinity(set, rhs) )
324  {
325  rhs -= SCIProwGetConstant(cut);
326  if( vals[0] > 0.0 )
327  {
328  /* coefficient is positive -> rhs corresponds to upper bound */
329  SCIP_Real newub;
330 
331  newub = rhs/vals[0];
332  SCIPvarAdjustUb(var, set, &newub);
333 
334  if( SCIPsetIsFeasLT(set, newub, oldlb) || SCIPsetIsLT(set, MAX(newub, oldlb), oldub) )
335  return TRUE;
336  }
337  else
338  {
339  /* coefficient is negative -> rhs corresponds to lower bound */
340  SCIP_Real newlb;
341 
342  newlb = rhs/vals[0];
343  SCIPvarAdjustLb(var, set, &newlb);
344 
345  if( SCIPsetIsFeasGT(set, newlb, oldub) || SCIPsetIsGT(set, MIN(newlb, oldub), oldlb) )
346  return TRUE;
347  }
348  }
349 
350  return FALSE;
351 }
352 
353 /** removes a non-forced cut from the separation storage */
354 static
356  SCIP_SEPASTORE* sepastore, /**< separation storage */
357  BMS_BLKMEM* blkmem, /**< block memory */
358  SCIP_SET* set, /**< global SCIP settings */
359  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
360  SCIP_EVENTFILTER* eventfilter, /**< event filter for global events */
361  SCIP_LP* lp, /**< LP data */
362  int pos /**< position of cut to delete */
363  )
364 {
365  assert(sepastore != NULL);
366  assert(sepastore->cuts != NULL);
367  assert(sepastore->nforcedcuts <= pos && pos < sepastore->ncuts);
368 
369  /* check, if the row deletions from separation storage events are tracked
370  * if so, issue ROWDELETEDSEPA event
371  */
372  if( eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWDELETEDSEPA) != 0 )
373  {
374  SCIP_EVENT* event;
375 
376  SCIP_CALL( SCIPeventCreateRowDeletedSepa(&event, blkmem, sepastore->cuts[pos]) );
377  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) );
378  }
379 
380  /* release the row */
381  SCIP_CALL( SCIProwRelease(&sepastore->cuts[pos], blkmem, set, lp) );
382 
383  /* move last cut to the empty position */
384  sepastore->cuts[pos] = sepastore->cuts[sepastore->ncuts-1];
385  sepastore->scores[pos] = sepastore->scores[sepastore->ncuts-1];
386  sepastore->ncuts--;
387 
388  return SCIP_OKAY;
389 }
390 
391 /** adds cut to separation storage and captures it;
392  * if the cut should be forced to enter the LP, an infinite score has to be used
393  */
395  SCIP_SEPASTORE* sepastore, /**< separation storage */
396  BMS_BLKMEM* blkmem, /**< block memory */
397  SCIP_SET* set, /**< global SCIP settings */
398  SCIP_STAT* stat, /**< problem statistics data */
399  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
400  SCIP_EVENTFILTER* eventfilter, /**< event filter for global events */
401  SCIP_LP* lp, /**< LP data */
402  SCIP_ROW* cut, /**< separated cut */
403  SCIP_Bool forcecut, /**< should the cut be forced to enter the LP? */
404  SCIP_Bool root, /**< are we at the root node? */
405  SCIP_Bool* infeasible /**< pointer to store whether the cut is infeasible */
406  )
407 {
408  SCIP_Real cutscore;
409  SCIP_Bool redundant;
410  int pos;
411 
412  assert(sepastore != NULL);
413  assert(sepastore->nforcedcuts <= sepastore->ncuts);
414  assert(set != NULL);
415  assert(cut != NULL);
416  assert(!SCIPsetIsInfinity(set, -SCIProwGetLhs(cut)) || !SCIPsetIsInfinity(set, SCIProwGetRhs(cut)));
417  assert(eventqueue != NULL);
418  assert(eventfilter != NULL);
419 
420  /* debug: check cut for feasibility */
421  SCIP_CALL( SCIPdebugCheckRow(set, cut) ); /*lint !e506 !e774*/
422 
423  /* update statistics of total number of found cuts */
424  if( !sepastore->initiallp )
425  {
426  sepastore->ncutsfound++;
427  sepastore->ncutsfoundround++;
428  }
429 
430  /* in the root node, every local cut is a global cut, and global cuts are nicer in many ways...*/
431  if( root && SCIProwIsLocal(cut) )
432  {
433  SCIPsetDebugMsg(set, "change local flag of cut <%s> to FALSE due to addition in root node\n", SCIProwGetName(cut));
434 
436 
437  assert(!SCIProwIsLocal(cut));
438  }
439 
440  /* check cut for redundancy or infeasibility */
441  redundant = sepastoreIsCutRedundantOrInfeasible(sepastore, set, stat, cut, infeasible);
442  /* Note that we add infeasible rows in any case, since we cannot be sure whether the return values are handled
443  * correctly. In this way, the LP becomes infeasible. */
444 
445  /* in each separation round, make sure that at least one (even redundant) cut enters the LP to avoid cycling */
446  if( !forcecut && sepastore->ncuts > 0 && redundant )
447  return SCIP_OKAY;
448 
449  /* if only one cut is currently present in the cut store, it could be redundant; in this case, it can now be removed
450  * again, because now a non redundant cut enters the store
451  */
452  if( sepastore->ncuts == 1 && sepastoreIsCutRedundant(sepastore, set, stat, sepastore->cuts[0]) )
453  {
454  /* check, if the row deletions from separation storage events are tracked if so, issue ROWDELETEDSEPA event */
455  if( eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWDELETEDSEPA) != 0 )
456  {
457  SCIP_EVENT* event;
458 
459  SCIP_CALL( SCIPeventCreateRowDeletedSepa(&event, blkmem, sepastore->cuts[0]) );
460  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) );
461  }
462 
463  SCIP_CALL( SCIProwRelease(&sepastore->cuts[0], blkmem, set, lp) );
464  sepastore->ncuts = 0;
465  sepastore->nforcedcuts = 0;
466  }
467 
468  /* a cut is forced to enter the LP if
469  * - we construct the initial LP, or
470  * - it has infinite score factor, or
471  * - it is a bound change that can be applied
472  * if it is a non-forced cut and no cuts should be added, abort
473  */
474  forcecut = forcecut || sepastore->initiallp || sepastore->forcecuts || (!SCIProwIsModifiable(cut) && SCIProwGetNNonz(cut) == 1 && sepastoreIsBdchgApplicable(set, cut));
475  if( !forcecut && SCIPsetGetSepaMaxcuts(set, root) == 0 )
476  return SCIP_OKAY;
477 
478  /* get enough memory to store the cut */
479  SCIP_CALL( sepastoreEnsureCutsMem(sepastore, set, sepastore->ncuts+1) );
480  assert(sepastore->ncuts < sepastore->cutssize);
481 
482  if( forcecut )
483  {
484  cutscore = SCIPsetInfinity(set);
485  }
486  else
487  {
488  /* initialize values to invalid (will be initialized during cut filtering) */
489  cutscore = SCIP_INVALID;
490  }
491 
492  SCIPsetDebugMsg(set, "adding cut <%s> to separation storage of size %d (forcecut=%u, len=%d)\n",
493  SCIProwGetName(cut), sepastore->ncuts, forcecut, SCIProwGetNNonz(cut));
494  /*SCIP_CALL( SCIPprintRow(set->scip, cut, NULL) );*/
495 
496  /* capture the cut */
497  SCIProwCapture(cut);
498 
499  /* add cut to arrays */
500  if( forcecut )
501  {
502  /* make room at the beginning of the array for forced cut */
503  pos = sepastore->nforcedcuts;
504  sepastore->cuts[sepastore->ncuts] = sepastore->cuts[pos];
505  sepastore->scores[sepastore->ncuts] = sepastore->scores[pos];
506  sepastore->nforcedcuts++;
507  }
508  else
509  pos = sepastore->ncuts;
510 
511  sepastore->cuts[pos] = cut;
512  sepastore->scores[pos] = cutscore;
513  sepastore->ncuts++;
514 
515  /* check, if the row addition to separation storage events are tracked
516  * if so, issue ROWADDEDSEPA event
517  */
518  if( eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWADDEDSEPA) != 0 )
519  {
520  SCIP_EVENT* event;
521 
522  SCIP_CALL( SCIPeventCreateRowAddedSepa(&event, blkmem, cut) );
523  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) );
524  }
525 
526  return SCIP_OKAY;
527 }
528 
529 /** applies a lower bound change */
530 static
532  SCIP_SEPASTORE* sepastore, /**< separation storage */
533  BMS_BLKMEM* blkmem, /**< block memory */
534  SCIP_SET* set, /**< global SCIP settings */
535  SCIP_STAT* stat, /**< problem statistics */
536  SCIP_PROB* transprob, /**< transformed problem */
537  SCIP_PROB* origprob, /**< original problem */
538  SCIP_TREE* tree, /**< branch and bound tree */
539  SCIP_REOPT* reopt, /**< reoptimization data structure */
540  SCIP_LP* lp, /**< LP data */
541  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
542  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
543  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
544  SCIP_VAR* var, /**< problem variable */
545  SCIP_Real bound, /**< new lower bound of variable */
546  SCIP_Bool local, /**< is it a local bound change? (otherwise global) */
547  SCIP_Bool* applied, /**< pointer to store whether the domain change was applied */
548  SCIP_Bool* cutoff /**< pointer to store TRUE, if an infeasibility has been detected */
549  )
550 {
551  assert(sepastore != NULL);
552  assert(cutoff != NULL);
553  assert(applied != NULL);
554 
555  /* adjust bound to the one that would be applied, so the SCIPsetIsGT check below is more reliable */
556  SCIPvarAdjustLb(var, set, &bound);
557 
558  if( local )
559  {
560  /* apply the local bound change or detect a cutoff */
561  if( SCIPsetIsGT(set, bound, SCIPvarGetLbLocal(var)) )
562  {
563  SCIPsetDebugMsg(set, " -> applying bound change: <%s>: [%.20g,%.20g] -> [%.20g,%.20g]\n",
565 
566  if( SCIPsetIsFeasLE(set, bound, SCIPvarGetUbLocal(var)) )
567  {
568  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetCurrentNode(tree), blkmem, set, stat, transprob, origprob, tree,
569  reopt, lp, branchcand, eventqueue, cliquetable, var, bound, SCIP_BOUNDTYPE_LOWER, FALSE) );
570  }
571  else
572  *cutoff = TRUE;
573 
574  *applied = TRUE;
575  }
576  else
577  {
578  SCIPsetDebugMsg(set, " -> ignoring bound change: <%s>: [%.20g,%.20g] -> [%.20g,%.20g]\n",
580  }
581  }
582  else
583  {
584  /* apply the global bound change or detect a global cutoff which means we can cutoff the root node */
585  if( SCIPsetIsGT(set, bound, SCIPvarGetLbGlobal(var)) )
586  {
587  SCIPsetDebugMsg(set, " -> applying global bound change: <%s>: [%.20g,%.20g] -> [%.20g,%.20g]\n",
589 
590  if( SCIPsetIsFeasLE(set, bound, SCIPvarGetUbGlobal(var)) )
591  {
592  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, tree, reopt,
593  lp, branchcand, eventqueue, cliquetable, var, bound, SCIP_BOUNDTYPE_LOWER, FALSE) );
594  }
595  else
596  {
597  /* we are done with solving since a global bound change is infeasible */
598  SCIP_CALL( SCIPnodeCutoff(SCIPtreeGetRootNode(tree), set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
599  *cutoff = TRUE;
600  }
601 
602  *applied = TRUE;
603  }
604  else
605  {
606  SCIPsetDebugMsg(set, " -> ignoring global bound change: <%s>: [%.20g,%.20g] -> [%.20g,%.20g]\n",
608  }
609  }
610 
611  return SCIP_OKAY;
612 }
613 
614 /** applies an upper bound change */
615 static
617  SCIP_SEPASTORE* sepastore, /**< separation storage */
618  BMS_BLKMEM* blkmem, /**< block memory */
619  SCIP_SET* set, /**< global SCIP settings */
620  SCIP_STAT* stat, /**< problem statistics */
621  SCIP_PROB* transprob, /**< transformed problem */
622  SCIP_PROB* origprob, /**< original problem */
623  SCIP_TREE* tree, /**< branch and bound tree */
624  SCIP_REOPT* reopt, /**< reoptimization data structure */
625  SCIP_LP* lp, /**< LP data */
626  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
627  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
628  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
629  SCIP_VAR* var, /**< problem variable */
630  SCIP_Real bound, /**< new upper bound of variable */
631  SCIP_Bool local, /**< is it a local bound change? (otherwise global) */
632  SCIP_Bool* applied, /**< pointer to store whether the domain change was applied */
633  SCIP_Bool* cutoff /**< pointer to store TRUE, if an infeasibility has been detected */
634  )
635 {
636  assert(sepastore != NULL);
637  assert(cutoff != NULL);
638  assert(applied != NULL);
639 
640  /* adjust bound to the one that would be applied, so the SCIPsetIsGT check below is more reliable */
641  SCIPvarAdjustUb(var, set, &bound);
642 
643  if( local )
644  {
645  /* apply the local bound change or detect a cutoff */
646  if( SCIPsetIsLT(set, bound, SCIPvarGetUbLocal(var)) )
647  {
648  SCIPsetDebugMsg(set, " -> applying bound change: <%s>: [%.20g,%.20g] -> [%.20g,%.20g]\n",
650 
651  if( SCIPsetIsFeasGE(set, bound, SCIPvarGetLbLocal(var)) )
652  {
653  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetCurrentNode(tree), blkmem, set, stat, transprob, origprob, tree,
654  reopt, lp, branchcand, eventqueue, cliquetable, var, bound, SCIP_BOUNDTYPE_UPPER, FALSE) );
655  }
656  else
657  *cutoff = TRUE;
658 
659  *applied = TRUE;
660  }
661  else
662  {
663  SCIPsetDebugMsg(set, " -> ignoring bound change: <%s>: [%.20g,%.20g] -> [%.20g,%.20g]\n",
665  }
666  }
667  else
668  {
669  /* apply the global bound change or detect a global cutoff which means we can cutoff the root node */
670  if( SCIPsetIsLT(set, bound, SCIPvarGetUbGlobal(var)) )
671  {
672  SCIPsetDebugMsg(set, " -> applying global bound change: <%s>: [%.20g,%.20g] -> [%.20g,%.20g]\n",
674 
675  if( SCIPsetIsFeasGE(set, bound, SCIPvarGetLbGlobal(var)) )
676  {
677  SCIP_CALL( SCIPnodeAddBoundchg(SCIPtreeGetRootNode(tree), blkmem, set, stat, transprob, origprob, tree, reopt,
678  lp, branchcand, eventqueue, cliquetable, var, bound, SCIP_BOUNDTYPE_UPPER, FALSE) );
679  }
680  else
681  {
682  /* we are done with solving since a global bound change is infeasible */
683  SCIP_CALL( SCIPnodeCutoff(SCIPtreeGetRootNode(tree), set, stat, tree, transprob, origprob, reopt, lp, blkmem) );
684  *cutoff = TRUE;
685  }
686 
687  *applied = TRUE;
688  }
689  else
690  {
691  SCIPsetDebugMsg(set, " -> ignoring global bound change: <%s>: [%.20g,%.20g] -> [%.20g,%.20g]\n",
693  }
694  }
695 
696  return SCIP_OKAY;
697 }
698 
699 /** applies a cut that is a bound change directly as bound change instead of adding it as row to the LP */
700 static
702  SCIP_SEPASTORE* sepastore, /**< separation storage */
703  BMS_BLKMEM* blkmem, /**< block memory */
704  SCIP_SET* set, /**< global SCIP settings */
705  SCIP_STAT* stat, /**< problem statistics */
706  SCIP_PROB* transprob, /**< transformed problem */
707  SCIP_PROB* origprob, /**< original problem */
708  SCIP_TREE* tree, /**< branch and bound tree */
709  SCIP_REOPT* reopt, /**< reoptimization data structure */
710  SCIP_LP* lp, /**< LP data */
711  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
712  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
713  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
714  SCIP_ROW* cut, /**< cut with a single variable */
715  SCIP_Bool* applied, /**< pointer to store whether the domain change was applied */
716  SCIP_Bool* cutoff /**< pointer to store whether an empty domain was created */
717  )
718 {
719  SCIP_COL** cols;
720  SCIP_Real* vals;
721  SCIP_VAR* var;
722  SCIP_Real lhs;
723  SCIP_Real rhs;
724  SCIP_Bool local;
725 
726  assert(sepastore != NULL);
727  assert(!SCIProwIsModifiable(cut));
728  assert(SCIProwGetNNonz(cut) == 1);
729  assert(cutoff != NULL);
730  assert(applied != NULL);
731 
732  *applied = FALSE;
733  *cutoff = FALSE;
734 
735  /* get the single variable and its coefficient of the cut */
736  cols = SCIProwGetCols(cut);
737  assert(cols != NULL);
738 
739  var = SCIPcolGetVar(cols[0]);
740  vals = SCIProwGetVals(cut);
741  assert(vals != NULL);
742  assert(!SCIPsetIsZero(set, vals[0]));
743 
744  /* if the coefficient is nearly zero, we better ignore this cut for numerical reasons */
745  if( SCIPsetIsFeasZero(set, vals[0]) )
746  return SCIP_OKAY;
747 
748  local = SCIProwIsLocal(cut);
749 
750  /* get the left hand side of the cut and convert it to a bound */
751  lhs = SCIProwGetLhs(cut);
752  if( !SCIPsetIsInfinity(set, -lhs) )
753  {
754  lhs -= SCIProwGetConstant(cut);
755  if( vals[0] > 0.0 )
756  {
757  /* coefficient is positive -> lhs corresponds to lower bound */
758  SCIP_CALL( sepastoreApplyLb(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
759  cliquetable, var, lhs/vals[0], local, applied, cutoff) );
760  }
761  else
762  {
763  /* coefficient is negative -> lhs corresponds to upper bound */
764  SCIP_CALL( sepastoreApplyUb(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
765  cliquetable, var, lhs/vals[0], local, applied, cutoff) );
766  }
767  }
768 
769  /* get the right hand side of the cut and convert it to a bound */
770  rhs = SCIProwGetRhs(cut);
771  if( !SCIPsetIsInfinity(set, rhs) )
772  {
773  rhs -= SCIProwGetConstant(cut);
774  if( vals[0] > 0.0 )
775  {
776  /* coefficient is positive -> rhs corresponds to upper bound */
777  SCIP_CALL( sepastoreApplyUb(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
778  cliquetable, var, rhs/vals[0], local, applied, cutoff) );
779  }
780  else
781  {
782  /* coefficient is negative -> rhs corresponds to lower bound */
783  SCIP_CALL( sepastoreApplyLb(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
784  cliquetable, var, rhs/vals[0], local, applied, cutoff) );
785  }
786  }
787 
788  /* count the bound change as applied cut */
789  if( *applied && !sepastore->initiallp )
790  sepastore->ncutsapplied++;
791 
792  return SCIP_OKAY;
793 }
794 
795 /** updates the orthogonalities and scores of the non-forced cuts after the given cut was added to the LP */
796 static
798  SCIP_SEPASTORE* sepastore, /**< separation storage */
799  BMS_BLKMEM* blkmem, /**< block memory */
800  SCIP_SET* set, /**< global SCIP settings */
801  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
802  SCIP_EVENTFILTER* eventfilter, /**< event filter for global events */
803  SCIP_LP* lp, /**< LP data */
804  SCIP_ROW* cut, /**< cut that was applied */
805  SCIP_Real mincutorthogonality,/**< minimal orthogonality of cuts to apply to LP */
806  SCIP_Real bestscore /**< best score in this round */
807  )
808 {
809  int pos;
810 
811  assert(sepastore != NULL);
812 
813  pos = sepastore->nforcedcuts;
814  while( pos < sepastore->ncuts )
815  {
816  SCIP_Real thisortho;
817 
818  /* update orthogonality */
819  thisortho = SCIProwGetOrthogonality(cut, sepastore->cuts[pos], set->sepa_orthofunc);
820 
821  if( thisortho < MIN(mincutorthogonality, 0.5) || (thisortho < mincutorthogonality && sepastore->scores[pos] < 0.9 * bestscore) )
822  {
823  /* cut is too parallel: release the row and delete the cut */
824  SCIPsetDebugMsg(set, " -> deleting parallel cut <%s> after adding <%s> (pos=%d, len=%d, orthogonality=%g, score=%g)\n",
825  SCIProwGetName(sepastore->cuts[pos]), SCIProwGetName(cut), pos, SCIProwGetNNonz(cut), thisortho, sepastore->scores[pos]);
826  SCIP_CALL( sepastoreDelCut(sepastore, blkmem, set, eventqueue, eventfilter, lp, pos) );
827  continue;
828  }
829 
830  pos++;
831  }
832 
833  return SCIP_OKAY;
834 }
835 
836 /** applies the given cut to the LP and updates the orthogonalities and scores of remaining cuts */
837 static
839  SCIP_SEPASTORE* sepastore, /**< separation storage */
840  BMS_BLKMEM* blkmem, /**< block memory */
841  SCIP_SET* set, /**< global SCIP settings */
842  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
843  SCIP_EVENTFILTER* eventfilter, /**< global event filter */
844  SCIP_LP* lp, /**< LP data */
845  SCIP_ROW* cut, /**< cut to apply to the LP */
846  SCIP_Real mincutorthogonality,/**< minimal orthogonality of cuts to apply to LP */
847  SCIP_Real bestscore, /**< best score in this round */
848  int depth, /**< depth of current node */
849  int* ncutsapplied /**< pointer to count the number of applied cuts */
850  )
851 {
852  assert(sepastore != NULL);
853  assert(ncutsapplied != NULL);
854 
855  /* a row could have been added twice to the separation store; add it only once! */
856  if( !SCIProwIsInLP(cut) )
857  {
858  /* add cut to the LP and capture it */
859  SCIP_CALL( SCIPlpAddRow(lp, blkmem, set, eventqueue, eventfilter, cut, depth) );
860 
861  /* update statistics -> only if we are not in the initial lp (cuts are only counted if added during run) */
862  if( !sepastore->initiallp )
863  {
864  sepastore->ncutsapplied++;
865 
866  /* increase count of applied cuts for origins of row */
867  switch ( cut->origintype )
868  {
870  assert( cut->origin != NULL );
872  break;
874  assert( cut->origin != NULL );
876  break;
879  /* do nothing - cannot update statistics */
880  break;
881  default:
882  SCIPerrorMessage("unkown type of row origin.\n");
883  return SCIP_INVALIDDATA;
884  }
885  }
886 
887  /* update the orthogonalities */
888  SCIP_CALL( sepastoreUpdateOrthogonalities(sepastore, blkmem, set, eventqueue, eventfilter, lp, cut, mincutorthogonality, bestscore) );
889  (*ncutsapplied)++;
890  }
891 
892  return SCIP_OKAY;
893 }
894 
895 /** returns the position of the best non-forced cut in the cuts array */
896 static
898  SCIP_SEPASTORE* sepastore /**< separation storage */
899  )
900 {
901  SCIP_Real bestscore;
902  int bestpos;
903  int pos;
904 
905  assert(sepastore != NULL);
906  assert(sepastore->nforcedcuts < sepastore->ncuts);
907 
908  bestpos = sepastore->nforcedcuts;
909  bestscore = sepastore->scores[bestpos];
910  assert( bestscore != SCIP_INVALID ); /*lint !e777*/
911  for( pos = sepastore->nforcedcuts + 1; pos < sepastore->ncuts; pos++ )
912  {
913  /* check if cut is current best cut */
914  assert( sepastore->scores[pos] != SCIP_INVALID ); /*lint !e777*/
915  if( sepastore->scores[pos] > bestscore )
916  {
917  bestscore = sepastore->scores[pos];
918  bestpos = pos;
919  }
920  }
921 
922  return bestpos;
923 }
924 
925 /** computes score for current LP solution and initialized orthogonalities */
926 static
928  SCIP_SEPASTORE* sepastore, /**< separation storage */
929  SCIP_SET* set, /**< global SCIP settings */
930  SCIP_STAT* stat, /**< problem statistics */
931  SCIP_LP* lp, /**< LP data */
932  SCIP_Bool handlepool, /**< whether the efficacy of cuts in the pool should be reduced */
933  int pos, /**< position of cut to handle */
934  SCIP_EFFICIACYCHOICE efficiacychoice, /**< type of solution to base efficiacy computation on */
935  SCIP_Real* bestscore /**< pointer to update best score */
936  )
937 {
938  SCIP_ROW* cut;
939  SCIP_Real cutefficacy;
940  SCIP_Real cutscore;
941 
942  cut = sepastore->cuts[pos];
943 
944  /* calculate cut's efficacy */
945  switch ( efficiacychoice )
946  {
948  cutefficacy = SCIProwGetLPEfficacy(cut, set, stat, lp);
949  break;
951  cutefficacy = SCIProwGetRelaxEfficacy(cut, set, stat);
952  break;
954  cutefficacy = SCIProwGetNLPEfficacy(cut, set, stat);
955  break;
956  default:
957  SCIPerrorMessage("Invalid efficiacy choice.\n");
958  return SCIP_INVALIDCALL;
959  }
960 
961  /* If a cut is not member of the cut pool, we slightly decrease its score to prefer identical
962  * cuts which are in the cut pool. This is because the conversion of cuts into linear
963  * constraints after a restart looks at the cut pool and cannot find tight non-pool cuts.
964  */
965 
966  /* calculate resulting score */
967  cutscore = cutefficacy + set->sepa_objparalfac * SCIProwGetObjParallelism(cut, set, lp)
968  + set->sepa_intsupportfac * SCIProwGetNumIntCols(cut, set) / (SCIP_Real) SCIProwGetNNonz(cut)
969  + 1e-4 * (handlepool && !SCIProwIsInGlobalCutpool(cut)); /*lint !e514*/
970  assert( !SCIPsetIsInfinity(set, cutscore) );
971  sepastore->scores[pos] = cutscore;
972  *bestscore = MAX(*bestscore, cutscore);
973 
974  return SCIP_OKAY;
975 }
976 
977 /** adds cuts to the LP and clears separation storage */
979  SCIP_SEPASTORE* sepastore, /**< separation storage */
980  BMS_BLKMEM* blkmem, /**< block memory */
981  SCIP_SET* set, /**< global SCIP settings */
982  SCIP_STAT* stat, /**< problem statistics */
983  SCIP_PROB* transprob, /**< transformed problem */
984  SCIP_PROB* origprob, /**< original problem */
985  SCIP_TREE* tree, /**< branch and bound tree */
986  SCIP_REOPT* reopt, /**< reoptimization data structure */
987  SCIP_LP* lp, /**< LP data */
988  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
989  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
990  SCIP_EVENTFILTER* eventfilter, /**< global event filter */
991  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
992  SCIP_Bool root, /**< are we at the root node? */
993  SCIP_EFFICIACYCHOICE efficiacychoice, /**< type of solution to base efficiacy computation on */
994  SCIP_Bool* cutoff /**< pointer to store whether an empty domain was created */
995  )
996 {
997  SCIP_NODE* node;
998  SCIP_Real mincutorthogonality;
999  SCIP_Real bestscore;
1000  SCIP_Bool applied;
1001  int depth;
1002  int maxsepacuts;
1003  int ncutsapplied;
1004  int pos;
1005 
1006  assert(sepastore != NULL);
1007  assert(set != NULL);
1008  assert(tree != NULL);
1009  assert(lp != NULL);
1010  assert(cutoff != NULL);
1011 
1012  *cutoff = FALSE;
1013 
1014  SCIPsetDebugMsg(set, "applying %d cuts\n", sepastore->ncuts);
1015 
1016  node = SCIPtreeGetCurrentNode(tree);
1017  assert(node != NULL);
1018 
1019  /* get maximal number of cuts to add to the LP */
1020  maxsepacuts = SCIPsetGetSepaMaxcuts(set, root);
1021  ncutsapplied = 0;
1022 
1023  /* get depth of current node */
1024  depth = SCIPnodeGetDepth(node);
1025 
1026  /* calculate minimal cut orthogonality */
1027  mincutorthogonality = root ? set->sepa_minorthoroot : set->sepa_minortho;
1028  mincutorthogonality = MAX(mincutorthogonality, set->num_epsilon);
1029 
1030  bestscore = 0.0;
1031 
1032  /* Compute scores for all non-forced cuts and initialize orthogonalities - make sure all cuts are initialized again for the current LP solution */
1033  for( pos = sepastore->nforcedcuts; pos < sepastore->ncuts; pos++ )
1034  {
1035  SCIP_CALL( computeScore(sepastore, set, stat, lp, TRUE, pos, efficiacychoice, &bestscore) );
1036  }
1037 
1038  /* apply all forced cuts */
1039  for( pos = 0; pos < sepastore->nforcedcuts && !(*cutoff); pos++ )
1040  {
1041  SCIP_ROW* cut;
1042 
1043  cut = sepastore->cuts[pos];
1044  assert(SCIPsetIsInfinity(set, sepastore->scores[pos]));
1045 
1046  /* if the cut is a bound change (i.e. a row with only one variable), add it as bound change instead of LP row */
1047  applied = FALSE;
1048  if( !SCIProwIsModifiable(cut) && SCIProwGetNNonz(cut) == 1 )
1049  {
1050  SCIPsetDebugMsg(set, " -> applying forced cut <%s> as boundchange\n", SCIProwGetName(cut));
1051  SCIP_CALL( sepastoreApplyBdchg(sepastore, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
1052  eventqueue, cliquetable, cut, &applied, cutoff) );
1053 
1054  assert(applied || !sepastoreIsBdchgApplicable(set, cut));
1055  }
1056 
1057  if( !applied )
1058  {
1059  /* add cut to the LP and update orthogonalities */
1060  SCIPsetDebugMsg(set, " -> applying forced cut <%s>\n", SCIProwGetName(cut));
1061  /*SCIPdebug( SCIProwPrint(cut, set->scip->messagehdlr, NULL));*/
1062  SCIP_CALL( sepastoreApplyCut(sepastore, blkmem, set, eventqueue, eventfilter, lp, cut, mincutorthogonality, bestscore, depth, &ncutsapplied) );
1063  }
1064  }
1065 
1066  /* apply non-forced cuts */
1067  while( ncutsapplied < maxsepacuts && sepastore->ncuts > sepastore->nforcedcuts && !(*cutoff) )
1068  {
1069  SCIP_ROW* cut;
1070  int bestpos;
1071  SCIP_Real efficacy;
1072 
1073  /* get best non-forced cut */
1074  bestpos = sepastoreGetBestCut(sepastore);
1075  assert(sepastore->nforcedcuts <= bestpos && bestpos < sepastore->ncuts);
1076  assert(sepastore->scores[bestpos] != SCIP_INVALID ); /*lint !e777*/
1077  cut = sepastore->cuts[bestpos];
1078  assert(SCIProwIsModifiable(cut) || SCIProwGetNNonz(cut) != 1 || !sepastoreIsBdchgApplicable(set, cut)); /* applicable bound changes are forced cuts */
1079  assert(!SCIPsetIsInfinity(set, sepastore->scores[bestpos]));
1080 
1081  SCIPsetDebugMsg(set, " -> applying cut <%s> (pos=%d/%d, len=%d, LP efficacy=%g, objparallelism=%g, score=%g)\n",
1082  SCIProwGetName(cut), bestpos, sepastore->ncuts, SCIProwGetNNonz(cut), SCIProwGetLPEfficacy(cut, set, stat, lp),
1083  SCIProwGetObjParallelism(cut, set, lp), sepastore->scores[bestpos]);
1084  /*SCIPdebug(SCIProwPrint(cut, set->scip->messagehdlr, NULL));*/
1085 
1086  /* capture cut such that it is not destroyed in sepastoreDelCut() */
1087  SCIProwCapture(cut);
1088 
1089  /* release the row and delete the cut (also issuing ROWDELETEDSEPA event) */
1090  SCIP_CALL( sepastoreDelCut(sepastore, blkmem, set, eventqueue, eventfilter, lp, bestpos) );
1091 
1092  efficacy = SCIProwGetLPEfficacy(cut, set, stat, lp);
1093  /* Do not add (non-forced) non-violated cuts.
1094  * Note: do not take SCIPsetIsEfficacious(), because constraint handlers often add cuts w.r.t. SCIPsetIsFeasPositive().
1095  * Note2: if separating/feastolfac != -1, constraint handlers may even add cuts w.r.t. SCIPsetIsPositive(); those are currently rejected here
1096  */
1097  if( SCIPsetIsFeasPositive(set, efficacy) )
1098  {
1099  /* add cut to the LP and update orthogonalities */
1100  SCIP_CALL( sepastoreApplyCut(sepastore, blkmem, set, eventqueue, eventfilter, lp, cut, mincutorthogonality, bestscore, depth, &ncutsapplied) );
1101  }
1102 
1103  /* release cut */
1104  SCIP_CALL( SCIProwRelease(&cut, blkmem, set, lp) );
1105  }
1106 
1107  /* clear the separation storage and reset statistics for separation round */
1108  SCIP_CALL( SCIPsepastoreClearCuts(sepastore, blkmem, set, eventqueue, eventfilter, lp) );
1109 
1110  return SCIP_OKAY;
1111 }
1112 
1113 /** clears the separation storage without adding the cuts to the LP */
1115  SCIP_SEPASTORE* sepastore, /**< separation storage */
1116  BMS_BLKMEM* blkmem, /**< block memory */
1117  SCIP_SET* set, /**< global SCIP settings */
1118  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1119  SCIP_EVENTFILTER* eventfilter, /**< event filter for global events */
1120  SCIP_LP* lp /**< LP data */
1121  )
1122 {
1123  int c;
1124 
1125  assert(sepastore != NULL);
1126 
1127  SCIPsetDebugMsg(set, "clearing %d cuts\n", sepastore->ncuts);
1128 
1129  /* release cuts */
1130  for( c = 0; c < sepastore->ncuts; ++c )
1131  {
1132  /* check, if the row deletions from separation storage events are tracked
1133  * if so, issue ROWDELETEDSEPA event
1134  */
1135  if( eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWDELETEDSEPA) != 0 )
1136  {
1137  SCIP_EVENT* event;
1138 
1139  SCIP_CALL( SCIPeventCreateRowDeletedSepa(&event, blkmem, sepastore->cuts[c]) );
1140  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) );
1141  }
1142 
1143  SCIP_CALL( SCIProwRelease(&sepastore->cuts[c], blkmem, set, lp) );
1144  }
1145 
1146  /* reset counters */
1147  sepastore->ncuts = 0;
1148  sepastore->nforcedcuts = 0;
1149  sepastore->ncutsfoundround = 0;
1150 
1151  /* if we have just finished the initial LP construction, free the (potentially large) cuts array */
1152  if( sepastore->initiallp )
1153  {
1154  BMSfreeMemoryArrayNull(&sepastore->cuts);
1155  sepastore->cutssize = 0;
1156  }
1157 
1158  return SCIP_OKAY;
1159 }
1160 
1161 /** removes cuts that are inefficacious w.r.t. the current LP solution from separation storage without adding the cuts to the LP */
1163  SCIP_SEPASTORE* sepastore, /**< separation storage */
1164  BMS_BLKMEM* blkmem, /**< block memory */
1165  SCIP_SET* set, /**< global SCIP settings */
1166  SCIP_STAT* stat, /**< problem statistics data */
1167  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1168  SCIP_EVENTFILTER* eventfilter, /**< event filter for global events */
1169  SCIP_LP* lp, /**< LP data */
1170  SCIP_Bool root, /**< are we at the root node? */
1171  SCIP_EFFICIACYCHOICE efficiacychoice /**< type of solution to base efficiacy computation on */
1172  )
1173 {
1174  int cnt;
1175  int c;
1176 
1177  assert( sepastore != NULL );
1178 
1179  /* check non-forced cuts only */
1180  cnt = 0;
1181  c = sepastore->nforcedcuts;
1182  while( c < sepastore->ncuts )
1183  {
1184  SCIP_Real cutefficacy;
1185  /* calculate cut's efficacy */
1186  switch ( efficiacychoice )
1187  {
1189  cutefficacy = SCIProwGetLPEfficacy(sepastore->cuts[c], set, stat, lp);
1190  break;
1192  cutefficacy = SCIProwGetRelaxEfficacy(sepastore->cuts[c], set, stat);
1193  break;
1195  cutefficacy = SCIProwGetNLPEfficacy(sepastore->cuts[c], set, stat);
1196  break;
1197  default:
1198  SCIPerrorMessage("Invalid efficiacy choice.\n");
1199  return SCIP_INVALIDCALL;
1200  }
1201  if( !SCIPsetIsEfficacious(set, root, cutefficacy) )
1202  {
1203  SCIP_CALL( sepastoreDelCut(sepastore, blkmem, set, eventqueue, eventfilter, lp, c) );
1204  ++cnt;
1205  }
1206  else
1207  ++c;
1208  }
1209  SCIPsetDebugMsg(set, "removed %d non-efficacious cuts\n", cnt);
1210 
1211  return SCIP_OKAY;
1212 }
1213 
1214 /** indicates whether a cut is applicable
1215  *
1216  * A cut is applicable if it is modifiable, not a bound change, or a bound change that changes bounds by at least epsilon.
1217  */
1219  SCIP_SET* set, /**< global SCIP settings */
1220  SCIP_ROW* cut /**< cut to check */
1221  )
1222 {
1223  return SCIProwIsModifiable(cut) || SCIProwGetNNonz(cut) != 1 || sepastoreIsBdchgApplicable(set, cut);
1224 }
1225 
1226 /** get cuts in the separation storage */
1228  SCIP_SEPASTORE* sepastore /**< separation storage */
1229  )
1230 {
1231  assert(sepastore != NULL);
1232 
1233  return sepastore->cuts;
1234 }
1235 
1236 /** get number of cuts in the separation storage */
1238  SCIP_SEPASTORE* sepastore /**< separation storage */
1239  )
1240 {
1241  assert(sepastore != NULL);
1242 
1243  return sepastore->ncuts;
1244 }
1245 
1246 /** get total number of cuts found so far */
1248  SCIP_SEPASTORE* sepastore /**< separation storage */
1249  )
1250 {
1251  assert(sepastore != NULL);
1252 
1253  return sepastore->ncutsfound;
1254 }
1255 
1256 /** get number of cuts found so far in current separation round */
1258  SCIP_SEPASTORE* sepastore /**< separation storage */
1259  )
1260 {
1261  assert(sepastore != NULL);
1262 
1263  return sepastore->ncutsfoundround;
1264 }
1265 
1266 /** get total number of cuts applied to the LPs */
1268  SCIP_SEPASTORE* sepastore /**< separation storage */
1269  )
1270 {
1271  assert(sepastore != NULL);
1272 
1273  return sepastore->ncutsapplied;
1274 }
internal methods for separators
SCIP_Bool SCIPsetIsInfinity(SCIP_SET *set, SCIP_Real val)
Definition: set.c:5776
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:531
internal methods for managing events
SCIP_Bool SCIPsetIsLE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:5834
SCIP_Bool SCIPsetIsFeasZero(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6284
void * origin
Definition: struct_lp.h:216
#define BMSfreeMemoryArrayNull(ptr)
Definition: memory.h:130
internal methods for branch and bound tree
static SCIP_RETCODE sepastoreUpdateOrthogonalities(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_LP *lp, SCIP_ROW *cut, SCIP_Real mincutorthogonality, SCIP_Real bestscore)
Definition: sepastore.c:797
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:701
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:2117
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17276
void SCIPsepaIncNAppliedCuts(SCIP_SEPA *sepa)
Definition: sepa.c:813
unsigned int origintype
Definition: struct_lp.h:255
SCIP_ROW ** SCIPsepastoreGetCuts(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1227
static long bound
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:16405
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17332
void SCIProwCapture(SCIP_ROW *row)
Definition: lp.c:5214
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:16543
void SCIPsepastoreStartForceCuts(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:139
SCIP_Real SCIPsetInfinity(SCIP_SET *set)
Definition: set.c:5636
int SCIPsepastoreGetNCutsApplied(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1267
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:16484
#define FALSE
Definition: def.h:64
static SCIP_RETCODE computeScore(SCIP_SEPASTORE *sepastore, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_Bool handlepool, int pos, SCIP_EFFICIACYCHOICE efficiacychoice, SCIP_Real *bestscore)
Definition: sepastore.c:927
SCIP_Bool SCIPsetIsZero(SCIP_SET *set, SCIP_Real val)
Definition: set.c:5888
#define TRUE
Definition: def.h:63
#define SCIPdebugCheckRow(set, row)
Definition: debug.h:250
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
SCIP_Real SCIProwGetLPEfficacy(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp)
Definition: lp.c:6614
int SCIPsetCalcMemGrowSize(SCIP_SET *set, int num)
Definition: set.c:5326
SCIP_Real SCIProwGetNLPEfficacy(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat)
Definition: lp.c:6770
static SCIP_Bool sepastoreIsCutRedundant(SCIP_SEPASTORE *sepastore, SCIP_SET *set, SCIP_STAT *stat, SCIP_ROW *cut)
Definition: sepastore.c:162
int SCIPnodeGetDepth(SCIP_NODE *node)
Definition: tree.c:7352
#define BMSfreeMemory(ptr)
Definition: memory.h:127
void SCIPvarAdjustLb(SCIP_VAR *var, SCIP_SET *set, SCIP_Real *lb)
Definition: var.c:6152
SCIP_Real * scores
internal methods for LP management
int SCIPsetGetSepaMaxcuts(SCIP_SET *set, SCIP_Bool root)
Definition: set.c:5504
SCIP_ROW ** cuts
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:16695
SCIP_Bool SCIPsetIsEfficacious(SCIP_SET *set, SCIP_Bool root, SCIP_Real efficacy)
Definition: set.c:6646
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:1146
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17286
SCIP_RETCODE SCIPeventCreateRowDeletedSepa(SCIP_EVENT **event, BMS_BLKMEM *blkmem, SCIP_ROW *row)
Definition: event.c:804
SCIP_Bool SCIPsetIsLT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:5816
SCIP_Bool SCIPsepastoreIsCutApplicable(SCIP_SET *set, SCIP_ROW *cut)
Definition: sepastore.c:1218
#define SCIP_EVENTTYPE_ROWADDEDSEPA
Definition: type_event.h:91
#define SCIPerrorMessage
Definition: pub_message.h:45
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:16593
SCIP_EVENTTYPE eventmask
Definition: struct_event.h:180
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, SCIP_Real mincutorthogonality, SCIP_Real bestscore, int depth, int *ncutsapplied)
Definition: sepastore.c:838
SCIP_RETCODE SCIProwChgLocal(SCIP_ROW *row, SCIP_Bool local)
Definition: lp.c:5605
int SCIPsepastoreGetNCuts(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1237
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:1162
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16662
SCIP_RETCODE SCIPsepastoreCreate(SCIP_SEPASTORE **sepastore)
Definition: sepastore.c:76
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:9293
internal methods for global SCIP settings
#define SCIP_CALL(x)
Definition: def.h:350
SCIP_Bool SCIPsetIsFeasGE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6262
static int sepastoreGetBestCut(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:897
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:16494
internal methods for storing separated cuts
SCIP_Bool SCIProwIsModifiable(SCIP_ROW *row)
Definition: lp.c:16603
SCIP_Bool SCIPsetIsFeasLE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6218
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:355
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:16430
int SCIProwGetNumIntCols(SCIP_ROW *row, SCIP_SET *set)
Definition: lp.c:6598
SCIP_RETCODE SCIProwRelease(SCIP_ROW **row, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_LP *lp)
Definition: lp.c:5227
data structures and methods for collecting reoptimization information
internal methods for problem variables
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:16440
#define SCIP_Bool
Definition: def.h:61
static SCIP_Bool sepastoreIsCutRedundantOrInfeasible(SCIP_SEPASTORE *sepastore, SCIP_SET *set, SCIP_STAT *stat, SCIP_ROW *cut, SCIP_Bool *infeasible)
Definition: sepastore.c:200
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:616
#define MAX(x, y)
Definition: tclique_def.h:75
void SCIPconshdlrIncNAppliedCuts(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4789
methods for debugging
#define SCIPsetDebugMsg
Definition: set.h:1913
SCIP_RETCODE SCIPsepastoreFree(SCIP_SEPASTORE **sepastore)
Definition: sepastore.c:99
#define SCIP_EVENTTYPE_ROWDELETEDSEPA
Definition: type_event.h:92
static SCIP_RETCODE sepastoreEnsureCutsMem(SCIP_SEPASTORE *sepastore, SCIP_SET *set, int num)
Definition: sepastore.c:49
static SCIP_Bool sepastoreIsBdchgApplicable(SCIP_SET *set, SCIP_ROW *cut)
Definition: sepastore.c:256
void SCIPsepastoreEndInitialLP(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:127
SCIP_Real SCIProwGetRelaxEfficacy(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat)
Definition: lp.c:6730
SCIP_Bool SCIPsetIsFeasLT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6196
void SCIPsepastoreStartInitialLP(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:115
SCIP_Real SCIProwGetMaxActivity(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat)
Definition: lp.c:6482
SCIP_Real SCIProwGetConstant(SCIP_ROW *row)
Definition: lp.c:16450
int SCIPsepastoreGetNCutsFound(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1247
SCIP_Real SCIProwGetMinActivity(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat)
Definition: lp.c:6461
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:16254
SCIP_NODE * SCIPtreeGetRootNode(SCIP_TREE *tree)
Definition: tree.c:8352
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:2021
SCIP_NODE * SCIPtreeGetCurrentNode(SCIP_TREE *tree)
Definition: tree.c:8285
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:978
SCIP_Bool SCIPsetIsGT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:5852
#define SCIP_Real
Definition: def.h:149
internal methods for problem statistics
SCIP_Real SCIProwGetObjParallelism(SCIP_ROW *row, SCIP_SET *set, SCIP_LP *lp)
Definition: lp.c:7606
SCIP_Bool SCIPsetIsFeasPositive(SCIP_SET *set, SCIP_Real val)
Definition: set.c:6295
int SCIPsepastoreGetNCutsFoundRound(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1257
#define BMSallocMemory(ptr)
Definition: memory.h:101
#define SCIP_INVALID
Definition: def.h:169
#define BMSreallocMemoryArray(ptr, num)
Definition: memory.h:109
internal methods for constraints and constraint handlers
SCIP_Bool SCIPsetIsFeasGT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6240
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17342
void SCIPvarAdjustUb(SCIP_VAR *var, SCIP_SET *set, SCIP_Real *ub)
Definition: var.c:6169
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:419
SCIP_RETCODE SCIPsepastoreClearCuts(SCIP_SEPASTORE *sepastore, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_LP *lp)
Definition: sepastore.c:1114
#define SCIP_ALLOC(x)
Definition: def.h:361
SCIP_Bool forcecuts
void SCIPsepastoreEndForceCuts(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:150
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:394
SCIP_Real SCIProwGetOrthogonality(SCIP_ROW *row1, SCIP_ROW *row2, char orthofunc)
Definition: lp.c:7594
SCIP_RETCODE SCIPeventCreateRowAddedSepa(SCIP_EVENT **event, BMS_BLKMEM *blkmem, SCIP_ROW *row)
Definition: event.c:785
SCIP_Bool SCIProwIsInGlobalCutpool(SCIP_ROW *row)
Definition: lp.c:16663