sepa_gmi.c
Go to the documentation of this file.
24 * This file implements a Gomory Mixed-Integer (GMI) cuts generator that reads cuts from the simplex tableau, applying
27 * \sum_{j \in J_I : f_j \leq f_0} f_j x_j + \sum_{j \in J_I : f_j > f_0} f_0 \frac{1-f_j}{1 - f_0} x_j +
28 * \sum_{j \in J_C : a_j \geq 0} a_j x_j - \sum_{j \in J_C : a_j < 0} f_0 \frac{a_j}{1-f_0} x_j \geq f_0.
30 * Here, \f$J_I\f$ and \f$J_C \subseteq \{1, \ldots, n\}\f$ are the indices of integer and continuous non basic
31 * variables, respectively. The tableaux row is given by \f$a_j\f$ and its right hand side is \f$a_0\f$. The values
32 * \f$f_j\f$ for \f$j = 0, \ldots, n\f$ denote the fractional values of the tableaux row and rhs, i.e., \f$f_j = a_j -
35 * Here is a brief description of the simplex tableau that we can expect from the SCIP LP interfaces:
37 * - Nonbasic columns can be at lower or upper bound, or they can be nonbasic at zero if they are free. Nonbasic columns
38 * at the upper bound must be flipped. Nonbasic free variables at zero are currently untested in the cut generator,
41 * - Nonbasic rows can be at lower or upper bound, depending on whether the lower or upper bound of the row is
42 * attained. SCIP always adds slack/surplus variables with a coefficient of +1: the slack variable is nonnegative in
43 * case of a <= constraint, it is nonpositive in case of a >= or ranged constraint. Therefore, slack variables
44 * corresponding to >= or ranged constraints must be flipped if the row is at its lower bound. (Ranged constraints at
47 * Generated cuts are modified and their numerical properties are checked before being added to the LP relaxation.
54 * In addition to the routines described in the paper above, here we additionally check the support of the cutting
57 * @todo Check whether it is worth rescaling the cut to have integral coefficients on integer variables. This may lead
62 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
76 #define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
78 #define DEFAULT_MAXROUNDS 5 /**< maximal number of Gomory separation rounds per node (-1: unlimited) */
79 #define DEFAULT_MAXROUNDSROOT 30 /**< maximal number of Gomory separation rounds in the root node (-1: unlimited) */
80 #define DEFAULT_MAXSEPACUTS -1 /**< maximal number of Gomory cuts separated per separation round */
81 #define DEFAULT_MAXSEPACUTSROOT -1 /**< maximal number of Gomory cuts separated per separation round in root node */
82 #define DEFAULT_DYNAMICCUTS TRUE /**< should generated cuts be removed from the LP if they are no longer tight? */
85 #define DEFAULT_AWAY 0.005 /**< minimal fractionality of a basic variable in order to try GMI cut - default */
90 #define DEFAULT_MAX_DYN 1.0e+6 /**< maximal valid range max(|weights|)/min(|weights|) of cut coefficients - default */
91 #define DEFAULT_MAX_SUPP_ABS 1000 /**< maximum cut support - absolute value in the formula - default */
92 #define DEFAULT_MAX_SUPP_REL 0.1 /**< maximum cut support - relative value in the formula - default */
99 int maxroundsroot; /**< maximal number of Gomory separation rounds in the root node (-1: unlimited) */
101 int maxsepacutsroot; /**< maximal number of Gomory cuts separated per separation round in root node */
103 SCIP_Bool dynamiccuts; /**< should generated cuts be removed from the LP if they are no longer tight? */
110 SCIP_Real maxdynamism; /**< maximal valid range max(|weights|)/min(|weights|) of cut coefficients */
120 /** Modify the cut to make it numerically safer, and packs it from dense format to sparse format.
122 * See paper "On the safety of Gomory cut generators" by Cornuejols, Margot, Nannicini for more information. Returns
134 int* cutnz, /**< pointer to store the number of nonzero elements in the cut in sparse format on output */
135 SCIP_Real* cutrhs /**< pointer to store the rhs of the cut, initialized to original value, modified */
160 /* Cycle over small elements that are not zero. If the element is zero, it will be discarded anyway. */
199 * See paper "On the safety of Gomory cut generators" by Cornuejols, Margot, Nannicini for more information. Returns
212 SCIP_Real* cutact /**< pointer to store activity of the cut at the current LP optimum will go here on output */
230 SCIPdebugMsg(scip, "Cut too dense (%d > %d).\n", cutnz, (int) (ncols * sepadata->maxsupprel + sepadata->maxsuppabs));
261 /** Method to obtain a GMI in the space of the original variables from a row of the simplex tableau.
263 * Returns TRUE if cut is successfully created, FALSE if no cut was generated or if it should be discarded. If the
264 * function returns FALSE, the contents of cutcoefs, cutind, cutnz, cutrhs, cutact may be garbage.
276 SCIP_Real rowrhs, /**< rhs of the tableau row, i.e., corresponding element in the LP solution */
281 SCIP_Real* cutact, /**< pointer to store cut activity at the current LP optimum - only meaningful if returns TRUE */
317 /* Generate cut coefficients for the original variables. We first use workcoefs to store the cut in dense form, then
347 /* If cutelem < 0, then we know SCIPisZero(scip, cutelem) is true and hope it doesn't do much damage. */
404 /* But if this is a >= or ranged constraint at the lower bound, we have to flip the row element. */
409 /* Take element if nonbasic at upper bound - see notes at beginning of file: only nonpositive slack variables
410 * can be nonbasic at upper, therefore they should be flipped twice and we can take the element directly. */
423 /* Check if row is integral and will stay integral through the Branch-and-Cut tree; if so, strengthen
427 /* If cutelem < 0, then we know SCIPisZero(scip, cutelem) is true and hope it doesn't do much damage. */
508 success = modifyAndPackCut(scip, sepadata, ncols, cols, workcoefs, cutcoefs, cutind, cutnz, cutrhs);
511 success = checkNumerics(scip, sepadata, ncols, cols, cutcoefs, cutind, *cutnz, *cutrhs, cutact);
618 if( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot) || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) )
656 for( i = 0; i < nrows && ncuts < maxsepacuts && ! SCIPisStopped(scip) && *result != SCIP_CUTOFF; ++i )
665 SCIPdebugMsg(scip, "Row %d basic variable %d with value %f\n", i, basisind[i], (c >= 0) ? SCIPcolGetPrimsol(cols[c]) : SCIPgetRowActivity(scip, rows[-c-1]));
677 if( (SCIPfeasFrac(scip, primsol) >= sepadata->away) && (SCIPfeasFrac(scip, primsol) <= 1.0 - sepadata->away) )
679 SCIPdebugMsg(scip, "trying Gomory cut for col <%s> [%g] row %i\n", SCIPvarGetName(var), primsol, i);
697 if( (SCIPfeasFrac(scip, primsol) >= sepadata->away) && (SCIPfeasFrac(scip, primsol) <= 1.0 - sepadata->away) )
718 /* this is an approximation (one could also pass over coefficients and check whether local rows have been used): */
722 success = getGMIFromRow(scip, sepadata, ncols, nrows, cols, rows, binvrow, binvarow, primsol, cutcoefs, cutind, &cutnz, &cutrhs, &cutact, workcoefs);
738 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), cutrhs, cutislocal, FALSE, sepadata->dynamiccuts) );
767 SCIPdebugMsg(scip, " -> found Gomory cut <%s>: act=%f, rhs=%f, norm=%f, eff=%f, min=%f, max=%f (range=%f)\n",
830 SCIP_CALL( SCIPincludeSepaBasic(scip, &sepa, SEPA_NAME, SEPA_DESC, SEPA_PRIORITY, SEPA_FREQ, SEPA_MAXBOUNDDIST,
Definition: type_result.h:33
SCIP_RETCODE SCIPgetLPBInvRow(SCIP *scip, int r, SCIP_Real *coefs, int *inds, int *ninds)
Definition: scip_lp.c:717
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1547
Definition: struct_scip.h:58
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1570
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1607
Definition: struct_var.h:198
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
Definition: scip_numerics.c:940
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition: scip_prob.c:1918
Definition: type_result.h:40
Definition: struct_sepa.h:37
SCIP_RETCODE SCIPgetLPColsData(SCIP *scip, SCIP_COL ***cols, int *ncols)
Definition: scip_lp.c:495
SCIP_RETCODE SCIPsetSepaCopy(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPACOPY((*sepacopy)))
Definition: scip_sepa.c:220
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_param.c:155
Definition: struct_lp.h:126
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:161
static SCIP_Bool modifyAndPackCut(SCIP *scip, SCIP_SEPADATA *sepadata, int ncols, SCIP_COL **cols, SCIP_Real *densecoefs, SCIP_Real *sparsecoefs, int *cutind, int *cutnz, SCIP_Real *cutrhs)
Definition: sepa_gmi.c:126
Definition: type_result.h:35
Definition: type_retcode.h:33
SCIP_Real SCIPgetRowLPActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1899
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:294
Definition: type_lp.h:34
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_sepa.c:178
SCIP_RETCODE SCIPgetLPBInvARow(SCIP *scip, int r, SCIP_Real *binvrow, SCIP_Real *coefs, int *inds, int *ninds)
Definition: scip_lp.c:788
public data structures and miscellaneous methods
static SCIP_Bool getGMIFromRow(SCIP *scip, SCIP_SEPADATA *sepadata, int ncols, int nrows, SCIP_COL **cols, SCIP_ROW **rows, SCIP_Real *binvrow, SCIP_Real *binvarow, SCIP_Real rowrhs, SCIP_Real *cutcoefs, int *cutind, int *cutnz, SCIP_Real *cutrhs, SCIP_Real *cutact, SCIP_Real *workcoefs)
Definition: sepa_gmi.c:267
Gomory Mixed-Integer Cuts.
Definition: struct_lp.h:192
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_lp.c:1365
SCIP_Real SCIPgetCutEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:138
static SCIP_Bool checkNumerics(SCIP *scip, SCIP_SEPADATA *sepadata, int ncols, SCIP_COL **cols, SCIP_Real *cutcoefs, int *cutind, int cutnz, SCIP_Real cutrhs, SCIP_Real *cutact)
Definition: sepa_gmi.c:203
SCIP_RETCODE SCIPsetSepaFree(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAFREE((*sepafree)))
Definition: scip_sepa.c:236
Definition: type_lpi.h:81
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2099
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip_numerics.c:542
Definition: type_lpi.h:82
SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition: scip_lp.c:573
Definition: objbenders.h:33
Definition: type_lpi.h:84
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_param.c:211
Definition: type_lpi.h:83
Definition: type_result.h:39
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_param.c:129
Definition: type_var.h:58