SCIP Doxygen Documentation
Loading...
Searching...
No Matches
sepa_gmi.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-2026 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* This file was written by Giacomo Nannicini, */
24/* Copyright (C) 2012 Singapore University of Technology and Design */
25/* */
26/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
27
28/**@file sepa_gmi.c
29 * @brief Gomory Mixed-Integer Cuts
30 * @author Giacomo Nannicini
31 * @author Marc Pfetsch
32 *
33 * This file implements a Gomory Mixed-Integer (GMI) cuts generator that reads cuts from the simplex tableau, applying
34 * the textbook formula:
35 * \f[
36 * \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 +
37 * \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.
38 * \f]
39 * Here, \f$J_I\f$ and \f$J_C \subseteq \{1, \ldots, n\}\f$ are the indices of integer and continuous non basic
40 * variables, respectively. The tableaux row is given by \f$a_j\f$ and its right hand side is \f$a_0\f$. The values
41 * \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 -
42 * \lfloor a_j \rfloor\f$.
43 *
44 * Here is a brief description of the simplex tableau that we can expect from the SCIP LP interfaces:
45 *
46 * - Nonbasic columns can be at the lower or upper bound, or they can be nonbasic at zero if they are free. Nonbasic columns
47 * at the upper bound must be flipped. Nonbasic free variables at zero are currently untested in the cut generator,
48 * but they should be handled properly anyway.
49 *
50 * - Nonbasic rows can be at lower or upper bound, depending on whether the lower or upper bound of the row is
51 * attained. SCIP always adds slack/surplus variables with a coefficient of +1: the slack variable is nonnegative in
52 * case of a <= constraint, it is nonpositive in case of a >= or ranged constraint. Therefore, slack variables
53 * corresponding to >= or ranged constraints must be flipped if the row is at its lower bound. (Ranged constraints at
54 * the upper bound do not have to be flipped, because the variable is nonpositive.)
55 *
56 * Generated cuts are modified and their numerical properties are checked before being added to the LP relaxation.
57 * Default parameters for cut modification and checking procedures are taken from the paper
58 *
59 * G. Cornuejols, F. Margot, and G. Nannicini:@n
60 * On the safety of Gomory cut generators.@n
61 * Mathematical Programming Computation 5, No. 4 (2013), pp. 345-395.
62 *
63 * In addition to the routines described in the paper above, here we additionally check the support of the cutting
64 * plane.
65 *
66 * @todo Check whether it is worth rescaling the cut to have integral coefficients on integer variables. This may lead
67 * to an integral slack variable, that has stronger cut coefficients in subsequent rounds.
68 */
69
70
71/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
72
73#include "scip/pub_misc.h"
74#include "sepa_gmi.h"
75
76#define SEPA_NAME "gmi"
77#define SEPA_DESC "Gomory Mixed-Integer cuts separator"
78#define SEPA_PRIORITY -1000
79#define SEPA_FREQ 0
80#define SEPA_MAXBOUNDDIST 0.0
81#define SEPA_USESSUBSCIP FALSE /**< does the separator use a secondary SCIP instance? */
82#define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
83
84#define DEFAULT_MAXROUNDS 5 /**< maximal number of GMI separation rounds per node (-1: unlimited) */
85#define DEFAULT_MAXROUNDSROOT 30 /**< maximal number of GMI separation rounds in the root node (-1: unlimited) */
86#define DEFAULT_MAXSEPACUTS -1 /**< maximal number of GMI cuts separated per separation round */
87#define DEFAULT_MAXSEPACUTSROOT -1 /**< maximal number of GMI cuts separated per separation round in root node */
88#define DEFAULT_DYNAMICCUTS TRUE /**< should generated cuts be removed from the LP if they are no longer tight? */
89#define DEFAULT_SEPARATEROWS TRUE /**< separate rows with integral slack? */
90
91#define DEFAULT_AWAY 0.005 /**< minimal fractionality of a basic variable in order to try GMI cut - default */
92#define DEFAULT_MIN_VIOLATION 0.00 /**< minimal violation to accept cut - default */
93#define DEFAULT_EPS_COEFF 1e-11 /**< tolerance for zeroing out small coefficients - default */
94#define DEFAULT_EPS_RELAX_ABS 1e-11 /**< absolute cut rhs relaxation - default */
95#define DEFAULT_EPS_RELAX_REL 1e-13 /**< relative cut rhs relaxation - default */
96#define DEFAULT_MAX_DYN 1.0e+6 /**< maximal valid range max(|weights|)/min(|weights|) of cut coefficients - default */
97#define DEFAULT_MAX_SUPP_ABS 1000 /**< maximum cut support - absolute value in the formula - default */
98#define DEFAULT_MAX_SUPP_REL 0.1 /**< maximum cut support - relative value in the formula - default */
99
100
101/** separator data */
102struct SCIP_SepaData
103{
104 int maxrounds; /**< maximal number of GMI separation rounds per node (-1: unlimited) */
105 int maxroundsroot; /**< maximal number of GMI separation rounds in the root node (-1: unlimited) */
106 int maxsepacuts; /**< maximal number of GMI cuts separated per separation round */
107 int maxsepacutsroot; /**< maximal number of GMI cuts separated per separation round in root node */
108 int lastncutsfound; /**< total number of cuts found after last call of separator */
109 SCIP_Bool dynamiccuts; /**< should generated cuts be removed from the LP if they are no longer tight? */
110 SCIP_Bool separaterows; /**< separate rows with integral slack? */
111 SCIP_Real away; /**< minimal fractionality of a basis variable in order to try GMI cut */
112 SCIP_Real minviolation; /**< minimal violation to accept cut */
113 SCIP_Real epscoeff; /**< tolerance for zeroing out small coefficients */
114 SCIP_Real epsrelaxabs; /**< absolute cut rhs relaxation */
115 SCIP_Real epsrelaxrel; /**< relative cut rhs relaxation */
116 SCIP_Real maxdynamism; /**< maximal valid range max(|weights|)/min(|weights|) of cut coefficients */
117 int maxsuppabs; /**< maximum cut support - absolute value in the formula */
118 SCIP_Real maxsupprel; /**< maximum cut support - relative value in the formula */
119};
120
121
122/*
123 * local methods
124 */
125
126/** Modify the cut to make it numerically safer, and packs it from dense format to sparse format.
127 *
128 * See paper "On the safety of Gomory cut generators" by Cornuejols, Margot, and Nannicini for more information. Returns
129 * TRUE if cut is accepted, FALSE if it is discarded.
130 */
131static
133 SCIP* scip, /**< pointer to the SCIP environment */
134 SCIP_SEPADATA* sepadata, /**< pointer to separator data */
135 int ncols, /**< number of columns in the LP */
136 SCIP_COL** cols, /**< columns of the LP */
137 SCIP_Real* densecoefs, /**< cut in dense format on input */
138 SCIP_Real* sparsecoefs, /**< cut coefficients in sparse format on output */
139 int* cutind, /**< cut indices in sparse format on output */
140 int* cutnz, /**< pointer to store the number of nonzero elements in the cut in sparse format on output */
141 SCIP_Real* cutrhs /**< pointer to store the rhs of the cut, initialized to original value, modified */
142 )
143{
144 SCIP_COL* col;
145 int i;
146 int c;
147
148 assert(scip != NULL);
149 assert(cols != NULL);
150 assert(densecoefs != NULL);
151 assert(sparsecoefs != NULL);
152 assert(cutind != NULL);
153 assert(cutnz != NULL);
154 assert(cutrhs != NULL);
155
156 *cutnz = 0; /* this is the current position in the cut array */
157
158 /* Check each cut coefficient. If it is small, try set it to zero. */
159 for( c = 0; c < ncols; ++c )
160 {
161 col = cols[c];
162 assert(col != NULL);
163 i = SCIPcolGetLPPos(col);
164 assert( 0 <= i );
165
166 /* Cycle over small elements that are not zero. If the element is zero, it will be discarded anyway. */
167 if( EPSZ(densecoefs[i], sepadata->epscoeff) && ! SCIPisZero(scip, densecoefs[i]) )
168 {
169 if( densecoefs[i] > 0.0 )
170 {
171 /* If we would have to modify the rhs by a multiple of infinity, discard the cut altogether. */
172 if( SCIPisInfinity(scip, -SCIPcolGetLb(col)) )
173 return FALSE;
174
175 /* Zero out coefficient and modify rhs to preserve validity and possibly strengthen the cut. */
176 *cutrhs -= densecoefs[i] * SCIPcolGetLb(cols[c]);
177 }
178 else if( densecoefs[i] < 0.0 )
179 {
180 /* If we would have to modify the rhs by a multiple of infinity, discard the cut altogether. */
181 if( SCIPisInfinity(scip, SCIPcolGetUb(col)) )
182 return FALSE;
183
184 /* Zero out coefficient and modify rhs to preserve validity and possibly strengthen the cut. */
185 *cutrhs -= densecoefs[i] * SCIPcolGetUb(cols[c]);
186 }
187 } /* if( EPSZ(densecoefs[i], sepadata->epscoeff) && ! SCIPisZero(densecoefs[i]) ) */
188 else if( ! EPSZ(densecoefs[i], sepadata->epscoeff) )
189 {
190 /* cut coefficient is large enough - keep it and write in sparse form */
191 sparsecoefs[*cutnz] = densecoefs[i];
192 cutind[*cutnz] = c;
193 (*cutnz)++;
194 }
195 } /* for( c = 0; c < ncols; ++c ) */
196
197 /* Relax rhs of the cut */
198 *cutrhs += REALABS(*cutrhs) * sepadata->epsrelaxrel + sepadata->epsrelaxabs;
199
200 return (*cutnz > 0) ? TRUE : FALSE;
201}
202
203/** Check the numerical properties of the cut.
204 *
205 * See paper "On the safety of Gomory cut generators" by Cornuejols, Margot, and Nannicini for more information. Returns
206 * TRUE if cut is accepted, FALSE if it is discarded.
207 */
208static
210 SCIP* scip, /**< pointer to the SCIP environment */
211 SCIP_SEPADATA* sepadata, /**< pointer to separator data */
212 int ncols, /**< number of columns in the LP */
213 SCIP_COL** cols, /**< columns of the LP */
214 SCIP_Real* cutcoefs, /**< cut in sparse format */
215 int* cutind, /**< cut indices in sparse format */
216 int cutnz, /**< number of nonzero elements in the cut in sparse format */
217 SCIP_Real cutrhs, /**< rhs of the cut */
218 SCIP_Real* cutact /**< pointer to store activity of the cut at the current LP optimum will go here on output */
219 )
220{
221 SCIP_Real violation;
222 SCIP_Real mincoef;
223 SCIP_Real maxcoef;
224 int i;
225
226 assert(scip != NULL);
227 assert(cols != NULL);
228 assert(cutcoefs != NULL);
229 assert(cutind != NULL);
230 assert(cutact != NULL);
231 assert(cutnz > 0);
232
233 /* Check maximum support */
234 if( cutnz > ncols * sepadata->maxsupprel + sepadata->maxsuppabs )
235 {
236 SCIPdebugMsg(scip, "Cut too dense (%d > %d).\n", cutnz, (int) (ncols * sepadata->maxsupprel + sepadata->maxsuppabs));
237 return FALSE;
238 }
239
240 /* Compute cut violation and dynamism */
241 mincoef = SCIP_REAL_MAX;
242 maxcoef = 0.0;
243 *cutact = 0.0;
244
245 for( i = 0; i < cutnz; ++i )
246 {
247 mincoef = MIN(mincoef, REALABS(cutcoefs[i])); /*lint !e666*/
248 maxcoef = MAX(maxcoef, REALABS(cutcoefs[i])); /*lint !e666*/
249 *cutact += cutcoefs[i] * SCIPcolGetPrimsol(cols[cutind[i]]);
250 }
251
252 /* Check dynamism */
253 if( maxcoef > mincoef * sepadata->maxdynamism )
254 {
255 SCIPdebugMsg(scip, "Cut too dynamic (%g > %g).\n", maxcoef, mincoef * sepadata->maxdynamism);
256 return FALSE;
257 }
258
259 /* Check minimum violation */
260 violation = *cutact - cutrhs;
261 if( REALABS(cutrhs) > 1.0 )
262 violation /= REALABS(cutrhs);
263
264 return (violation >= sepadata->minviolation) ? TRUE : FALSE;
265}
266
267/** Method to obtain a GMI in the space of the original variables from a row of the simplex tableau.
268 *
269 * Returns TRUE if cut is successfully created, FALSE if no cut was generated or if it should be discarded. If the
270 * function returns FALSE, the contents of cutcoefs, cutind, cutnz, cutrhs, cutact may be garbage.
271 */
272static
274 SCIP* scip, /**< pointer to the SCIP environment */
275 SCIP_SEPADATA* sepadata, /**< pointer to separator data */
276 int ncols, /**< number of columns in the LP */
277 int nrows, /**< number of rows in the LP */
278 SCIP_COL** cols, /**< columns of the LP */
279 SCIP_ROW** rows, /**< rows of the LP */
280 SCIP_Real* binvrow, /**< row of the basis inverse */
281 SCIP_Real* binvarow, /**< row of the simplex tableau */
282 SCIP_Real rowrhs, /**< rhs of the tableau row, i.e., corresponding element in the LP solution */
283 SCIP_Real* cutcoefs, /**< array for cut elements in sparse format - must be of size ncols */
284 int* cutind, /**< array for indices of nonzero cut coefficients - must be of size ncols */
285 int* cutnz, /**< pointer to store number of nonzero elements in the cut */
286 SCIP_Real* cutrhs, /**< pointer to store cut rhs */
287 SCIP_Real* cutact, /**< pointer to store cut activity at the current LP optimum - only meaningful if returns TRUE */
288 SCIP_Real* workcoefs /**< working array of size ncols, allocated by caller for efficiency */
289 )
290{
291 SCIP_COL* col;
292 SCIP_ROW* row;
293 SCIP_Real rowelem;
294 SCIP_Real cutelem;
295 SCIP_Real f0;
296 SCIP_Real ratiof0compl;
297 SCIP_Bool success;
298 int i;
299 int c;
300
301 assert(scip != NULL);
302 assert(cols != NULL);
303 assert(rows != NULL);
304 assert(binvrow != NULL);
305 assert(binvarow != NULL);
306 assert(cutcoefs != NULL);
307 assert(cutind != NULL);
308 assert(cutnz != NULL);
309 assert(cutrhs != NULL);
310 assert(cutact != NULL);
311 assert(workcoefs != NULL);
312
313 /* Compute cut fractionality f0 and f0/(1-f0). */
314 f0 = SCIPfeasFrac(scip, rowrhs);
315 ratiof0compl = f0/(1-f0);
316
317 /* rhs of the cut is the fractional part of the LP solution for the basic variable */
318 *cutrhs = -f0;
319
320 /* clear cutcoefs */
321 BMSclearMemoryArray(workcoefs, ncols);
322
323 /* Generate cut coefficients for the original variables. We first use workcoefs to store the cut in dense form, then
324 * we clean and pack the cut to sparse form in cutcoefs. */
325 for( c = 0; c < ncols; ++c)
326 {
327 col = cols[c];
328 assert( col != NULL );
329
330 /* Get simplex tableau element. */
331 switch ( SCIPcolGetBasisStatus(col) )
332 {
334 /* Take element if nonbasic at lower bound. */
335 rowelem = binvarow[c];
336 break;
338 /* Flip element if nonbasic at upper bound. */
339 rowelem = -binvarow[c];
340 break;
342 /* Nonbasic free variable at zero: cut coefficient is zero, skip */
343 continue;
345 default:
346 /* Basic variable: skip */
347 continue;
348 }
349
350 /* Integer variables */
351 if( SCIPcolIsIntegral(col) )
352 {
353 /* If cutelem < 0, then we know SCIPisZero(scip, cutelem) is true and hope it doesn't do much damage. */
354 cutelem = SCIPfrac(scip, rowelem);
355
356 if( cutelem > f0 )
357 {
358 /* cut element if f > f0 */
359 cutelem = -((1.0 - cutelem) * ratiof0compl);
360 }
361 else
362 {
363 /* cut element if f <= f0 */
364 cutelem = -cutelem;
365 }
366 }
367 /* Continuous variables */
368 else
369 {
370 if( rowelem < 0.0 )
371 {
372 /* cut element if f < 0 */
373 cutelem = rowelem * ratiof0compl;
374 }
375 else
376 {
377 /* cut element if f >= 0 */
378 cutelem = -rowelem;
379 }
380 }
381
382 if( ! SCIPisZero(scip, cutelem) )
383 {
384 /* Unflip if necessary, and adjust rhs if at lower or upper bound. */
386 {
387 cutelem = -cutelem;
388 *cutrhs += cutelem * SCIPcolGetUb(col);
389 }
390 else
391 *cutrhs += cutelem * SCIPcolGetLb(col);
392
393 /* Add coefficient to cut in dense form. */
394 workcoefs[SCIPcolGetLPPos(col)] = cutelem;
395 }
396 } /* for( c = 0; c < ncols; ++c) */
397
398 /* Generate cut coefficients for the slack variables. */
399 for( c = 0; c < nrows; ++c )
400 {
401 row = rows[c];
402 assert( row != NULL );
403
404 /* Get simplex tableau element. */
405 switch ( SCIProwGetBasisStatus(row) )
406 {
408 /* Take element if nonbasic at lower bound. */
409 rowelem = binvrow[SCIProwGetLPPos(row)];
410 /* But if this is a >= or ranged constraint at the lower bound, we have to flip the row element. */
411 if( !SCIPisInfinity(scip, -SCIProwGetLhs(row)) )
412 rowelem = -rowelem;
413 break;
415 /* Take element if nonbasic at upper bound - see notes at beginning of file: only nonpositive slack variables
416 * can be nonbasic at upper, therefore they should be flipped twice and we can take the element directly. */
417 rowelem = binvrow[SCIProwGetLPPos(row)];
418 break;
420 /* Nonbasic free variable at zero: cut coefficient is zero, skip */
421 SCIPdebugMsg(scip, "Free nonbasic slack variable, this should not happen!\n");
422 continue;
424 default:
425 /* Basic variable: skip */
426 continue;
427 }
428
429 /* Check if row is integral and will stay integral through the Branch-and-Cut tree; if so, strengthen
430 * coefficient */
431 if( SCIProwIsIntegral(row) && !SCIProwIsModifiable(row) )
432 {
433 /* If cutelem < 0, then we know SCIPisZero(scip, cutelem) is true and hope it doesn't do much damage. */
434 cutelem = SCIPfrac(scip, rowelem);
435
436 if( cutelem > f0 )
437 {
438 /* cut element if f > f0 */
439 cutelem = -((1.0 - cutelem) * ratiof0compl);
440 }
441 else
442 {
443 /* cut element if f <= f0 */
444 cutelem = -cutelem;
445 }
446 }
447 else
448 {
449 if( rowelem < 0.0 )
450 {
451 /* cut element if f < 0 */
452 cutelem = rowelem * ratiof0compl;
453 }
454 else
455 {
456 /* cut element if f >= 0 */
457 cutelem = -rowelem;
458 }
459 }
460
461 if( ! SCIPisZero(scip, cutelem) )
462 {
463 /* Coefficient is large enough, we can keep it. */
464 SCIP_COL** rowcols;
465 SCIP_Real* rowvals;
466
467 SCIP_Real act;
468 SCIP_Real rlhs;
469 SCIP_Real rrhs;
470 SCIP_Real rhsslack;
471
472 /* get lhs/rhs */
473 rlhs = SCIProwGetLhs(row);
474 rrhs = SCIProwGetRhs(row);
475 assert( SCIPisLE(scip, rlhs, rrhs) );
476 assert( ! SCIPisInfinity(scip, rlhs) || ! SCIPisInfinity(scip, rrhs) );
477
478 /* If the slack variable is fixed, we can ignore this cut coefficient. */
479 if( SCIPisFeasZero(scip, rrhs - rlhs) )
480 continue;
481
482 act = SCIPgetRowLPActivity(scip, row);
483 rhsslack = rrhs - act;
484
485 /* Unflip slack variable and adjust rhs if necessary. */
487 {
488 /* If >= or ranged constraint, flip element back to original */
490 cutelem = -cutelem;
491 }
492
493 rowcols = SCIProwGetCols(row);
494 rowvals = SCIProwGetVals(row);
495
496 /* Eliminate slack variable. */
497 for( i = 0; i < SCIProwGetNLPNonz(row); ++i )
498 workcoefs[SCIPcolGetLPPos(rowcols[i])] -= cutelem * rowvals[i];
499
500 if ( SCIPisFeasZero(scip, rhsslack) )
501 *cutrhs -= cutelem * (rrhs - SCIProwGetConstant(row));
502 else
503 {
504 assert( SCIPisFeasZero(scip, act - rlhs) );
505 *cutrhs -= cutelem * (rlhs - SCIProwGetConstant(row));
506 }
507 }
508 } /* for( c = 0; c < nrows; ++c) */
509
510 /* Initialize cut activity. */
511 *cutact = 0.0;
512
513 /* Modify cut to make it numerically safer, and check that it is numerically safe. */
514 success = modifyAndPackCut(scip, sepadata, ncols, cols, workcoefs, cutcoefs, cutind, cutnz, cutrhs);
515 if ( success )
516 {
517 success = checkNumerics(scip, sepadata, ncols, cols, cutcoefs, cutind, *cutnz, *cutrhs, cutact);
518 SCIPdebugMsg(scip, "checkNumerics returned: %u.\n", success);
519 return success;
520 }
521 SCIPdebugMsg(scip, "modifyAndPackCut was not successful.\n");
522
523 return FALSE;
524}
525
526
527/*
528 * Callback methods
529 */
530
531/** copy method for separator plugins (called when SCIP copies plugins) */
532static
534{ /*lint --e{715}*/
535 assert(scip != NULL);
536 assert(sepa != NULL);
537
539
540 /* call inclusion method of constraint handler */
542
543 return SCIP_OKAY;
544}
545
546/** destructor of separator to free user data (called when SCIP is exiting) */
547static
549{ /*lint --e{715}*/
551
552 assert(scip != NULL);
553 assert(sepa != NULL);
554
556
557 /* free separator data */
559 assert(sepadata != NULL);
560
562
563 SCIPsepaSetData(sepa, NULL);
564
565 return SCIP_OKAY;
566}
567
568/** LP solution separation method of separator */
569static
571{ /*lint --e{715}*/
572 char cutname[SCIP_MAXSTRLEN];
574 SCIP_VAR** vars;
575 SCIP_COL** cols;
576 SCIP_ROW** rows;
577 SCIP_Real* binvrow;
578 SCIP_Real* binvarow;
579 SCIP_Real* cutcoefs;
580 SCIP_Real* workcoefs;
581 SCIP_Real cutrhs;
582 int* cutind;
583 int* basisind;
584 int nvars;
585 int ncols;
586 int nrows;
587 int ncalls;
588 int maxsepacuts;
589 int ncuts;
590 int cutnz;
591 int c;
592 int i;
593 int j;
594
595 assert(sepa != NULL);
596 assert(scip != NULL);
597 assert(result != NULL);
598
600
602
603 /* Only call separator, if we are not close to terminating. */
604 if( SCIPisStopped(scip) )
605 return SCIP_OKAY;
606
607 /* Only call separator, if an optimal LP solution is at hand. */
609 return SCIP_OKAY;
610
611 /* Only call separator, if the LP solution is basic. */
612 if( ! SCIPisLPSolBasic(scip) )
613 return SCIP_OKAY;
614
615 /* Only call separator, if there are fractional variables. */
616 if( SCIPgetNLPBranchCands(scip) == 0 )
617 return SCIP_OKAY;
618
620 assert(sepadata != NULL);
621
623
624 /* Only call the GMI cut separator a given number of times at each node. */
625 if( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot)
626 || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) )
627 return SCIP_OKAY;
628
629 /* get variables data */
631
632 /* get LP data */
633 SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
634 SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
635
636 /* exit if LP is trivial */
637 if( ncols == 0 || nrows == 0 )
638 return SCIP_OKAY;
639
641
642 /* allocate temporary memory */
643 SCIP_CALL( SCIPallocBufferArray(scip, &cutcoefs, ncols) );
644 SCIP_CALL( SCIPallocBufferArray(scip, &workcoefs, ncols) );
645 SCIP_CALL( SCIPallocBufferArray(scip, &cutind, ncols) );
646 SCIP_CALL( SCIPallocBufferArray(scip, &basisind, nrows) );
647 SCIP_CALL( SCIPallocBufferArray(scip, &binvarow, ncols) );
648 SCIP_CALL( SCIPallocBufferArray(scip, &binvrow, nrows) );
649
650 /* get basis indices */
651 SCIP_CALL( SCIPgetLPBasisInd(scip, basisind) );
652
653 /* get the maximal number of cuts allowed in a separation round */
654 if( depth == 0 )
655 maxsepacuts = sepadata->maxsepacutsroot;
656 else
657 maxsepacuts = sepadata->maxsepacuts;
658
659 if( maxsepacuts == -1 )
660 maxsepacuts = INT_MAX;
661
662 /* For all basic columns belonging to integer variables, try to generate a GMI cut. */
663 ncuts = 0;
664 for( i = 0; i < nrows && ncuts < maxsepacuts && ! SCIPisStopped(scip) && *result != SCIP_CUTOFF; ++i )
665 {
666 SCIP_Bool tryrow;
668
669 tryrow = FALSE;
670 c = basisind[i];
672
673 SCIPdebugMsg(scip, "Row %d basic variable %d with value %f\n", i, basisind[i],
674 (c >= 0) ? SCIPcolGetPrimsol(cols[c]) : SCIPgetRowActivity(scip, rows[-c-1]));
675
676 if( c >= 0 )
677 {
678 SCIP_VAR* var;
679 assert(c < ncols);
680 assert(cols[c] != NULL);
681 var = SCIPcolGetVar(cols[c]);
683 {
684 primsol = SCIPcolGetPrimsol(cols[c]);
685 assert(SCIPgetVarSol(scip, var) == primsol); /*lint !e777*/
686
687 if( (SCIPfeasFrac(scip, primsol) >= sepadata->away) && (SCIPfeasFrac(scip, primsol) <= 1.0 - sepadata->away) )
688 {
689 SCIPdebugMsg(scip, "trying GMI cut for col <%s> [%g] row %i\n", SCIPvarGetName(var), primsol, i);
690 tryrow = TRUE;
691 }
692 }
693 }
694 else if( sepadata->separaterows )
695 {
696 SCIP_ROW* row;
697 assert(0 <= -c-1 && -c-1 < nrows);
698 row = rows[-c-1];
699 if( SCIProwIsIntegral(row) && !SCIProwIsModifiable(row) )
700 {
701 /* Compute value of the slack variable (we only care about the correct fractionality) */
702 if ( SCIPisInfinity(scip, SCIProwGetRhs(row)) )
704 else
706
707 if( (SCIPfeasFrac(scip, primsol) >= sepadata->away) && (SCIPfeasFrac(scip, primsol) <= 1.0 - sepadata->away) )
708 {
709 SCIPdebugMsg(scip, "trying GMI cut for row <%s> [%g]\n", SCIProwGetName(row), primsol);
711 tryrow = TRUE;
712 }
713 }
714 }
715
716 if( tryrow )
717 {
718 SCIP_Real cutact;
719 SCIP_Bool success;
720 SCIP_Bool cutislocal;
721
722 /* get the row of B^-1 for this basic integer variable with fractional solution value */
723 SCIP_CALL( SCIPgetLPBInvRow(scip, i, binvrow, NULL, NULL) );
724
725 /* get the tableau row for this basic integer variable with fractional solution value */
726 SCIP_CALL( SCIPgetLPBInvARow(scip, i, binvrow, binvarow, NULL, NULL) );
727
728 /* this is an approximation (one could also pass over coefficients and check whether local rows have been used): */
729 cutislocal = (depth != 0) ? TRUE : FALSE;
730
731 /* create a GMI cut out of the simplex tableau row */
732 success = getGMIFromRow(scip, sepadata, ncols, nrows, cols, rows, binvrow, binvarow, primsol, cutcoefs, cutind, &cutnz, &cutrhs, &cutact, workcoefs);
733
734 SCIPdebugMsg(scip, " -> success = %u: %g <= %g\n", success, cutact, cutrhs);
735
736 /* if successful, add the row as a cut */
737 if( success )
738 {
739 SCIP_ROW* cut;
740
741 /* construct cut name */
742 if( c >= 0 )
743 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "gmi%d_x%d", SCIPgetNLPs(scip), c);
744 else
745 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "gmi%d_s%d", SCIPgetNLPs(scip), -c-1);
746
747 /* create empty cut */
748 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), cutrhs, cutislocal, FALSE, sepadata->dynamiccuts) );
749
750 /* cache the row extension and only flush them if the cut gets added */
752
753 /* collect all non-zero coefficients */
754 for( j = 0; j < cutnz; ++j )
755 {
756 SCIP_CALL( SCIPaddVarToRow(scip, cut, SCIPcolGetVar(cols[cutind[j]]), cutcoefs[j]) );
757 }
758
759 if( SCIProwGetNNonz(cut) == 0 )
760 {
762 SCIPdebugMsg(scip, " -> GMI cut detected infeasibility with cut 0 <= %f.\n", cutrhs);
764 break;
765 }
766
767 /* Only take efficacious cuts, except for cuts with one non-zero coefficient (= bound
768 * changes); the latter cuts will be handeled internally in sepastore. */
769 if( SCIProwGetNNonz(cut) == 1 || SCIPisCutEfficacious(scip, NULL, cut) )
770 {
771 SCIP_Bool infeasible;
772
773 SCIPdebugMsg(scip, " -> found GMI cut <%s>: act=%f, rhs=%f, norm=%f, eff=%f, min=%f, max=%f (range=%f).\n",
774 cutname, SCIPgetRowLPActivity(scip, cut), SCIProwGetRhs(cut), SCIProwGetNorm(cut),
778
779 /* flush all changes before adding the cut */
781
782 SCIP_CALL( SCIPaddRow(scip, cut, FALSE, &infeasible) );
783
784 /* add global cuts that are not implicit bound changes to the cut pool */
785 if( ! cutislocal && SCIProwGetNNonz(cut) > 1 )
786 {
788 }
789
790 if ( infeasible )
792 else
794 ncuts++;
795 }
796
797 /* release the row */
798 SCIP_CALL( SCIPreleaseRow(scip, &cut) );
799 }
800 }
801 }
802
803 /* free temporary memory */
804 SCIPfreeBufferArray(scip, &binvarow);
805 SCIPfreeBufferArray(scip, &binvrow);
806 SCIPfreeBufferArray(scip, &basisind);
807 SCIPfreeBufferArray(scip, &workcoefs);
808 SCIPfreeBufferArray(scip, &cutcoefs);
809 SCIPfreeBufferArray(scip, &cutind);
810
811 SCIPdebugMsg(scip, "end searching GMI cuts: found %d cuts.\n", ncuts);
812
813 sepadata->lastncutsfound = SCIPgetNCutsFound(scip);
814
815 return SCIP_OKAY;
816}
817
818
819/*
820 * separator specific interface methods
821 */
822
823/** creates the GMI MIR cut separator and includes it in SCIP */
825 SCIP* scip /**< SCIP data structure */
826 )
827{
829 SCIP_SEPA* sepa;
830
831 /* create separator data */
833 sepadata->lastncutsfound = 0;
834
835 /* include separator */
837 SEPA_USESSUBSCIP, SEPA_DELAY, sepaExeclpGMI, NULL, sepadata) );
838
839 assert(sepa != NULL);
840
841 /* set non-NULL pointers to callback methods */
842 SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyGMI) );
843 SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeGMI) );
844
845 /* add separator parameters */
847 "separating/gmi/maxrounds",
848 "maximal number of GMI separation rounds per node (-1: unlimited)",
849 &sepadata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
851 "separating/gmi/maxroundsroot",
852 "maximal number of GMI separation rounds in the root node (-1: unlimited)",
853 &sepadata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
855 "separating/gmi/maxsepacuts",
856 "maximal number of GMI cuts separated per separation round (-1: unlimited)",
857 &sepadata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, -1, INT_MAX, NULL, NULL) );
859 "separating/gmi/maxsepacutsroot",
860 "maximal number of GMI cuts separated per separation round in the root node (-1: unlimited)",
861 &sepadata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, -1, INT_MAX, NULL, NULL) );
863 "separating/gmi/dynamiccuts",
864 "should generated cuts be removed from the LP if they are no longer tight?",
865 &sepadata->dynamiccuts, FALSE, DEFAULT_DYNAMICCUTS, NULL, NULL) );
867 "separating/gmi/separaterows",
868 "separate rows with integral slack",
869 &sepadata->separaterows, FALSE, DEFAULT_SEPARATEROWS, NULL, NULL) );
871 "separating/gmi/away",
872 "minimal fractionality of a basic variable in order to try GMI cut",
873 &sepadata->away, FALSE, DEFAULT_AWAY, 0.0, 0.5, NULL, NULL) );
875 "separating/gmi/minviolation",
876 "minimal violation to accept cut",
877 &sepadata->minviolation, FALSE, DEFAULT_MIN_VIOLATION, 0.0, 1.0, NULL, NULL) );
879 "separating/gmi/epscoeff",
880 "tolerance for zeroing out small coefficients",
881 &sepadata->epscoeff, FALSE, DEFAULT_EPS_COEFF, 0.0, 0.01, NULL, NULL) );
883 "separating/gmi/epsrelaxabs",
884 "absolute cut rhs relaxation",
885 &sepadata->epsrelaxabs, FALSE, DEFAULT_EPS_RELAX_ABS, 0.0, SCIP_REAL_MAX, NULL, NULL) );
887 "separating/gmi/epsrelaxrel",
888 "relative cut rhs relaxation",
889 &sepadata->epsrelaxrel, FALSE, DEFAULT_EPS_RELAX_REL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
891 "separating/gmi/maxdynamism",
892 "maximal valid range max(|weights|)/min(|weights|) of cut coefficients",
893 &sepadata->maxdynamism, FALSE, DEFAULT_MAX_DYN, 0.0, SCIP_REAL_MAX, NULL, NULL) );
895 "separating/gmi/maxsuppabs",
896 "maximum cut support - absolute value in the formula",
897 &sepadata->maxsuppabs, FALSE, DEFAULT_MAX_SUPP_ABS, 0, INT_MAX, NULL, NULL) );
899 "separating/gmi/maxsupprel",
900 "maximum cut support - relative value in the formula",
901 &sepadata->maxsupprel, FALSE, DEFAULT_MAX_SUPP_REL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
902
903 return SCIP_OKAY;
904}
#define DEFAULT_MAXROUNDSROOT
#define DEFAULT_MAXSEPACUTSROOT
#define DEFAULT_MAXSEPACUTS
#define DEFAULT_MAXROUNDS
#define NULL
Definition def.h:257
#define SCIP_MAXSTRLEN
Definition def.h:278
#define SCIP_REAL_MAX
Definition def.h:167
#define SCIP_INVALID
Definition def.h:187
#define SCIP_Bool
Definition def.h:100
#define MIN(x, y)
Definition def.h:233
#define SCIP_STRINGEQ(name, reference, retcode)
Definition def.h:454
#define SCIP_Real
Definition def.h:165
#define TRUE
Definition def.h:102
#define FALSE
Definition def.h:103
#define MAX(x, y)
Definition def.h:229
#define REALABS(x)
Definition def.h:191
#define EPSZ(x, eps)
Definition def.h:197
#define SCIP_CALL(x)
Definition def.h:364
SCIP_Bool SCIPisStopped(SCIP *scip)
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition scip_prob.c:2115
#define SCIPdebugMsg
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:83
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:139
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:57
int SCIPgetNLPBranchCands(SCIP *scip)
int SCIPcolGetLPPos(SCIP_COL *col)
Definition lp.c:17487
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition lp.c:17425
SCIP_Bool SCIPcolIsIntegral(SCIP_COL *col)
Definition lp.c:17455
SCIP_Real SCIPcolGetLb(SCIP_COL *col)
Definition lp.c:17346
SCIP_Real SCIPcolGetPrimsol(SCIP_COL *col)
Definition lp.c:17379
SCIP_Real SCIPcolGetUb(SCIP_COL *col)
Definition lp.c:17356
SCIP_BASESTAT SCIPcolGetBasisStatus(SCIP_COL *col)
Definition lp.c:17414
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition scip_cut.c:336
SCIP_Real SCIPgetCutEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition scip_cut.c:94
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition scip_cut.c:117
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition scip_cut.c:225
SCIP_RETCODE SCIPgetLPBasisInd(SCIP *scip, int *basisind)
Definition scip_lp.c:692
SCIP_RETCODE SCIPgetLPColsData(SCIP *scip, SCIP_COL ***cols, int *ncols)
Definition scip_lp.c:477
SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition scip_lp.c:576
SCIP_RETCODE SCIPgetLPBInvARow(SCIP *scip, int r, SCIP_Real *binvrow, SCIP_Real *coefs, int *inds, int *ninds)
Definition scip_lp.c:791
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition scip_lp.c:174
SCIP_Bool SCIPisLPSolBasic(SCIP *scip)
Definition scip_lp.c:673
SCIP_RETCODE SCIPgetLPBInvRow(SCIP *scip, int r, SCIP_Real *coefs, int *inds, int *ninds)
Definition scip_lp.c:720
#define SCIPallocBufferArray(scip, ptr, num)
Definition scip_mem.h:124
#define SCIPfreeBufferArray(scip, ptr)
Definition scip_mem.h:136
#define SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
SCIP_Bool SCIProwIsIntegral(SCIP_ROW *row)
Definition lp.c:17785
SCIP_Real SCIPgetRowMaxCoef(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1886
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition lp.c:17686
SCIP_Real SCIPgetRowMinCoef(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1868
SCIP_Bool SCIProwIsModifiable(SCIP_ROW *row)
Definition lp.c:17805
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1581
int SCIProwGetNNonz(SCIP_ROW *row)
Definition lp.c:17607
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition lp.c:17632
SCIP_Real SCIPgetRowLPActivity(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1957
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition lp.c:17696
int SCIProwGetNLPNonz(SCIP_ROW *row)
Definition lp.c:17621
SCIP_Real SCIProwGetNorm(SCIP_ROW *row)
Definition lp.c:17662
int SCIProwGetLPPos(SCIP_ROW *row)
Definition lp.c:17895
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1604
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition scip_lp.c:1646
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition scip_lp.c:2176
const char * SCIProwGetName(SCIP_ROW *row)
Definition lp.c:17745
SCIP_Real SCIPgetRowActivity(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:2068
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition scip_lp.c:1508
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:1429
SCIP_Real SCIProwGetConstant(SCIP_ROW *row)
Definition lp.c:17652
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition lp.c:17642
SCIP_BASESTAT SCIProwGetBasisStatus(SCIP_ROW *row)
Definition lp.c:17734
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:115
SCIP_RETCODE SCIPsetSepaFree(SCIP *scip, SCIP_SEPA *sepa,)
Definition scip_sepa.c:173
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition sepa.c:746
int SCIPsepaGetNCallsAtNode(SCIP_SEPA *sepa)
Definition sepa.c:893
SCIP_SEPADATA * SCIPsepaGetData(SCIP_SEPA *sepa)
Definition sepa.c:636
void SCIPsepaSetData(SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata)
Definition sepa.c:646
SCIP_RETCODE SCIPsetSepaCopy(SCIP *scip, SCIP_SEPA *sepa,)
Definition scip_sepa.c:157
SCIP_Longint SCIPgetNLPs(SCIP *scip)
int SCIPgetNCutsFound(SCIP *scip)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Real SCIPfeasFrac(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfrac(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23299
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition var.c:23522
SCIP_Real SCIPgetVarSol(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:3051
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10827
return SCIP_OKAY
SCIP_Longint ncalls
int c
int depth
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
SCIP_Real primsol
static SCIP_VAR ** vars
#define BMSclearMemoryArray(ptr, num)
Definition memory.h:130
#define SCIPdebug(x)
Definition pub_message.h:93
public data structures and miscellaneous methods
#define SEPA_PRIORITY
#define SEPA_DELAY
#define DEFAULT_DYNAMICCUTS
#define SEPA_DESC
#define SEPA_USESSUBSCIP
#define SEPA_MAXBOUNDDIST
#define SEPA_FREQ
#define SEPA_NAME
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:273
#define DEFAULT_MAX_SUPP_ABS
Definition sepa_gmi.c:97
#define DEFAULT_MIN_VIOLATION
Definition sepa_gmi.c:92
#define DEFAULT_EPS_COEFF
Definition sepa_gmi.c:93
#define DEFAULT_EPS_RELAX_REL
Definition sepa_gmi.c:95
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:132
#define DEFAULT_MAX_SUPP_REL
Definition sepa_gmi.c:98
#define DEFAULT_MAX_DYN
Definition sepa_gmi.c:96
#define DEFAULT_EPS_RELAX_ABS
Definition sepa_gmi.c:94
SCIP_RETCODE SCIPincludeSepaGMI(SCIP *scip)
Definition sepa_gmi.c:824
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:209
Gomory Mixed-Integer Cuts.
#define DEFAULT_AWAY
#define DEFAULT_SEPARATEROWS
struct SCIP_Row SCIP_ROW
Definition type_lp.h:105
struct SCIP_Col SCIP_COL
Definition type_lp.h:99
@ SCIP_LPSOLSTAT_OPTIMAL
Definition type_lp.h:44
@ SCIP_BASESTAT_BASIC
Definition type_lpi.h:92
@ SCIP_BASESTAT_UPPER
Definition type_lpi.h:93
@ SCIP_BASESTAT_LOWER
Definition type_lpi.h:91
@ SCIP_BASESTAT_ZERO
Definition type_lpi.h:94
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_CUTOFF
Definition type_result.h:48
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_SEPARATED
Definition type_result.h:49
@ SCIP_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
struct SCIP_SepaData SCIP_SEPADATA
Definition type_sepa.h:52
#define SCIP_DECL_SEPAEXECLP(x)
Definition type_sepa.h:136
#define SCIP_DECL_SEPAFREE(x)
Definition type_sepa.h:69
struct SCIP_Sepa SCIP_SEPA
Definition type_sepa.h:51
#define SCIP_DECL_SEPACOPY(x)
Definition type_sepa.h:61
struct SCIP_Var SCIP_VAR
Definition type_var.h:166