Scippy

SCIP

Solving Constraint Integer Programs

sepa_gomory.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 sepa_gomory.c
17  * @brief Gomory MIR Cuts
18  * @author Tobias Achterberg
19  * @author Stefan Heinz
20  * @author Domenico Salvagnin
21  * @author Marc Pfetsch
22  */
23 
24 /**@todo try k-Gomory-cuts (s. Cornuejols: K-Cuts: A Variation of Gomory Mixed Integer Cuts from the LP Tableau)
25  *
26  * @todo Try cuts on the objective tableau row.
27  *
28  * @todo Also try negative basis inverse row?
29  *
30  * @todo It happens that the SCIPcalcMIR() function returns with the same cut for different calls. Check if this is a
31  * bug or do not use it for the MIP below and turn off presolving and all heuristics:
32  *
33  * Max y
34  * Subject to
35  * c1: -x + y <= 1
36  * c2: 2x + 3y <= 12
37  * c3: 3x + 2y <= 12
38  * Bounds
39  * 0 <= x
40  * 0 <= y
41  * General
42  * x
43  * y
44  * END
45  */
46 
47 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
48 
49 #include <assert.h>
50 #include <string.h>
51 
52 #include "scip/sepa_gomory.h"
53 #include "scip/pub_misc.h"
54 #include "scip/pub_lp.h"
55 
56 #define SEPA_NAME "gomory"
57 #define SEPA_DESC "Gomory MIR cuts separator"
58 #define SEPA_PRIORITY -1000
59 #define SEPA_FREQ 0
60 #define SEPA_MAXBOUNDDIST 0.0
61 #define SEPA_USESSUBSCIP FALSE /**< does the separator use a secondary SCIP instance? */
62 #define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
63 
64 #define DEFAULT_MAXROUNDS 5 /**< maximal number of gomory separation rounds per node (-1: unlimited) */
65 #define DEFAULT_MAXROUNDSROOT 10 /**< maximal number of gomory separation rounds in the root node (-1: unlimited) */
66 #define DEFAULT_MAXSEPACUTS 50 /**< maximal number of gomory cuts separated per separation round */
67 #define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of gomory cuts separated per separation round in root node */
68 #define DEFAULT_MAXRANK 3 /**< maximal rank of a gomory cut that could not be scaled to integral coefficients (-1: unlimited) */
69 #define DEFAULT_MAXRANKINTEGRAL -1 /**< maximal rank of a gomory cut that could be scaled to integral coefficients (-1: unlimited) */
70 #define DEFAULT_DYNAMICCUTS TRUE /**< should generated cuts be removed from the LP if they are no longer tight? */
71 #define DEFAULT_MAXWEIGHTRANGE 1e+04 /**< maximal valid range max(|weights|)/min(|weights|) of row weights */
72 #define DEFAULT_AWAY 0.01 /**< minimal integrality violation of a basis variable in order to try Gomory cut */
73 #define DEFAULT_MAKEINTEGRAL TRUE /**< try to scale all cuts to integral coefficients */
74 #define DEFAULT_FORCECUTS TRUE /**< if conversion to integral coefficients failed still consider the cut */
75 #define DEFAULT_SEPARATEROWS TRUE /**< separate rows with integral slack */
76 #define DEFAULT_DELAYEDCUTS TRUE /**< should cuts be added to the delayed cut pool? */
77 #define DEFAULT_SIDETYPEBASIS FALSE /**< choose side types of row (lhs/rhs) based on basis information? */
78 #define DEFAULT_RANDSEED 53 /**< initial random seed */
79 
80 #define BOUNDSWITCH 0.9999 /**< threshold for bound switching - see SCIPcalcMIR() */
81 #define USEVBDS TRUE /**< use variable bounds - see SCIPcalcMIR() */
82 #define ALLOWLOCAL TRUE /**< allow to generate local cuts - see SCIPcalcMIR() */
83 #define FIXINTEGRALRHS FALSE /**< try to generate an integral rhs - see SCIPcalcMIR() */
84 #define MAKECONTINTEGRAL FALSE /**< convert continuous variable to integral variables in SCIPmakeRowIntegral() */
85 
86 #define MAXAGGRLEN(nvars) (0.1*(nvars)+1000) /**< maximal length of base inequality */
87 
88 
89 /** separator data */
90 struct SCIP_SepaData
91 {
92  SCIP_RANDNUMGEN* randnumgen; /**< random number generator */
93  SCIP_Real maxweightrange; /**< maximal valid range max(|weights|)/min(|weights|) of row weights */
94  SCIP_Real away; /**< minimal integrality violation of a basis variable in order to try Gomory cut */
95  int maxrounds; /**< maximal number of gomory separation rounds per node (-1: unlimited) */
96  int maxroundsroot; /**< maximal number of gomory separation rounds in the root node (-1: unlimited) */
97  int maxsepacuts; /**< maximal number of gomory cuts separated per separation round */
98  int maxsepacutsroot; /**< maximal number of gomory cuts separated per separation round in root node */
99  int maxrank; /**< maximal rank of a gomory cut that could not be scaled to integral coefficients (-1: unlimited) */
100  int maxrankintegral; /**< maximal rank of a gomory cut that could be scaled to integral coefficients (-1: unlimited) */
101  int lastncutsfound; /**< total number of cuts found after last call of separator */
102  SCIP_Bool dynamiccuts; /**< should generated cuts be removed from the LP if they are no longer tight? */
103  SCIP_Bool makeintegral; /**< try to scale all cuts to integral coefficients */
104  SCIP_Bool forcecuts; /**< if conversion to integral coefficients failed still consider the cut */
105  SCIP_Bool separaterows; /**< separate rows with integral slack */
106  SCIP_Bool delayedcuts; /**< should cuts be added to the delayed cut pool? */
107  SCIP_Bool sidetypebasis; /**< choose side types of row (lhs/rhs) based on basis information? */
108 };
109 
110 
111 /** returns TRUE if the cut can be taken, otherwise FALSE if there some numerical evidences */
112 static
114  SCIP* scip, /**< SCIP data structure */
115  SCIP_SEPADATA* sepadata, /**< data of the separator */
116  SCIP_ROW* cut, /**< cut to check */
117  SCIP_Longint maxdnom, /**< maximal denominator to use for scaling */
118  SCIP_Real maxscale, /**< maximal scaling factor */
119  SCIP_Bool* useful /**< pointer to store if the cut is useful */
120  )
121 {
122  SCIP_Bool madeintegral;
123 
124  madeintegral = FALSE;
125  (*useful) = FALSE;
126 
127  if( sepadata->makeintegral )
128  {
129  /* try to scale the cut to integral values */
130  SCIP_CALL( SCIPmakeRowIntegral(scip, cut, -SCIPepsilon(scip), SCIPsumepsilon(scip),
131  maxdnom, maxscale, MAKECONTINTEGRAL, &madeintegral) );
132 
133  if( !madeintegral && !sepadata->forcecuts )
134  return SCIP_OKAY;
135 
136  /* in case the right hand side is plus infinity (due to scaling) the cut is useless so we are not taking it at all
137  */
138  if( madeintegral && SCIPisInfinity(scip, SCIProwGetRhs(cut)) )
139  return SCIP_OKAY;
140  }
141 
142  /* discard integral cut if the rank is too high */
143  if( madeintegral && sepadata->maxrankintegral != -1 && (SCIProwGetRank(cut) > sepadata->maxrankintegral) )
144  return SCIP_OKAY;
145 
146  /* discard cut if the rank is too high */
147  if( !madeintegral && (sepadata->maxrank != -1) && (SCIProwGetRank(cut) > sepadata->maxrank) )
148  return SCIP_OKAY;
149 
150  (*useful) = TRUE;
151 
152  return SCIP_OKAY;
153 }
154 
155 
156 /*
157  * Callback methods
158  */
159 
160 /** copy method for separator plugins (called when SCIP copies plugins) */
161 static
162 SCIP_DECL_SEPACOPY(sepaCopyGomory)
163 { /*lint --e{715}*/
164  assert(scip != NULL);
165  assert(sepa != NULL);
166  assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
167 
168  /* call inclusion method of separator */
170 
171  return SCIP_OKAY;
172 }
173 
174 /** destructor of separator to free user data (called when SCIP is exiting) */
175 /**! [SnippetSepaFreeGomory] */
176 static
177 SCIP_DECL_SEPAFREE(sepaFreeGomory)
178 { /*lint --e{715}*/
179  SCIP_SEPADATA* sepadata;
180 
181  assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
182 
183  /* free separator data */
184  sepadata = SCIPsepaGetData(sepa);
185  assert(sepadata != NULL);
186 
187  SCIPfreeBlockMemory(scip, &sepadata);
188 
189  SCIPsepaSetData(sepa, NULL);
190 
191  return SCIP_OKAY;
192 }
193 /**! [SnippetSepaFreeGomory] */
194 
195 /** initialization method of separator (called after problem was transformed) */
196 static
197 SCIP_DECL_SEPAINIT(sepaInitGomory)
198 {
199  SCIP_SEPADATA* sepadata;
200 
201  sepadata = SCIPsepaGetData(sepa);
202  assert(sepadata != NULL);
203 
204  /* create and initialize random number generator */
206 
207  return SCIP_OKAY;
208 }
209 
210 /** deinitialization method of separator (called before transformed problem is freed) */
211 static
212 SCIP_DECL_SEPAEXIT(sepaExitGomory)
213 { /*lint --e{715}*/
214  SCIP_SEPADATA* sepadata;
215 
216  sepadata = SCIPsepaGetData(sepa);
217  assert(sepadata != NULL);
218 
219  SCIPrandomFree(&sepadata->randnumgen);
220 
221  return SCIP_OKAY;
222 }
223 
224 
225 /** LP solution separation method of separator */
226 static
227 SCIP_DECL_SEPAEXECLP(sepaExeclpGomory)
228 { /*lint --e{715}*/
229  SCIP_SEPADATA* sepadata;
230  SCIP_VAR** vars;
231  SCIP_COL** cols;
232  SCIP_ROW** rows;
233  SCIP_Real* binvrow;
234  SCIP_Real* cutcoefs;
235  SCIP_Real maxscale;
236  SCIP_Real minfrac;
237  SCIP_Real maxfrac;
238  SCIP_Longint maxdnom;
239  SCIP_Bool cutoff;
240  int* sidetypes = NULL;
241  int* basisind;
242  int* inds;
243  int ninds;
244  int naddedcuts;
245  int nvars;
246  int ncols;
247  int nrows;
248  int ncalls;
249  int depth;
250  int maxdepth;
251  int maxsepacuts;
252  int c;
253  int i;
254 
255  assert(sepa != NULL);
256  assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
257  assert(scip != NULL);
258  assert(result != NULL);
259 
260  *result = SCIP_DIDNOTRUN;
261 
262  sepadata = SCIPsepaGetData(sepa);
263  assert(sepadata != NULL);
264 
265  depth = SCIPgetDepth(scip);
266  ncalls = SCIPsepaGetNCallsAtNode(sepa);
267 
268  minfrac = sepadata->away;
269  maxfrac = 1.0 - sepadata->away;
270 
271  /* only call separator, if we are not close to terminating */
272  if( SCIPisStopped(scip) )
273  return SCIP_OKAY;
274 
275  /* only call the gomory cut separator a given number of times at each node */
276  if( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot)
277  || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) )
278  return SCIP_OKAY;
279 
280  /* only call separator, if an optimal LP solution is at hand */
282  return SCIP_OKAY;
283 
284  /* only call separator, if the LP solution is basic */
285  if( !SCIPisLPSolBasic(scip) )
286  return SCIP_OKAY;
287 
288  /* only call separator, if there are fractional variables */
289  if( SCIPgetNLPBranchCands(scip) == 0 )
290  return SCIP_OKAY;
291 
292  /* get variables data */
293  SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
294 
295  /* get LP data */
296  SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
297  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
298  if( ncols == 0 || nrows == 0 )
299  return SCIP_OKAY;
300 
301 #if 0 /* if too many columns, separator is usually very slow: delay it until no other cuts have been found */
302  if( ncols >= 50*nrows )
303  return SCIP_OKAY;
304 
305  if( ncols >= 5*nrows )
306  {
307  int ncutsfound;
308 
309  ncutsfound = SCIPgetNCutsFound(scip);
310  if( ncutsfound > sepadata->lastncutsfound || !SCIPsepaWasLPDelayed(sepa) )
311  {
312  sepadata->lastncutsfound = ncutsfound;
313  *result = SCIP_DELAYED;
314  return SCIP_OKAY;
315  }
316  }
317 #endif
318 
319  /* set the maximal denominator in rational representation of gomory cut and the maximal scale factor to
320  * scale resulting cut to integral values to avoid numerical instabilities
321  */
322  /**@todo find better but still stable gomory cut settings: look at dcmulti, gesa3, khb0525, misc06, p2756 */
323  maxdepth = SCIPgetMaxDepth(scip);
324  if( depth == 0 )
325  {
326  maxdnom = 1000;
327  maxscale = 1000.0;
328  }
329  else if( depth <= maxdepth/4 )
330  {
331  maxdnom = 1000;
332  maxscale = 1000.0;
333  }
334  else if( depth <= maxdepth/2 )
335  {
336  maxdnom = 100;
337  maxscale = 100.0;
338  }
339  else
340  {
341  maxdnom = 10;
342  maxscale = 10.0;
343  }
344 
345  /* allocate temporary memory */
346  SCIP_CALL( SCIPallocBufferArray(scip, &cutcoefs, nvars) );
347  SCIP_CALL( SCIPallocBufferArray(scip, &basisind, nrows) );
348  SCIP_CALL( SCIPallocBufferArray(scip, &binvrow, nrows) );
349  SCIP_CALL( SCIPallocBufferArray(scip, &inds, nrows) );
350  if ( sepadata->sidetypebasis )
351  {
352  SCIP_CALL( SCIPallocBufferArray(scip, &sidetypes, nrows) );
353  }
354 
355  /* get basis indices */
356  SCIP_CALL( SCIPgetLPBasisInd(scip, basisind) );
357 
358  /* permute basis indices to reduce performance variability */
359  SCIPrandomPermuteIntArray(sepadata->randnumgen, basisind, 0, nrows);
360 
361  /* get the maximal number of cuts allowed in a separation round */
362  if( depth == 0 )
363  maxsepacuts = sepadata->maxsepacutsroot;
364  else
365  maxsepacuts = sepadata->maxsepacuts;
366 
367  SCIPdebugMsg(scip, "searching gomory cuts: %d cols, %d rows, maxdnom=%" SCIP_LONGINT_FORMAT ", maxscale=%g, maxcuts=%d\n",
368  ncols, nrows, maxdnom, maxscale, maxsepacuts);
369 
370  cutoff = FALSE;
371  naddedcuts = 0;
372 
373  /* for all basic columns belonging to integer variables, try to generate a gomory cut */
374  for( i = 0; i < nrows && naddedcuts < maxsepacuts && !SCIPisStopped(scip) && !cutoff; ++i )
375  {
376  SCIP_Bool tryrow;
377 
378  tryrow = FALSE;
379  c = basisind[i];
380  if( c >= 0 )
381  {
382  SCIP_VAR* var;
383 
384  assert(c < ncols);
385  var = SCIPcolGetVar(cols[c]);
387  {
388  SCIP_Real primsol;
389 
390  primsol = SCIPcolGetPrimsol(cols[c]);
391  assert(SCIPgetVarSol(scip, var) == primsol); /*lint !e777*/
392 
393  if( SCIPfeasFrac(scip, primsol) >= minfrac )
394  {
395  SCIPdebugMsg(scip, "trying gomory cut for col <%s> [%g]\n", SCIPvarGetName(var), primsol);
396  tryrow = TRUE;
397  }
398  }
399  }
400  else if( sepadata->separaterows )
401  {
402  SCIP_ROW* row;
403 
404  assert(0 <= -c-1 && -c-1 < nrows);
405  row = rows[-c-1];
406  if( SCIProwIsIntegral(row) && !SCIProwIsModifiable(row) )
407  {
408  SCIP_Real primsol;
409 
410  primsol = SCIPgetRowActivity(scip, row);
411  if( SCIPfeasFrac(scip, primsol) >= minfrac )
412  {
413  SCIPdebugMsg(scip, "trying gomory cut for row <%s> [%g]\n", SCIProwGetName(row), primsol);
414  tryrow = TRUE;
415  }
416  }
417  }
418 
419  if( tryrow )
420  {
421  SCIP_Real cutrhs;
422  SCIP_Real cutact;
423  SCIP_Bool success;
424  SCIP_Bool cutislocal;
425  int cutrank;
426 
427  /* get the row of B^-1 for this basic integer variable with fractional solution value */
428  ninds = -1;
429  SCIP_CALL( SCIPgetLPBInvRow(scip, i, binvrow, inds, &ninds) );
430 
431  if ( sepadata->sidetypebasis )
432  {
433  int k;
434 
435  assert( sidetypes != NULL );
436  for (k = 0; k < nrows; ++k)
437  {
438  SCIP_BASESTAT stat;
439  SCIP_ROW* row;
440 
441  row = rows[k];
442  assert( row != NULL );
443 
444  /* for equations take automatic choice */
445  if ( SCIPisEQ(scip, SCIProwGetLhs(row), SCIProwGetRhs(row)) )
446  sidetypes[k] = 0;
447  else
448  {
449  /* for ranged rows use basis status */
450  assert( SCIPisLPSolBasic(scip) );
451  stat = SCIProwGetBasisStatus(row);
452  if ( stat == SCIP_BASESTAT_LOWER )
453  {
454  assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
455  sidetypes[k] = -1;
456  }
457  else if ( stat == SCIP_BASESTAT_UPPER )
458  {
459  assert( ! SCIPisInfinity(scip, SCIProwGetRhs(row)) );
460  sidetypes[k] = 1;
461  }
462  else
463  sidetypes[k] = 0;
464  }
465  }
466  }
467 
468  cutact = 0.0;
469  cutrhs = SCIPinfinity(scip);
470 
471  /* need to ensure that is sparsity information is requested from SCIPgetLPBInvRow
472  * that it is used in SCIPcalcMIR */
473  if( inds != NULL && ninds > -1 )
474  {
475  /* create a MIR cut out of the weighted LP rows using the B^-1 row as weights */
477  (int) MAXAGGRLEN(nvars), sepadata->maxweightrange, minfrac, maxfrac, binvrow, -1.0, inds, ninds, -1,
478  sidetypes, 1.0, NULL, NULL, cutcoefs, &cutrhs, &cutact, &success, &cutislocal, &cutrank) );
479  }
480  else
481  {
482  /* create a MIR cut out of the weighted LP rows using the B^-1 row as weights */
484  (int) MAXAGGRLEN(nvars), sepadata->maxweightrange, minfrac, maxfrac, binvrow, -1.0, NULL, -1, -1,
485  sidetypes, 1.0, NULL, NULL, cutcoefs, &cutrhs, &cutact, &success, &cutislocal, &cutrank) );
486  }
487  assert(ALLOWLOCAL || !cutislocal);
488 
489  /* @todo Currently we are using the SCIPcalcMIR() function to compute the coefficients of the Gomory
490  * cut. Alternatively, we could use the direct version (see thesis of Achterberg formula (8.4)) which
491  * leads to cut a of the form \sum a_i x_i \geq 1. Rumor has it that these cuts are better.
492  */
493 
494  SCIPdebugMsg(scip, " -> success=%u: %g <= %g\n", success, cutact, cutrhs);
495 
496  /* if successful, convert dense cut into sparse row, and add the row as a cut */
497  if( success && SCIPisFeasGT(scip, cutact, cutrhs) )
498  {
499  SCIP_ROW* cut;
500  char cutname[SCIP_MAXSTRLEN];
501  int v;
502 
503  /* construct cut name */
504  if( c >= 0 )
505  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "gom%d_x%d", SCIPgetNLPs(scip), c);
506  else
507  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "gom%d_s%d", SCIPgetNLPs(scip), -c-1);
508 
509  /* create empty cut */
510  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), cutrhs,
511  cutislocal, FALSE, sepadata->dynamiccuts) );
512 
513  /* set cut rank */
514  SCIProwChgRank(cut, cutrank);
515 
516  /* cache the row extension and only flush them if the cut gets added */
518 
519  /* collect all non-zero coefficients */
520  for( v = 0; v < nvars; ++v )
521  {
522  if( !SCIPisZero(scip, cutcoefs[v]) )
523  {
524  SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[v], cutcoefs[v]) );
525  }
526  }
527 
528  if( SCIProwGetNNonz(cut) == 0 )
529  {
530  assert(SCIPisFeasNegative(scip, cutrhs));
531  SCIPdebugMsg(scip, " -> gomory cut detected infeasibility with cut 0 <= %f\n", cutrhs);
532  cutoff = TRUE;
533  }
534  else if( SCIProwGetNNonz(cut) == 1 )
535  {
536  /* add the bound change as cut to avoid that the LP gets modified. that would mean the LP is not flushed
537  * and the method SCIPgetLPBInvRow() fails; SCIP internally will apply that bound change automatically
538  */
539  SCIP_CALL( SCIPaddCut(scip, NULL, cut, TRUE, &cutoff) );
540  naddedcuts++;
541  }
542  else
543  {
544  /* Only take efficacious cuts, except for cuts with one non-zero coefficients (= bound
545  * changes); the latter cuts will be handeled internally in sepastore.
546  */
547  if( SCIPisCutEfficacious(scip, NULL, cut) )
548  {
549  SCIP_Bool useful;
550 
551  assert(success == TRUE);
552  assert(SCIPisInfinity(scip, -SCIProwGetLhs(cut)));
553  assert(!SCIPisInfinity(scip, SCIProwGetRhs(cut)));
554 
555  SCIPdebugMsg(scip, " -> gomory cut for <%s>: act=%f, rhs=%f, eff=%f\n",
556  c >= 0 ? SCIPvarGetName(SCIPcolGetVar(cols[c])) : SCIProwGetName(rows[-c-1]),
557  cutact, cutrhs, SCIPgetCutEfficacy(scip, NULL, cut));
558 
559  SCIP_CALL( evaluateCutNumerics(scip, sepadata, cut, maxdnom, maxscale, &useful) );
560 
561  if( useful )
562  {
563  SCIPdebugMsg(scip, " -> found gomory cut <%s>: act=%f, rhs=%f, norm=%f, eff=%f, min=%f, max=%f (range=%f)\n",
564  cutname, SCIPgetRowLPActivity(scip, cut), SCIProwGetRhs(cut), SCIProwGetNorm(cut),
568 
569  /* flush all changes before adding the cut */
571 
572  /* add global cuts which are not implicit bound changes to the cut pool */
573  if( !cutislocal )
574  {
575  if( sepadata->delayedcuts )
576  {
578  }
579  else
580  {
581  SCIP_CALL( SCIPaddPoolCut(scip, cut) );
582  }
583  }
584  else
585  {
586  /* local cuts we add to the sepastore */
587  SCIP_CALL( SCIPaddCut(scip, NULL, cut, FALSE, &cutoff) );
588  }
589 
590  naddedcuts++;
591  }
592  }
593  }
594 
595  /* release the row */
596  SCIP_CALL( SCIPreleaseRow(scip, &cut) );
597  }
598  }
599  }
600 
601  /* free temporary memory */
602  if ( sepadata->sidetypebasis )
603  {
604  SCIPfreeBufferArray(scip, &sidetypes);
605  }
606  SCIPfreeBufferArray(scip, &inds);
607  SCIPfreeBufferArray(scip, &binvrow);
608  SCIPfreeBufferArray(scip, &basisind);
609  SCIPfreeBufferArray(scip, &cutcoefs);
610 
611  SCIPdebugMsg(scip, "end searching gomory cuts: found %d cuts\n", naddedcuts);
612 
613  sepadata->lastncutsfound = SCIPgetNCutsFound(scip);
614 
615  /* evalute the result of the separation */
616  if( cutoff )
617  *result = SCIP_CUTOFF;
618  else if ( naddedcuts > 0 )
619  *result = SCIP_SEPARATED;
620  else
621  *result = SCIP_DIDNOTFIND;
622 
623  return SCIP_OKAY;
624 }
625 
626 
627 /*
628  * separator specific interface methods
629  */
630 
631 /** creates the Gomory MIR cut separator and includes it in SCIP */
633  SCIP* scip /**< SCIP data structure */
634  )
635 {
636  SCIP_SEPADATA* sepadata;
637  SCIP_SEPA* sepa;
638 
639  /* create separator data */
640  SCIP_CALL( SCIPallocBlockMemory(scip, &sepadata) );
641  sepadata->lastncutsfound = 0;
642 
643  /* include separator */
646  sepaExeclpGomory, NULL,
647  sepadata) );
648 
649  assert(sepa != NULL);
650 
651  /* set non-NULL pointers to callback methods */
652  SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyGomory) );
653  SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeGomory) );
654  SCIP_CALL( SCIPsetSepaInit(scip, sepa, sepaInitGomory) );
655  SCIP_CALL( SCIPsetSepaExit(scip, sepa, sepaExitGomory) );
656 
657  /* add separator parameters */
659  "separating/gomory/maxrounds",
660  "maximal number of gomory separation rounds per node (-1: unlimited)",
661  &sepadata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
663  "separating/gomory/maxroundsroot",
664  "maximal number of gomory separation rounds in the root node (-1: unlimited)",
665  &sepadata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
667  "separating/gomory/maxsepacuts",
668  "maximal number of gomory cuts separated per separation round",
669  &sepadata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
671  "separating/gomory/maxsepacutsroot",
672  "maximal number of gomory cuts separated per separation round in the root node",
673  &sepadata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
675  "separating/gomory/maxrank",
676  "maximal rank of a gomory cut that could not be scaled to integral coefficients (-1: unlimited)",
677  &sepadata->maxrank, FALSE, DEFAULT_MAXRANK, -1, INT_MAX, NULL, NULL) );
679  "separating/gomory/maxrankintegral",
680  "maximal rank of a gomory cut that could be scaled to integral coefficients (-1: unlimited)",
681  &sepadata->maxrankintegral, FALSE, DEFAULT_MAXRANKINTEGRAL, -1, INT_MAX, NULL, NULL) );
683  "separating/gomory/away",
684  "minimal integrality violation of a basis variable in order to try Gomory cut",
685  &sepadata->away, FALSE, DEFAULT_AWAY, 1e-4, 0.5, NULL, NULL) );
687  "separating/gomory/maxweightrange",
688  "maximal valid range max(|weights|)/min(|weights|) of row weights",
689  &sepadata->maxweightrange, TRUE, DEFAULT_MAXWEIGHTRANGE, 1.0, SCIP_REAL_MAX, NULL, NULL) );
691  "separating/gomory/dynamiccuts",
692  "should generated cuts be removed from the LP if they are no longer tight?",
693  &sepadata->dynamiccuts, FALSE, DEFAULT_DYNAMICCUTS, NULL, NULL) );
695  "separating/gomory/makeintegral",
696  "try to scale cuts to integral coefficients",
697  &sepadata->makeintegral, TRUE, DEFAULT_MAKEINTEGRAL, NULL, NULL) );
699  "separating/gomory/forcecuts",
700  "if conversion to integral coefficients failed still consider the cut",
701  &sepadata->forcecuts, TRUE, DEFAULT_FORCECUTS, NULL, NULL) );
703  "separating/gomory/separaterows",
704  "separate rows with integral slack",
705  &sepadata->separaterows, TRUE, DEFAULT_SEPARATEROWS, NULL, NULL) );
707  "separating/gomory/delayedcuts",
708  "should cuts be added to the delayed cut pool?",
709  &sepadata->delayedcuts, TRUE, DEFAULT_DELAYEDCUTS, NULL, NULL) );
711  "separating/gomory/sidetypebasis",
712  "choose side types of row (lhs/rhs) based on basis information?",
713  &sepadata->sidetypebasis, TRUE, DEFAULT_SIDETYPEBASIS, NULL, NULL) );
714 
715  return SCIP_OKAY;
716 }
#define DEFAULT_MAXSEPACUTSROOT
Definition: sepa_gomory.c:67
SCIP_RETCODE SCIPrandomCreate(SCIP_RANDNUMGEN **randnumgen, BMS_BLKMEM *blkmem, unsigned int initialseed)
Definition: misc.c:8693
SCIP_RETCODE SCIPgetLPBInvRow(SCIP *scip, int r, SCIP_Real *coefs, int *inds, int *ninds)
Definition: scip.c:29439
SCIP_RETCODE SCIPincludeSepaGomory(SCIP *scip)
Definition: sepa_gomory.c:632
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30363
static SCIP_RETCODE evaluateCutNumerics(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_ROW *cut, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Bool *useful)
Definition: sepa_gomory.c:113
#define SEPA_PRIORITY
Definition: sepa_gomory.c:58
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30386
enum SCIP_BaseStat SCIP_BASESTAT
Definition: type_lpi.h:86
#define SCIP_MAXSTRLEN
Definition: def.h:225
#define SEPA_DESC
Definition: sepa_gomory.c:57
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip.c:30418
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:16312
#define DEFAULT_MAXROUNDSROOT
Definition: sepa_gomory.c:65
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:16450
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:46409
SCIP_RETCODE SCIPaddDelayedPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:34373
int SCIPgetMaxDepth(SCIP *scip)
Definition: scip.c:42371
#define DEFAULT_DELAYEDCUTS
Definition: sepa_gomory.c:76
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition: scip.c:11554
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:16391
#define FALSE
Definition: def.h:64
#define DEFAULT_MAXROUNDS
Definition: sepa_gomory.c:64
SCIP_BASESTAT SCIProwGetBasisStatus(SCIP_ROW *row)
Definition: lp.c:16439
#define SEPA_MAXBOUNDDIST
Definition: sepa_gomory.c:60
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:46050
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:9340
#define TRUE
Definition: def.h:63
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition: sepa.c:632
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
static SCIP_DECL_SEPAEXIT(sepaExitGomory)
Definition: sepa_gomory.c:212
#define DEFAULT_MAKEINTEGRAL
Definition: sepa_gomory.c:73
#define FIXINTEGRALRHS
Definition: sepa_gomory.c:83
SCIP_RETCODE SCIPcalcMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, int maxmksetcoefs, SCIP_Real maxweightrange, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real *weights, SCIP_Real maxweight, int *weightinds, int nweightinds, int rowlensum, int *sidetypes, SCIP_Real scale, SCIP_Real *mksetcoefs, SCIP_Bool *mksetcoefsvalid, SCIP_Real *mircoef, SCIP_Real *mirrhs, SCIP_Real *cutactivity, SCIP_Bool *success, SCIP_Bool *cutislocal, int *cutrank)
Definition: scip.c:29603
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:21973
#define ALLOWLOCAL
Definition: sepa_gomory.c:82
SCIP_Real SCIPfeasFrac(SCIP *scip, SCIP_Real val)
Definition: scip.c:46481
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45985
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:22003
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:21956
SCIP_RETCODE SCIPgetLPColsData(SCIP *scip, SCIP_COL ***cols, int *ncols)
Definition: scip.c:29217
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip.c:36334
SCIP_RETCODE SCIPsetSepaCopy(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPACOPY((*sepacopy)))
Definition: scip.c:7402
#define SCIPdebugMsg
Definition: scip.h:451
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4237
SCIP_Real SCIPepsilon(SCIP *scip)
Definition: scip.c:45480
SCIP_Real SCIPgetRowMaxCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30621
#define USEVBDS
Definition: sepa_gomory.c:81
SCIP_SEPADATA * SCIPsepaGetData(SCIP_SEPA *sepa)
Definition: sepa.c:543
#define DEFAULT_MAXRANKINTEGRAL
Definition: sepa_gomory.c:69
static SCIP_DECL_SEPAEXECLP(sepaExeclpGomory)
Definition: sepa_gomory.c:227
SCIP_Bool SCIPisLPSolBasic(SCIP *scip)
Definition: scip.c:29392
void SCIPrandomFree(SCIP_RANDNUMGEN **randnumgen)
Definition: misc.c:8710
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip.c:33891
SCIP_Real SCIPcolGetPrimsol(SCIP_COL *col)
Definition: lp.c:16115
#define MAKECONTINTEGRAL
Definition: sepa_gomory.c:84
SCIP_Real SCIPgetRowMinCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30603
#define DEFAULT_MAXSEPACUTS
Definition: sepa_gomory.c:66
#define SEPA_USESSUBSCIP
Definition: sepa_gomory.c:61
int SCIPgetNCutsFound(SCIP *scip)
Definition: scip.c:42178
SCIP_RETCODE SCIPsetSepaExit(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAEXIT((*sepaexit)))
Definition: scip.c:7450
int SCIPsepaGetNCallsAtNode(SCIP_SEPA *sepa)
Definition: sepa.c:759
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:45753
#define DEFAULT_MAXRANK
Definition: sepa_gomory.c:68
#define DEFAULT_FORCECUTS
Definition: sepa_gomory.c:74
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16555
SCIP_Bool SCIProwIsIntegral(SCIP_ROW *row)
Definition: lp.c:16490
void SCIPsepaSetData(SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata)
Definition: sepa.c:553
#define DEFAULT_SEPARATEROWS
Definition: sepa_gomory.c:75
#define NULL
Definition: lpi_spx1.cpp:137
#define DEFAULT_SIDETYPEBASIS
Definition: sepa_gomory.c:77
static SCIP_DECL_SEPAINIT(sepaInitGomory)
Definition: sepa_gomory.c:197
#define SEPA_DELAY
Definition: sepa_gomory.c:62
#define SCIP_CALL(x)
Definition: def.h:316
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46359
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:16401
SCIP_Real SCIPgetRowLPActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30692
SCIP_RETCODE SCIPaddCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip.c:33999
SCIP_Bool SCIProwIsModifiable(SCIP_ROW *row)
Definition: lp.c:16510
#define DEFAULT_DYNAMICCUTS
Definition: sepa_gomory.c:70
SCIP_RETCODE SCIPincludeSepaBasic(SCIP *scip, SCIP_SEPA **sepa, const char *name, const char *desc, int priority, int freq, SCIP_Real maxbounddist, SCIP_Bool usessubscip, SCIP_Bool delay, SCIP_DECL_SEPAEXECLP((*sepaexeclp)), SCIP_DECL_SEPAEXECSOL((*sepaexecsol)), SCIP_SEPADATA *sepadata)
Definition: scip.c:7360
SCIP_Bool SCIPsepaWasLPDelayed(SCIP_SEPA *sepa)
Definition: sepa.c:869
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:21991
public data structures and miscellaneous methods
#define SCIP_Bool
Definition: def.h:61
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip.c:28948
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:42321
#define SEPA_NAME
Definition: sepa_gomory.c:56
void SCIPrandomPermuteIntArray(SCIP_RANDNUMGEN *randnumgen, int *array, int begin, int end)
Definition: misc.c:8764
#define SEPA_FREQ
Definition: sepa_gomory.c:59
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:34094
public methods for LP management
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip.c:30181
unsigned int SCIPinitializeRandomSeed(SCIP *scip, int initialseedvalue)
Definition: scip.c:25561
SCIP_Real SCIPgetCutEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip.c:33868
SCIP_RETCODE SCIPgetLPBasisInd(SCIP *scip, int *basisind)
Definition: scip.c:29411
Gomory MIR Cuts.
#define DEFAULT_MAXWEIGHTRANGE
Definition: sepa_gomory.c:71
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:46061
#define MAXAGGRLEN(nvars)
Definition: sepa_gomory.c:86
int SCIProwGetRank(SCIP_ROW *row)
Definition: lp.c:16480
#define SCIP_REAL_MAX
Definition: def.h:146
static SCIP_DECL_SEPACOPY(sepaCopyGomory)
Definition: sepa_gomory.c:162
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip.c:30290
SCIP_RETCODE SCIPsetSepaFree(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAFREE((*sepafree)))
Definition: scip.c:7418
SCIP_RETCODE SCIPsetSepaInit(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAINIT((*sepainit)))
Definition: scip.c:7434
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:16161
void SCIProwChgRank(SCIP_ROW *row, int rank)
Definition: lp.c:16613
#define SCIP_Real
Definition: def.h:145
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip.c:1138
#define SCIP_Longint
Definition: def.h:130
#define DEFAULT_AWAY
Definition: sepa_gomory.c:72
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16720
#define BOUNDSWITCH
Definition: sepa_gomory.c:80
#define DEFAULT_RANDSEED
Definition: sepa_gomory.c:78
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:46098
SCIP_Real SCIPgetVarSol(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:19529
static SCIP_DECL_SEPAFREE(sepaFreeGomory)
Definition: sepa_gomory.c:177
SCIP_Real SCIPsumepsilon(SCIP *scip)
Definition: scip.c:45494
SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition: scip.c:29295
SCIP_Longint SCIPgetNLPs(SCIP *scip)
Definition: scip.c:41590
SCIP_RETCODE SCIPmakeRowIntegral(SCIP *scip, SCIP_ROW *row, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Bool usecontvars, SCIP_Bool *success)
Definition: scip.c:30561
SCIP_Real SCIProwGetNorm(SCIP_ROW *row)
Definition: lp.c:16367
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4293
struct SCIP_SepaData SCIP_SEPADATA
Definition: type_sepa.h:38
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4211
SCIP_Real SCIPgetRowActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30803