Scippy

SCIP

Solving Constraint Integer Programs

cutpool.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-2017 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 cutpool.c
17  * @brief methods for storing cuts in a cut pool
18  * @author Tobias Achterberg
19  * @author Stefan Heinz
20  * @author Gerald Gamrath
21  * @author Marc Pfetsch
22  * @author Kati Wolter
23  */
24 
25 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
26 
27 #include <assert.h>
28 
29 #include "scip/def.h"
30 #include "scip/set.h"
31 #include "scip/stat.h"
32 #include "scip/clock.h"
33 #include "scip/lp.h"
34 #include "scip/cons.h"
35 #include "scip/sepa.h"
36 #include "scip/sepastore.h"
37 #include "scip/cutpool.h"
38 #include "scip/pub_message.h"
39 #include "scip/pub_misc.h"
40 
41 #include "scip/struct_cutpool.h"
42 
43 
44 
45 /*
46  * Hash functions
47  */
48 
49 /** gets the hash key of a cut */
50 static
51 SCIP_DECL_HASHGETKEY(hashGetKeyCut)
52 { /*lint --e{715}*/
53  SCIP_CUT* cut;
54 
55  cut = (SCIP_CUT*)elem;
56  assert(cut != NULL);
57  assert(cut->row != NULL);
58 
59  /* the key of a cut is the row */
60  return cut->row;
61 }
62 
63 /** returns TRUE iff both cuts are identical */
64 static
65 SCIP_DECL_HASHKEYEQ(hashKeyEqCut)
66 { /*lint --e{715}*/
67  /* Warning: The comparison of real values is made against default epsilon.
68  * This is ugly, but we have no settings at hand.
69  */
70  SCIP_ROW* row1;
71  SCIP_ROW* row2;
72 
73  row1 = (SCIP_ROW*)key1;
74  row2 = (SCIP_ROW*)key2;
75  assert(row1 != NULL);
76  assert(row2 != NULL);
77 
78  /* Sort the column indices of both rows.
79  *
80  * The columns in a row are divided into two parts: LP columns, which are currently in the LP and non-LP columns;
81  * we sort the rows, but that only ensures that within these two parts, columns are sorted w.r.t. their index.
82  * Normally, this should be suficient, because a column contained in both rows should either be one of the LP columns
83  * for both or one of the non-LP columns for both.
84  * However, directly after a row was created, before it is added to the LP, the row is not linked to all its
85  * columns and all columns are treated as non-LP columns.
86  * Therefore, if exactly one of the rows has no LP columns, we cannot rely on the partition, because this row might
87  * just have been created and also columns that are in the LP might be in the non-LP columns part.
88  */
89  SCIProwSort(row1);
90  SCIProwSort(row2);
91  assert(row1->lpcolssorted);
92  assert(row1->nonlpcolssorted);
93  assert(row1->validminmaxidx);
94  assert(row2->lpcolssorted);
95  assert(row2->nonlpcolssorted);
96  assert(row2->validminmaxidx);
97 
98  /* currently we are only handling rows which are completely linked or not linked at all */
99  assert(row1->nunlinked == 0 || row1->nlpcols == 0);
100  assert(row2->nunlinked == 0 || row2->nlpcols == 0);
101 
102  /* compare the trivial characteristics of the rows */
103  if( row1->len != row2->len
104  || row1->minidx != row2->minidx
105  || row1->maxidx != row2->maxidx
106  || row1->nummaxval != row2->nummaxval
107  || row1->numminval != row2->numminval
108  || REALABS(row1->lhs - row2->lhs) > SCIP_DEFAULT_EPSILON
109  || REALABS(row1->rhs - row2->rhs) > SCIP_DEFAULT_EPSILON
110  || REALABS(row1->maxval - row2->maxval) > SCIP_DEFAULT_EPSILON
111  || REALABS(row1->minval - row2->minval) > SCIP_DEFAULT_EPSILON
112  )
113  return FALSE;
114 
115  /* both rows have LP columns, or none of them has, or one has only LP colums and the other only non-LP columns,
116  * so we can rely on the sorting of the columns
117  */
118  if( (row1->nlpcols == 0) == (row2->nlpcols == 0)
119  || (row1->nlpcols == 0 && row2->nlpcols == row2->len)
120  || (row1->nlpcols == row1->len && row2->nlpcols == 0) )
121  {
122  int i;
123 
124  if( (row1->nlpcols == 0) == (row2->nlpcols == 0) )
125  {
126 #ifndef NDEBUG
127  /* in debug mode, we check that we can rely on the partition into LP columns and non-LP columns */
128  int i2;
129 
130  i = 0;
131  i2 = row2->nlpcols;
132  while( i < row1->nlpcols && i2 < row2->len )
133  {
134  assert(row1->cols[i] != row2->cols[i2]);
135  if( row1->cols[i]->index < row2->cols[i2]->index )
136  ++i;
137  else
138  {
139  assert(row1->cols[i]->index > row2->cols[i2]->index);
140  ++i2;
141  }
142  }
143  assert(i == row1->nlpcols || i2 == row2->len);
144 
145  i = row1->nlpcols;
146  i2 = 0;
147  while( i < row1->len && i2 < row2->nlpcols )
148  {
149  assert(row1->cols[i] != row2->cols[i2]);
150  if( row1->cols[i]->index < row2->cols[i2]->index )
151  ++i;
152  else
153  {
154  assert(row1->cols[i]->index > row2->cols[i2]->index);
155  ++i2;
156  }
157  }
158  assert(i == row1->len || i2 == row2->nlpcols);
159 #endif
160 
161  /* both rows are linked and the number of lpcolumns is not equal so they cannot be equal */
162  if( row1->nlpcols != row2->nlpcols )
163  return FALSE;
164  }
165 
166  /* compare the columns of the rows */
167  for( i = 0; i < row1->len; ++i )
168  {
169  if( row1->cols[i] != row2->cols[i] )
170  return FALSE;
171  }
172 
173  /* compare the coefficients of the rows */
174  for( i = 0; i < row1->len; ++i )
175  {
176  if( REALABS(row1->vals[i] - row2->vals[i]) > SCIP_DEFAULT_EPSILON )
177  return FALSE;
178  }
179  }
180  /* one row has LP columns, but the other not, that could be because the one without was just created and isn't
181  * linked yet; in this case, one column could be an LP column in one row and a non-LP column in the other row, so we
182  * cannot rely on the partition; thus, we iteratively check whether the next column of row1 is either the next LP
183  * column of row2 or the next non-LP column of row2 and the coefficients are equal
184  */
185  else
186  {
187  int i1;
188  int ilp;
189  int inlp;
190 
191  /* ensure that row1 is the row without LP columns, switch the rows, if neccessary */
192  if( row2->nlpcols == 0 )
193  {
194  SCIP_ROW* tmprow;
195  tmprow = row2;
196  row2 = row1;
197  row1 = tmprow;
198  }
199  assert(row1->nlpcols == 0 && row2->nlpcols > 0);
200 
201  ilp = 0;
202  inlp = row2->nlpcols;
203 
204  /* compare the columns and coefficients of the rows */
205  for( i1 = 0; i1 < row1->len; ++i1 )
206  {
207  /* current column of row1 is the current LP column of row2, check the coefficient */
208  if( ilp < row2->nlpcols && row1->cols[i1] == row2->cols[ilp] )
209  {
210  if( REALABS(row1->vals[i1] - row2->vals[ilp]) > SCIP_DEFAULT_EPSILON )
211  return FALSE;
212  else
213  ++ilp;
214  }
215  /* current column of row1 is the current non-LP column of row2, check the coefficient */
216  else if( inlp < row2->len && row1->cols[i1] == row2->cols[inlp] )
217  {
218  if( REALABS(row1->vals[i1] - row2->vals[inlp]) > SCIP_DEFAULT_EPSILON )
219  return FALSE;
220  else
221  ++inlp;
222  }
223  /* current column of row1 is neither the current LP column of row2, nor the current non-LP column of row 2 */
224  else
225  return FALSE;
226  }
227  }
228 
229  return TRUE;
230 }
231 
232 static
233 SCIP_DECL_HASHKEYVAL(hashKeyValCut)
234 { /*lint --e{715}*/
235  SCIP_ROW* row;
236  unsigned int keyval;
237  SCIP_Real maxval;
238  SCIP_Real minval;
239  SCIP_SET* set;
240 
241  set = (SCIP_SET*) userptr;
242  row = (SCIP_ROW*)key;
243  assert(row != NULL);
244 
245  maxval = SCIProwGetMaxval(row, set);
246  minval = SCIProwGetMinval(row, set);
247  assert(row->nummaxval > 0);
248  assert(row->numminval > 0);
249  assert(row->validminmaxidx);
250 
251  keyval = SCIPhashFour(SCIPpositiveRealHashCode(maxval, 8),
252  SCIPpositiveRealHashCode(minval, 12),
253  SCIPcombineThreeInt(row->maxidx, row->len, row->minidx),
255 
256  return keyval;
257 }
258 
259 
260 
261 /*
262  * dynamic memory arrays
263  */
264 
265 /** resizes cuts array to be able to store at least num entries */
266 static
268  SCIP_CUTPOOL* cutpool, /**< cut pool */
269  SCIP_SET* set, /**< global SCIP settings */
270  int num /**< minimal number of slots in array */
271  )
272 {
273  assert(cutpool != NULL);
274  assert(set != NULL);
275 
276  if( num > cutpool->cutssize )
277  {
278  int newsize;
279 
280  newsize = SCIPsetCalcMemGrowSize(set, num);
281  SCIP_ALLOC( BMSreallocMemoryArray(&cutpool->cuts, newsize) );
282  cutpool->cutssize = newsize;
283  }
284  assert(num <= cutpool->cutssize);
285 
286  return SCIP_OKAY;
287 }
288 
289 
290 
291 /*
292  * Cut methods
293  */
294 
295 /** creates a cut and captures the row */
296 static
298  SCIP_CUT** cut, /**< pointer to store the cut */
299  BMS_BLKMEM* blkmem, /**< block memory */
300  SCIP_ROW* row /**< row this cut represents */
301  )
302 {
303  assert(cut != NULL);
304  assert(blkmem != NULL);
305  assert(row != NULL);
306 
307  /* allocate cut memory */
308  SCIP_ALLOC( BMSallocBlockMemory(blkmem, cut) );
309  (*cut)->row = row;
310  (*cut)->age = 0;
311  (*cut)->processedlp = -1;
312  (*cut)->processedlpsol = -1;
313  (*cut)->pos = -1;
314 
315  /* capture row */
316  SCIProwCapture(row);
317 
318  return SCIP_OKAY;
319 }
320 
321 /** frees a cut and releases the row */
322 static
324  SCIP_CUT** cut, /**< pointer to store the cut */
325  BMS_BLKMEM* blkmem, /**< block memory */
326  SCIP_SET* set, /**< global SCIP settings */
327  SCIP_LP* lp /**< current LP data */
328  )
329 {
330  assert(cut != NULL);
331  assert(*cut != NULL);
332  assert((*cut)->row != NULL);
333  assert(blkmem != NULL);
334 
335  /* release row */
336  SCIP_CALL( SCIProwRelease(&(*cut)->row, blkmem, set, lp) );
337 
338  /* free cut memory */
339  BMSfreeBlockMemory(blkmem, cut);
340 
341  return SCIP_OKAY;
342 }
343 
344 /** returns whether the cut's age exceeds the age limit */
345 static
347  SCIP_CUT* cut, /**< cut to check */
348  int agelimit /**< maximum age a cut can reach before it is deleted from the pool, or -1 */
349  )
350 {
351  assert(cut != NULL);
352 
353  return (agelimit >= 0 && cut->age > agelimit);
354 }
355 
356 /** gets the row of the cut */
358  SCIP_CUT* cut /**< cut */
359  )
360 {
361  assert(cut != NULL);
362 
363  return cut->row;
364 }
365 
366 /** gets the age of the cut: the number of consecutive cut pool separation rounds where the cut was neither in the LP nor violated */
368  SCIP_CUT* cut /**< cut */
369  )
370 {
371  assert(cut != NULL);
372 
373  return cut->age;
374 }
375 
376 /** returns the ratio of LPs where the row belonging to this cut was active in an LP solution, i.e.
377  * where the age of its row has not been increased
378  *
379  * @see SCIPcutGetAge() to get the age of a cut
380  */
382  SCIP_CUT* cut /**< cut */
383  )
384 {
385  SCIP_Longint nlpsaftercreation;
386  SCIP_Longint activeinlpcounter;
387 
388  assert(cut != NULL);
389  assert(cut->row != NULL);
390 
391  nlpsaftercreation = SCIProwGetNLPsAfterCreation(cut->row);
392  activeinlpcounter = SCIProwGetActiveLPCount(cut->row);
393 
394  return (nlpsaftercreation > 0 ? activeinlpcounter / (SCIP_Real)nlpsaftercreation : 0.0);
395 }
396 
397 /*
398  * Cutpool methods
399  */
400 
401 /** creates cut pool */
403  SCIP_CUTPOOL** cutpool, /**< pointer to store cut pool */
404  BMS_BLKMEM* blkmem, /**< block memory */
405  SCIP_SET* set, /**< global SCIP settings */
406  int agelimit, /**< maximum age a cut can reach before it is deleted from the pool */
407  SCIP_Bool globalcutpool /**< is this the global cut pool of SCIP? */
408  )
409 {
410  assert(cutpool != NULL);
411  assert(agelimit >= -1);
412 
413  SCIP_ALLOC( BMSallocMemory(cutpool) );
414 
415  SCIP_CALL( SCIPclockCreate(&(*cutpool)->poolclock, SCIP_CLOCKTYPE_DEFAULT) );
416 
417  SCIP_CALL( SCIPhashtableCreate(&(*cutpool)->hashtable, blkmem,
418  (set->misc_usesmalltables ? SCIP_HASHSIZE_CUTPOOLS_SMALL : SCIP_HASHSIZE_CUTPOOLS),
419  hashGetKeyCut, hashKeyEqCut, hashKeyValCut, (void*) set) );
420 
421  (*cutpool)->cuts = NULL;
422  (*cutpool)->cutssize = 0;
423  (*cutpool)->ncuts = 0;
424  (*cutpool)->nremovablecuts = 0;
425  (*cutpool)->agelimit = agelimit;
426  (*cutpool)->processedlp = -1;
427  (*cutpool)->processedlpsol = -1;
428  (*cutpool)->firstunprocessed = 0;
429  (*cutpool)->firstunprocessedsol = 0;
430  (*cutpool)->maxncuts = 0;
431  (*cutpool)->ncalls = 0;
432  (*cutpool)->ncutsfound = 0;
433  (*cutpool)->globalcutpool = globalcutpool;
434 
435  return SCIP_OKAY;
436 }
437 
438 /** frees cut pool */
440  SCIP_CUTPOOL** cutpool, /**< pointer to store cut pool */
441  BMS_BLKMEM* blkmem, /**< block memory */
442  SCIP_SET* set, /**< global SCIP settings */
443  SCIP_LP* lp /**< current LP data */
444  )
445 {
446  assert(cutpool != NULL);
447  assert(*cutpool != NULL);
448 
449  /* remove all cuts from the pool */
450  SCIP_CALL( SCIPcutpoolClear(*cutpool, blkmem, set, lp) );
451 
452  /* free clock */
453  SCIPclockFree(&(*cutpool)->poolclock);
454 
455  /* free hash table */
456  SCIPhashtableFree(&(*cutpool)->hashtable);
457 
458  BMSfreeMemoryArrayNull(&(*cutpool)->cuts);
459  BMSfreeMemory(cutpool);
460 
461  return SCIP_OKAY;
462 }
463 
464 /** removes all rows from the cut pool */
466  SCIP_CUTPOOL* cutpool, /**< cut pool */
467  BMS_BLKMEM* blkmem, /**< block memory */
468  SCIP_SET* set, /**< global SCIP settings */
469  SCIP_LP* lp /**< current LP data */
470  )
471 {
472  int i;
473 
474  assert(cutpool != NULL);
475 
476  /* free cuts */
477  for( i = 0; i < cutpool->ncuts; ++i )
478  {
479  if( cutpool->globalcutpool )
480  cutpool->cuts[i]->row->inglobalcutpool = FALSE;
481  SCIProwUnlock(cutpool->cuts[i]->row);
482  SCIP_CALL( cutFree(&cutpool->cuts[i], blkmem, set, lp) );
483  }
484  cutpool->ncuts = 0;
485  cutpool->nremovablecuts = 0;
486 
487  return SCIP_OKAY;
488 }
489 
490 /** if not already existing, adds row to cut pool and captures it */
492  SCIP_CUTPOOL* cutpool, /**< cut pool */
493  BMS_BLKMEM* blkmem, /**< block memory */
494  SCIP_SET* set, /**< global SCIP settings */
495  SCIP_ROW* row /**< cutting plane to add */
496  )
497 {
498  assert(cutpool != NULL);
499  assert(row != NULL);
500 
501  /* only called to ensure that minidx and maxidx are up-to-date */
502  (void) SCIProwGetMaxidx(row, set);
503  assert(row->validminmaxidx);
504 
505  /* check in hash table, if cut already exists in the pool */
506  if( SCIPhashtableRetrieve(cutpool->hashtable, (void*)row) == NULL )
507  {
508  SCIP_CALL( SCIPcutpoolAddNewRow(cutpool, blkmem, set, row) );
509  }
510 
511  return SCIP_OKAY;
512 }
513 
514 /** adds row to cut pool and captures it; doesn't check for multiple cuts */
516  SCIP_CUTPOOL* cutpool, /**< cut pool */
517  BMS_BLKMEM* blkmem, /**< block memory */
518  SCIP_SET* set, /**< global SCIP settings */
519  SCIP_ROW* row /**< cutting plane to add */
520  )
521 {
522  SCIP_CUT* cut;
523 
524  assert(cutpool != NULL);
525  assert(row != NULL);
526 
527  /* check, if row is modifiable or local */
528  if( SCIProwIsModifiable(row) )
529  {
530  SCIPerrorMessage("cannot store modifiable row <%s> in a cut pool\n", SCIProwGetName(row));
531  return SCIP_INVALIDDATA;
532  }
533  if( SCIProwIsLocal(row) )
534  {
535  SCIPerrorMessage("cannot store locally valid row <%s> in a cut pool\n", SCIProwGetName(row));
536  return SCIP_INVALIDDATA;
537  }
538 
539  /* only called to ensure that minidx and maxidx are up-to-date */
540  (void) SCIProwGetMaxidx(row, set);
541  assert(row->validminmaxidx);
542 
543  /* create the cut */
544  SCIP_CALL( cutCreate(&cut, blkmem, row) );
545  cut->pos = cutpool->ncuts;
546 
547  /* add cut to the pool */
548  SCIP_CALL( cutpoolEnsureCutsMem(cutpool, set, cutpool->ncuts+1) );
549  cutpool->cuts[cutpool->ncuts] = cut;
550  cutpool->ncuts++;
551  cutpool->maxncuts = MAX(cutpool->maxncuts, cutpool->ncuts);
552  if( SCIProwIsRemovable(row) )
553  cutpool->nremovablecuts++;
554 
555  /* insert cut in the hash table */
556  SCIP_CALL( SCIPhashtableInsert(cutpool->hashtable, (void*)cut) );
557 
558  /* if this is the global cut pool of SCIP, mark the row to be member of the pool */
559  if( cutpool->globalcutpool )
560  row->inglobalcutpool = TRUE;
561 
562  /* lock the row */
563  SCIProwLock(row);
564 
565  return SCIP_OKAY;
566 }
567 
568 /** removes the cut from the cut pool */
569 static
571  SCIP_CUTPOOL* cutpool, /**< cut pool */
572  BMS_BLKMEM* blkmem, /**< block memory */
573  SCIP_SET* set, /**< global SCIP settings */
574  SCIP_STAT* stat, /**< problem statistics data */
575  SCIP_LP* lp, /**< current LP data */
576  SCIP_CUT* cut /**< cut to remove */
577  )
578 {
579  int pos;
580 
581  assert(cutpool != NULL);
582  assert(cutpool->firstunprocessed <= cutpool->ncuts);
583  assert(cutpool->firstunprocessedsol <= cutpool->ncuts);
584  assert(blkmem != NULL);
585  assert(stat != NULL);
586  assert(cutpool->processedlp <= stat->lpcount);
587  assert(cutpool->processedlpsol <= stat->lpcount);
588  assert(cut != NULL);
589  assert(cut->row != NULL);
590 
591  pos = cut->pos;
592  assert(0 <= pos && pos < cutpool->ncuts);
593  assert(cutpool->cuts[pos] == cut);
594 
595  /* decrease the number of removable cuts counter (row might have changed its removable status -> counting might not
596  * be correct
597  */
598  if( SCIProwIsRemovable(cut->row) && cutpool->nremovablecuts > 0 )
599  cutpool->nremovablecuts--;
600 
601  /* if this is the global cut pool of SCIP, mark the row to not be member anymore */
602  if( cutpool->globalcutpool )
603  cut->row->inglobalcutpool = FALSE;
604 
605  /* unlock the row */
606  SCIProwUnlock(cut->row);
607 
608  /* remove the cut from the hash table */
609  assert(SCIPhashtableExists(cutpool->hashtable, (void*)cut));
610  SCIP_CALL( SCIPhashtableRemove(cutpool->hashtable, (void*)cut) );
611 
612  /* free the cut */
613  SCIP_CALL( cutFree(&cutpool->cuts[pos], blkmem, set, lp) );
614 
615  /* move the last cut of the pool to the free position */
616  if( pos < cutpool->ncuts-1 )
617  {
618  cutpool->cuts[pos] = cutpool->cuts[cutpool->ncuts-1];
619  cutpool->cuts[pos]->pos = pos;
620  assert(cutpool->cuts[pos]->processedlp <= stat->lpcount);
621  assert(cutpool->cuts[pos]->processedlpsol <= stat->lpcount);
622  if( cutpool->cuts[pos]->processedlp < stat->lpcount )
623  cutpool->firstunprocessed = MIN(cutpool->firstunprocessed, pos);
624  if( cutpool->cuts[pos]->processedlpsol < stat->lpcount )
625  cutpool->firstunprocessedsol = MIN(cutpool->firstunprocessedsol, pos);
626  }
627  else
628  {
629  cutpool->firstunprocessed = MIN(cutpool->firstunprocessed, cutpool->ncuts-1);
630  cutpool->firstunprocessedsol = MIN(cutpool->firstunprocessedsol, cutpool->ncuts-1);
631  }
632 
633  cutpool->ncuts--;
634 
635  return SCIP_OKAY;
636 }
637 
638 /** removes the LP row from the cut pool */
640  SCIP_CUTPOOL* cutpool, /**< cut pool */
641  BMS_BLKMEM* blkmem, /**< block memory */
642  SCIP_SET* set, /**< global SCIP settings */
643  SCIP_STAT* stat, /**< problem statistics data */
644  SCIP_LP* lp, /**< current LP data */
645  SCIP_ROW* row /**< row to remove */
646  )
647 {
648  SCIP_CUT* cut;
649 
650  assert(cutpool != NULL);
651  assert(row != NULL);
652 
653  /* find the cut in hash table */
654  cut = (SCIP_CUT*)SCIPhashtableRetrieve(cutpool->hashtable, (void*)row);
655  if( cut == NULL )
656  {
657  SCIPerrorMessage("row <%s> is not existing in cutpool %p\n", SCIProwGetName(row), cutpool);
658  return SCIP_INVALIDDATA;
659  }
660 
661  SCIP_CALL( cutpoolDelCut(cutpool, blkmem, set, stat, lp, cut) );
662 
663  return SCIP_OKAY;
664 }
665 
666 
667 /** separates cuts of the cut pool */
669  SCIP_CUTPOOL* cutpool, /**< cut pool */
670  BMS_BLKMEM* blkmem, /**< block memory */
671  SCIP_SET* set, /**< global SCIP settings */
672  SCIP_STAT* stat, /**< problem statistics data */
673  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
674  SCIP_EVENTFILTER* eventfilter, /**< event filter for global events */
675  SCIP_LP* lp, /**< current LP data */
676  SCIP_SEPASTORE* sepastore, /**< separation storage */
677  SCIP_SOL* sol, /**< solution to be separated (or NULL for LP-solution) */
678  SCIP_Bool cutpoolisdelayed, /**< is the cutpool delayed (count cuts found)? */
679  SCIP_Bool root, /**< are we at the root node? */
680  SCIP_RESULT* result /**< pointer to store the result of the separation call */
681  )
682 {
683  SCIP_CUT* cut;
684  SCIP_Bool found;
685  SCIP_Bool cutoff;
686  int firstunproc;
687  int oldncuts;
688  int c;
689 
690  assert(cutpool != NULL);
691  assert(stat != NULL);
692  assert(cutpool->processedlp <= stat->lpcount);
693  assert(cutpool->processedlpsol <= stat->lpcount);
694  assert(cutpool->firstunprocessed <= cutpool->ncuts);
695  assert(cutpool->firstunprocessedsol <= cutpool->ncuts);
696  assert(result != NULL);
697 
698  *result = SCIP_DIDNOTRUN;
699 
700  /* don't separate cut pool in the root node, if there are no removable cuts */
701  if( root && cutpool->nremovablecuts == 0 )
702  return SCIP_OKAY;
703 
704  if ( sol == NULL )
705  {
706  if( cutpool->processedlp < stat->lpcount )
707  cutpool->firstunprocessed = 0;
708  if( cutpool->firstunprocessed == cutpool->ncuts )
709  return SCIP_OKAY;
710  firstunproc = cutpool->firstunprocessed;
711  }
712  else
713  {
714  if( cutpool->processedlpsol < stat->lpcount )
715  cutpool->firstunprocessedsol = 0;
716  if( cutpool->firstunprocessedsol == cutpool->ncuts )
717  return SCIP_OKAY;
718  firstunproc = cutpool->firstunprocessedsol;
719  }
720 
721  *result = SCIP_DIDNOTFIND;
722  cutpool->ncalls++;
723  found = FALSE;
724 
725  SCIPsetDebugMsg(set, "separating%s cut pool %p with %d cuts, beginning with cut %d\n", ( sol == NULL ) ? "" : " solution from", (void*)cutpool, cutpool->ncuts, firstunproc);
726 
727  /* start timing */
728  SCIPclockStart(cutpool->poolclock, set);
729 
730  /* remember the current total number of found cuts */
731  oldncuts = SCIPsepastoreGetNCuts(sepastore);
732 
733  /* process all unprocessed cuts in the pool */
734  cutoff = FALSE;
735  for( c = firstunproc; c < cutpool->ncuts; ++c )
736  {
737  SCIP_Longint proclp;
738 
739  cut = cutpool->cuts[c];
740  assert(cut != NULL);
741  assert(cut->processedlp <= stat->lpcount);
742  assert(cut->processedlpsol <= stat->lpcount);
743  assert(cut->pos == c);
744 
745  proclp = ( sol == NULL ) ? cut->processedlp : cut->processedlpsol;
746 
747  if( proclp < stat->lpcount )
748  {
749  SCIP_ROW* row;
750 
751  if ( sol == NULL )
752  cut->processedlp = stat->lpcount;
753  else
754  cut->processedlpsol = stat->lpcount;
755 
756  row = cut->row;
757  if( !SCIProwIsInLP(row) )
758  {
759  /* if the cut is a bound change (i.e. a row with only one variable), add it as bound change instead of LP
760  * row; hence, we want to remove the bound change cut from the SCIP cut pool
761  */
762  if( !SCIProwIsModifiable(row) && SCIProwGetNNonz(row) == 1 )
763  {
764  /* insert bound change cut into separation store which will force that cut */
765  SCIP_CALL( SCIPsepastoreAddCut(sepastore, blkmem, set, stat, eventqueue, eventfilter, lp, sol, row, FALSE, root, &cutoff) );
766  SCIP_CALL( cutpoolDelCut(cutpool, blkmem, set, stat, lp, cut) );
767 
768  if ( cutoff )
769  break;
770  }
771  else if( (sol == NULL && SCIProwIsLPEfficacious(row, set, stat, lp, root)) || (sol != NULL && SCIProwIsSolEfficacious(row, set, stat, sol, root)) )
772  {
773  /* insert cut in separation storage */
774  SCIPsetDebugMsg(set, " -> separated cut <%s> from the cut pool (feasibility: %g)\n",
775  SCIProwGetName(row), ( sol == NULL ) ? SCIProwGetLPFeasibility(row, set, stat, lp) : SCIProwGetSolFeasibility(row, set, stat, sol) );
776  SCIP_CALL( SCIPsepastoreAddCut(sepastore, blkmem, set, stat, eventqueue, eventfilter, lp, sol, row, FALSE, root, &cutoff) );
777 
778  /* count cuts */
779  if ( cutpoolisdelayed )
780  {
781  if ( SCIProwGetOriginSepa(row) != NULL )
782  {
783  SCIP_SEPA* sepa;
784 
785  sepa = SCIProwGetOriginSepa(row);
786  SCIPsepaIncNCutsFound(sepa);
788  }
789  else if ( SCIProwGetOriginCons(row) != NULL )
790  {
791  SCIP_CONSHDLR* conshdlr;
792 
793  conshdlr = SCIProwGetOriginCons(row);
794  SCIPconshdlrIncNCutsFound(conshdlr);
795  }
796  }
797 
798  found = TRUE;
799  cut->age = 0;
800 
801  if ( cutoff )
802  break;
803  }
804  else
805  {
806  cut->age++;
807  if( cutIsAged(cut, cutpool->agelimit) )
808  {
809  SCIP_CALL( cutpoolDelCut(cutpool, blkmem, set, stat, lp, cut) );
810  }
811  }
812  }
813  }
814  }
815 
816  if ( sol == NULL )
817  {
818  cutpool->processedlp = stat->lpcount;
819  cutpool->firstunprocessed = cutpool->ncuts;
820  }
821  else
822  {
823  cutpool->processedlpsol = stat->lpcount;
824  cutpool->firstunprocessedsol = cutpool->ncuts;
825  }
826 
827  /* update the number of found cuts */
828  cutpool->ncutsfound += SCIPsepastoreGetNCuts(sepastore) - oldncuts; /*lint !e776*/
829 
830  /* stop timing */
831  SCIPclockStop(cutpool->poolclock, set);
832 
833  if ( cutoff )
834  *result = SCIP_CUTOFF;
835  else if( found )
836  *result = SCIP_SEPARATED;
837 
838  return SCIP_OKAY;
839 }
840 
841 /** gets array of cuts in the cut pool */
843  SCIP_CUTPOOL* cutpool /**< cut pool */
844  )
845 {
846  assert(cutpool != NULL);
847 
848  return cutpool->cuts;
849 }
850 
851 /** gets number of cuts in the cut pool */
853  SCIP_CUTPOOL* cutpool /**< cut pool */
854  )
855 {
856  assert(cutpool != NULL);
857 
858  return cutpool->ncuts;
859 }
860 
861 /** gets maximum number of cuts that were stored in the cut pool at the same time */
863  SCIP_CUTPOOL* cutpool /**< cut pool */
864  )
865 {
866  assert(cutpool != NULL);
867 
868  return cutpool->maxncuts;
869 }
870 
871 /** gets time in seconds used for separating cuts from the pool */
873  SCIP_CUTPOOL* cutpool /**< cut pool */
874  )
875 {
876  assert(cutpool != NULL);
877 
878  return SCIPclockGetTime(cutpool->poolclock);
879 }
880 
881 /** get number of times, the cut pool was separated */
883  SCIP_CUTPOOL* cutpool /**< cut pool */
884  )
885 {
886  assert(cutpool != NULL);
887 
888  return cutpool->ncalls;
889 }
890 
891 /** get total number of cuts that were separated from the cut pool */
893  SCIP_CUTPOOL* cutpool /**< cut pool */
894  )
895 {
896  assert(cutpool != NULL);
897 
898  return cutpool->ncutsfound;
899 }
900 
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
internal methods for separators
SCIP_Bool SCIProwIsRemovable(SCIP_ROW *row)
Definition: lp.c:16440
SCIP_ROW * row
int nunlinked
Definition: struct_lp.h:226
SCIP_Real SCIProwGetSolFeasibility(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat, SCIP_SOL *sol)
Definition: lp.c:6328
int SCIProwGetMaxidx(SCIP_ROW *row, SCIP_SET *set)
Definition: lp.c:6511
SCIP_HASHTABLE * hashtable
#define BMSfreeMemoryArrayNull(ptr)
Definition: memory.h:103
int nummaxval
Definition: struct_lp.h:233
#define SCIP_HASHSIZE_CUTPOOLS
Definition: def.h:226
SCIP_SEPA * SCIProwGetOriginSepa(SCIP_ROW *row)
Definition: lp.c:16475
SCIP_Longint processedlp
SCIP_Real SCIProwGetMinval(SCIP_ROW *row, SCIP_SET *set)
Definition: lp.c:6495
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2254
SCIP_CUT ** cuts
SCIP_Longint SCIPcutpoolGetNCutsFound(SCIP_CUTPOOL *cutpool)
Definition: cutpool.c:892
internal methods for clocks and timing issues
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:16232
void SCIProwCapture(SCIP_ROW *row)
Definition: lp.c:5159
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:16370
SCIP_Longint SCIProwGetActiveLPCount(SCIP_ROW *row)
Definition: lp.c:16544
void SCIPclockStop(SCIP_CLOCK *clck, SCIP_SET *set)
Definition: clock.c:350
#define FALSE
Definition: def.h:64
SCIP_Longint processedlpsol
void SCIPclockStart(SCIP_CLOCK *clck, SCIP_SET *set)
Definition: clock.c:280
#define TRUE
Definition: def.h:63
SCIP_Real SCIPcutGetLPActivityQuot(SCIP_CUT *cut)
Definition: cutpool.c:381
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
SCIP_Longint SCIPcutpoolGetNCalls(SCIP_CUTPOOL *cutpool)
Definition: cutpool.c:882
int SCIPsetCalcMemGrowSize(SCIP_SET *set, int num)
Definition: set.c:5096
void SCIPsepaIncNCutsFoundAtNode(SCIP_SEPA *sepa)
Definition: sepa.c:819
int index
Definition: struct_lp.h:156
static SCIP_RETCODE cutpoolDelCut(SCIP_CUTPOOL *cutpool, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_CUT *cut)
Definition: cutpool.c:570
int SCIPcutpoolGetMaxNCuts(SCIP_CUTPOOL *cutpool)
Definition: cutpool.c:862
static SCIP_RETCODE cutFree(SCIP_CUT **cut, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_LP *lp)
Definition: cutpool.c:323
#define BMSfreeMemory(ptr)
Definition: memory.h:100
SCIP_Longint processedlp
SCIP_RETCODE SCIPcutpoolFree(SCIP_CUTPOOL **cutpool, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_LP *lp)
Definition: cutpool.c:439
int nlpcols
Definition: struct_lp.h:225
internal methods for LP management
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition: misc.c:2015
#define SCIP_DEFAULT_EPSILON
Definition: def.h:141
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:16522
SCIP_Real * vals
Definition: struct_lp.h:218
SCIP_RETCODE SCIPcutpoolDelRow(SCIP_CUTPOOL *cutpool, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_ROW *row)
Definition: cutpool.c:639
void SCIProwSort(SCIP_ROW *row)
Definition: lp.c:5836
SCIP_RETCODE SCIPcutpoolAddNewRow(SCIP_CUTPOOL *cutpool, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_ROW *row)
Definition: cutpool.c:515
#define SCIPhashFour(a, b, c, d)
Definition: pub_misc.h:473
#define SCIPerrorMessage
Definition: pub_message.h:45
SCIP_Longint lpcount
Definition: struct_stat.h:168
static SCIP_RETCODE cutCreate(SCIP_CUT **cut, BMS_BLKMEM *blkmem, SCIP_ROW *row)
Definition: cutpool.c:297
SCIP_COL ** cols
Definition: struct_lp.h:216
#define SCIPcombineThreeInt(a, b, c)
Definition: pub_misc.h:479
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:16420
#define SCIPpositiveRealHashCode(x, n)
Definition: pub_misc.h:486
SCIP_Real minval
Definition: struct_lp.h:201
static SCIP_DECL_HASHKEYVAL(hashKeyValCut)
Definition: cutpool.c:233
SCIP_Real lhs
Definition: struct_lp.h:193
SCIP_Longint processedlpsol
int SCIPsepastoreGetNCuts(SCIP_SEPASTORE *sepastore)
Definition: sepastore.c:1328
SCIP_Real SCIPclockGetTime(SCIP_CLOCK *clck)
Definition: clock.c:428
datastructures for storing cuts in a cut pool
#define NULL
Definition: lpi_spx1.cpp:137
SCIP_CONSHDLR * SCIProwGetOriginCons(SCIP_ROW *row)
Definition: lp.c:16460
#define REALABS(x)
Definition: def.h:159
int maxidx
Definition: struct_lp.h:232
SCIP_ROW * SCIPcutGetRow(SCIP_CUT *cut)
Definition: cutpool.c:357
internal methods for global SCIP settings
#define SCIP_CALL(x)
Definition: def.h:306
SCIP_RETCODE SCIPcutpoolClear(SCIP_CUTPOOL *cutpool, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_LP *lp)
Definition: cutpool.c:465
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2384
SCIP_CUT ** SCIPcutpoolGetCuts(SCIP_CUTPOOL *cutpool)
Definition: cutpool.c:842
int SCIPcutpoolGetNCuts(SCIP_CUTPOOL *cutpool)
Definition: cutpool.c:852
internal methods for storing separated cuts
SCIP_Bool SCIProwIsModifiable(SCIP_ROW *row)
Definition: lp.c:16430
SCIP_Bool SCIProwIsSolEfficacious(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat, SCIP_SOL *sol, SCIP_Bool root)
Definition: lp.c:6643
SCIP_RETCODE SCIProwRelease(SCIP_ROW **row, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_LP *lp)
Definition: lp.c:5172
SCIP_RETCODE SCIPclockCreate(SCIP_CLOCK **clck, SCIP_CLOCKTYPE clocktype)
Definition: clock.c:160
void SCIPconshdlrIncNCutsFound(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4799
SCIP_RETCODE SCIPcutpoolAddRow(SCIP_CUTPOOL *cutpool, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_ROW *row)
Definition: cutpool.c:491
#define BMSfreeBlockMemory(mem, ptr)
Definition: memory.h:419
public data structures and miscellaneous methods
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_SOL *sol, SCIP_ROW *cut, SCIP_Bool forcecut, SCIP_Bool root, SCIP_Bool *infeasible)
Definition: sepastore.c:406
#define SCIP_Bool
Definition: def.h:61
int numminval
Definition: struct_lp.h:234
void SCIPclockFree(SCIP_CLOCK **clck)
Definition: clock.c:175
#define MAX(x, y)
Definition: tclique_def.h:75
#define SCIP_HASHSIZE_CUTPOOLS_SMALL
Definition: def.h:229
#define SCIPsetDebugMsg
Definition: set.h:1870
int minidx
Definition: struct_lp.h:231
SCIP_RETCODE SCIPcutpoolCreate(SCIP_CUTPOOL **cutpool, BMS_BLKMEM *blkmem, SCIP_SET *set, int agelimit, SCIP_Bool globalcutpool)
Definition: cutpool.c:402
unsigned int lpcolssorted
Definition: struct_lp.h:238
internal methods for storing cuts in a cut pool
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2315
int firstunprocessedsol
SCIP_CLOCK * poolclock
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2065
void SCIProwLock(SCIP_ROW *row)
Definition: lp.c:5198
SCIP_Real maxval
Definition: struct_lp.h:200
SCIP_Real rhs
Definition: struct_lp.h:194
SCIP_Longint ncalls
SCIP_Bool SCIProwIsLPEfficacious(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp, SCIP_Bool root)
Definition: lp.c:6584
unsigned int inglobalcutpool
Definition: struct_lp.h:249
public methods for message output
SCIP_Longint ncutsfound
SCIP_Real SCIProwGetLPFeasibility(SCIP_ROW *row, SCIP_SET *set, SCIP_STAT *stat, SCIP_LP *lp)
Definition: lp.c:6074
#define SCIP_Real
Definition: def.h:135
internal methods for problem statistics
#define MIN(x, y)
Definition: memory.c:75
#define BMSallocMemory(ptr)
Definition: memory.h:74
#define BMSreallocMemoryArray(ptr, num)
Definition: memory.h:82
internal methods for constraints and constraint handlers
void SCIPsepaIncNCutsFound(SCIP_SEPA *sepa)
Definition: sepa.c:809
SCIP_RETCODE SCIPcutpoolSeparate(SCIP_CUTPOOL *cutpool, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_EVENTQUEUE *eventqueue, SCIP_EVENTFILTER *eventfilter, SCIP_LP *lp, SCIP_SEPASTORE *sepastore, SCIP_SOL *sol, SCIP_Bool cutpoolisdelayed, SCIP_Bool root, SCIP_RESULT *result)
Definition: cutpool.c:668
#define SCIP_Longint
Definition: def.h:120
SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2366
SCIP_Real SCIProwGetMaxval(SCIP_ROW *row, SCIP_SET *set)
Definition: lp.c:6479
#define BMSallocBlockMemory(mem, ptr)
Definition: memory.h:406
SCIP_Real SCIPcutpoolGetTime(SCIP_CUTPOOL *cutpool)
Definition: cutpool.c:872
SCIP_Bool globalcutpool
int SCIPcutGetAge(SCIP_CUT *cut)
Definition: cutpool.c:367
common defines and data types used in all packages of SCIP
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:392
unsigned int validminmaxidx
Definition: struct_lp.h:241
#define SCIPcombineTwoInt(a, b)
Definition: pub_misc.h:477
#define SCIP_ALLOC(x)
Definition: def.h:317
unsigned int nonlpcolssorted
Definition: struct_lp.h:239
SCIP_Longint SCIProwGetNLPsAfterCreation(SCIP_ROW *row)
Definition: lp.c:16554
static SCIP_Bool cutIsAged(SCIP_CUT *cut, int agelimit)
Definition: cutpool.c:346
static SCIP_DECL_HASHGETKEY(hashGetKeyCut)
Definition: cutpool.c:51
static SCIP_DECL_HASHKEYEQ(hashKeyEqCut)
Definition: cutpool.c:65
static SCIP_RETCODE cutpoolEnsureCutsMem(SCIP_CUTPOOL *cutpool, SCIP_SET *set, int num)
Definition: cutpool.c:267
int len
Definition: struct_lp.h:224
int age
Definition: struct_lp.h:235
void SCIProwUnlock(SCIP_ROW *row)
Definition: lp.c:5213