Scippy

SCIP

Solving Constraint Integer Programs

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-2024 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 <assert.h>
74#include <string.h>
75
76#include "scip/pub_misc.h"
77#include "sepa_gmi.h"
78
79#define SEPA_NAME "gmi"
80#define SEPA_DESC "Gomory Mixed-Integer cuts separator"
81#define SEPA_PRIORITY -1000
82#define SEPA_FREQ 0
83#define SEPA_MAXBOUNDDIST 0.0
84#define SEPA_USESSUBSCIP FALSE /**< does the separator use a secondary SCIP instance? */
85#define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
86
87#define DEFAULT_MAXROUNDS 5 /**< maximal number of GMI separation rounds per node (-1: unlimited) */
88#define DEFAULT_MAXROUNDSROOT 30 /**< maximal number of GMI separation rounds in the root node (-1: unlimited) */
89#define DEFAULT_MAXSEPACUTS -1 /**< maximal number of GMI cuts separated per separation round */
90#define DEFAULT_MAXSEPACUTSROOT -1 /**< maximal number of GMI cuts separated per separation round in root node */
91#define DEFAULT_DYNAMICCUTS TRUE /**< should generated cuts be removed from the LP if they are no longer tight? */
92#define DEFAULT_SEPARATEROWS TRUE /**< separate rows with integral slack? */
93
94#define DEFAULT_AWAY 0.005 /**< minimal fractionality of a basic variable in order to try GMI cut - default */
95#define DEFAULT_MIN_VIOLATION 0.00 /**< minimal violation to accept cut - default */
96#define DEFAULT_EPS_COEFF 1e-11 /**< tolerance for zeroing out small coefficients - default */
97#define DEFAULT_EPS_RELAX_ABS 1e-11 /**< absolute cut rhs relaxation - default */
98#define DEFAULT_EPS_RELAX_REL 1e-13 /**< relative cut rhs relaxation - default */
99#define DEFAULT_MAX_DYN 1.0e+6 /**< maximal valid range max(|weights|)/min(|weights|) of cut coefficients - default */
100#define DEFAULT_MAX_SUPP_ABS 1000 /**< maximum cut support - absolute value in the formula - default */
101#define DEFAULT_MAX_SUPP_REL 0.1 /**< maximum cut support - relative value in the formula - default */
102
103
104/** separator data */
105struct SCIP_SepaData
106{
107 int maxrounds; /**< maximal number of GMI separation rounds per node (-1: unlimited) */
108 int maxroundsroot; /**< maximal number of GMI separation rounds in the root node (-1: unlimited) */
109 int maxsepacuts; /**< maximal number of GMI cuts separated per separation round */
110 int maxsepacutsroot; /**< maximal number of GMI cuts separated per separation round in root node */
111 int lastncutsfound; /**< total number of cuts found after last call of separator */
112 SCIP_Bool dynamiccuts; /**< should generated cuts be removed from the LP if they are no longer tight? */
113 SCIP_Bool separaterows; /**< separate rows with integral slack? */
114 SCIP_Real away; /**< minimal fractionality of a basis variable in order to try GMI cut */
115 SCIP_Real minviolation; /**< minimal violation to accept cut */
116 SCIP_Real epscoeff; /**< tolerance for zeroing out small coefficients */
117 SCIP_Real epsrelaxabs; /**< absolute cut rhs relaxation */
118 SCIP_Real epsrelaxrel; /**< relative cut rhs relaxation */
119 SCIP_Real maxdynamism; /**< maximal valid range max(|weights|)/min(|weights|) of cut coefficients */
120 int maxsuppabs; /**< maximum cut support - absolute value in the formula */
121 SCIP_Real maxsupprel; /**< maximum cut support - relative value in the formula */
122};
123
124
125/*
126 * local methods
127 */
128
129/** Modify the cut to make it numerically safer, and packs it from dense format to sparse format.
130 *
131 * See paper "On the safety of Gomory cut generators" by Cornuejols, Margot, and Nannicini for more information. Returns
132 * TRUE if cut is accepted, FALSE if it is discarded.
133 */
134static
136 SCIP* scip, /**< pointer to the SCIP environment */
137 SCIP_SEPADATA* sepadata, /**< pointer to separator data */
138 int ncols, /**< number of columns in the LP */
139 SCIP_COL** cols, /**< columns of the LP */
140 SCIP_Real* densecoefs, /**< cut in dense format on input */
141 SCIP_Real* sparsecoefs, /**< cut coefficients in sparse format on output */
142 int* cutind, /**< cut indices in sparse format on output */
143 int* cutnz, /**< pointer to store the number of nonzero elements in the cut in sparse format on output */
144 SCIP_Real* cutrhs /**< pointer to store the rhs of the cut, initialized to original value, modified */
145 )
146{
147 SCIP_COL* col;
148 int i;
149 int c;
150
151 assert(scip != NULL);
152 assert(cols != NULL);
153 assert(densecoefs != NULL);
154 assert(sparsecoefs != NULL);
155 assert(cutind != NULL);
156 assert(cutnz != NULL);
157 assert(cutrhs != NULL);
158
159 *cutnz = 0; /* this is the current position in the cut array */
160
161 /* Check each cut coefficient. If it is small, try set it to zero. */
162 for( c = 0; c < ncols; ++c )
163 {
164 col = cols[c];
165 assert(col != NULL);
166 i = SCIPcolGetLPPos(col);
167 assert( 0 <= i );
168
169 /* Cycle over small elements that are not zero. If the element is zero, it will be discarded anyway. */
170 if( EPSZ(densecoefs[i], sepadata->epscoeff) && ! SCIPisZero(scip, densecoefs[i]) )
171 {
172 if( densecoefs[i] > 0.0 )
173 {
174 /* If we would have to modify the rhs by a multiple of infinity, discard the cut altogether. */
175 if( SCIPisInfinity(scip, -SCIPcolGetLb(col)) )
176 return FALSE;
177
178 /* Zero out coefficient and modify rhs to preserve validity and possibly strengthen the cut. */
179 *cutrhs -= densecoefs[i] * SCIPcolGetLb(cols[c]);
180 }
181 else if( densecoefs[i] < 0.0 )
182 {
183 /* If we would have to modify the rhs by a multiple of infinity, discard the cut altogether. */
184 if( SCIPisInfinity(scip, SCIPcolGetUb(col)) )
185 return FALSE;
186
187 /* Zero out coefficient and modify rhs to preserve validity and possibly strengthen the cut. */
188 *cutrhs -= densecoefs[i] * SCIPcolGetUb(cols[c]);
189 }
190 } /* if( EPSZ(densecoefs[i], sepadata->epscoeff) && ! SCIPisZero(densecoefs[i]) ) */
191 else if( ! EPSZ(densecoefs[i], sepadata->epscoeff) )
192 {
193 /* cut coefficient is large enough - keep it and write in sparse form */
194 sparsecoefs[*cutnz] = densecoefs[i];
195 cutind[*cutnz] = c;
196 (*cutnz)++;
197 }
198 } /* for( c = 0; c < ncols; ++c ) */
199
200 /* Relax rhs of the cut */
201 *cutrhs += REALABS(*cutrhs) * sepadata->epsrelaxrel + sepadata->epsrelaxabs;
202
203 return (*cutnz > 0) ? TRUE : FALSE;
204}
205
206/** Check the numerical properties of the cut.
207 *
208 * See paper "On the safety of Gomory cut generators" by Cornuejols, Margot, and Nannicini for more information. Returns
209 * TRUE if cut is accepted, FALSE if it is discarded.
210 */
211static
213 SCIP* scip, /**< pointer to the SCIP environment */
214 SCIP_SEPADATA* sepadata, /**< pointer to separator data */
215 int ncols, /**< number of columns in the LP */
216 SCIP_COL** cols, /**< columns of the LP */
217 SCIP_Real* cutcoefs, /**< cut in sparse format */
218 int* cutind, /**< cut indices in sparse format */
219 int cutnz, /**< number of nonzero elements in the cut in sparse format */
220 SCIP_Real cutrhs, /**< rhs of the cut */
221 SCIP_Real* cutact /**< pointer to store activity of the cut at the current LP optimum will go here on output */
222 )
223{
224 SCIP_Real violation;
225 SCIP_Real mincoef;
226 SCIP_Real maxcoef;
227 int i;
228
229 assert(scip != NULL);
230 assert(cols != NULL);
231 assert(cutcoefs != NULL);
232 assert(cutind != NULL);
233 assert(cutact != NULL);
234 assert(cutnz > 0);
235
236 /* Check maximum support */
237 if( cutnz > ncols * sepadata->maxsupprel + sepadata->maxsuppabs )
238 {
239 SCIPdebugMsg(scip, "Cut too dense (%d > %d).\n", cutnz, (int) (ncols * sepadata->maxsupprel + sepadata->maxsuppabs));
240 return FALSE;
241 }
242
243 /* Compute cut violation and dynamism */
244 mincoef = SCIP_REAL_MAX;
245 maxcoef = 0.0;
246 *cutact = 0.0;
247
248 for( i = 0; i < cutnz; ++i )
249 {
250 mincoef = MIN(mincoef, REALABS(cutcoefs[i])); /*lint !e666*/
251 maxcoef = MAX(maxcoef, REALABS(cutcoefs[i])); /*lint !e666*/
252 *cutact += cutcoefs[i] * SCIPcolGetPrimsol(cols[cutind[i]]);
253 }
254
255 /* Check dynamism */
256 if( maxcoef > mincoef * sepadata->maxdynamism )
257 {
258 SCIPdebugMsg(scip, "Cut too dynamic (%g > %g).\n", maxcoef, mincoef * sepadata->maxdynamism);
259 return FALSE;
260 }
261
262 /* Check minimum violation */
263 violation = *cutact - cutrhs;
264 if( REALABS(cutrhs) > 1.0 )
265 violation /= REALABS(cutrhs);
266
267 return (violation >= sepadata->minviolation) ? TRUE : FALSE;
268}
269
270/** Method to obtain a GMI in the space of the original variables from a row of the simplex tableau.
271 *
272 * Returns TRUE if cut is successfully created, FALSE if no cut was generated or if it should be discarded. If the
273 * function returns FALSE, the contents of cutcoefs, cutind, cutnz, cutrhs, cutact may be garbage.
274 */
275static
277 SCIP* scip, /**< pointer to the SCIP environment */
278 SCIP_SEPADATA* sepadata, /**< pointer to separator data */
279 int ncols, /**< number of columns in the LP */
280 int nrows, /**< number of rows in the LP */
281 SCIP_COL** cols, /**< columns of the LP */
282 SCIP_ROW** rows, /**< rows of the LP */
283 SCIP_Real* binvrow, /**< row of the basis inverse */
284 SCIP_Real* binvarow, /**< row of the simplex tableau */
285 SCIP_Real rowrhs, /**< rhs of the tableau row, i.e., corresponding element in the LP solution */
286 SCIP_Real* cutcoefs, /**< array for cut elements in sparse format - must be of size ncols */
287 int* cutind, /**< array for indices of nonzero cut coefficients - must be of size ncols */
288 int* cutnz, /**< pointer to store number of nonzero elements in the cut */
289 SCIP_Real* cutrhs, /**< pointer to store cut rhs */
290 SCIP_Real* cutact, /**< pointer to store cut activity at the current LP optimum - only meaningful if returns TRUE */
291 SCIP_Real* workcoefs /**< working array of size ncols, allocated by caller for efficiency */
292 )
293{
294 SCIP_COL* col;
295 SCIP_ROW* row;
296 SCIP_Real rowelem;
297 SCIP_Real cutelem;
298 SCIP_Real f0;
299 SCIP_Real ratiof0compl;
300 SCIP_Bool success;
301 int i;
302 int c;
303
304 assert(scip != NULL);
305 assert(cols != NULL);
306 assert(rows != NULL);
307 assert(binvrow != NULL);
308 assert(binvarow != NULL);
309 assert(cutcoefs != NULL);
310 assert(cutind != NULL);
311 assert(cutnz != NULL);
312 assert(cutrhs != NULL);
313 assert(cutact != NULL);
314 assert(workcoefs != NULL);
315
316 /* Compute cut fractionality f0 and f0/(1-f0). */
317 f0 = SCIPfeasFrac(scip, rowrhs);
318 ratiof0compl = f0/(1-f0);
319
320 /* rhs of the cut is the fractional part of the LP solution for the basic variable */
321 *cutrhs = -f0;
322
323 /* clear cutcoefs */
324 BMSclearMemoryArray(workcoefs, ncols);
325
326 /* Generate cut coefficients for the original variables. We first use workcoefs to store the cut in dense form, then
327 * we clean and pack the cut to sparse form in cutcoefs. */
328 for( c = 0; c < ncols; ++c)
329 {
330 col = cols[c];
331 assert( col != NULL );
332
333 /* Get simplex tableau element. */
334 switch ( SCIPcolGetBasisStatus(col) )
335 {
337 /* Take element if nonbasic at lower bound. */
338 rowelem = binvarow[c];
339 break;
341 /* Flip element if nonbasic at upper bound. */
342 rowelem = -binvarow[c];
343 break;
345 /* Nonbasic free variable at zero: cut coefficient is zero, skip */
346 continue;
348 default:
349 /* Basic variable: skip */
350 continue;
351 }
352
353 /* Integer variables */
354 if( SCIPcolIsIntegral(col) )
355 {
356 /* If cutelem < 0, then we know SCIPisZero(scip, cutelem) is true and hope it doesn't do much damage. */
357 cutelem = SCIPfrac(scip, rowelem);
358
359 if( cutelem > f0 )
360 {
361 /* cut element if f > f0 */
362 cutelem = -((1.0 - cutelem) * ratiof0compl);
363 }
364 else
365 {
366 /* cut element if f <= f0 */
367 cutelem = -cutelem;
368 }
369 }
370 /* Continuous variables */
371 else
372 {
373 if( rowelem < 0.0 )
374 {
375 /* cut element if f < 0 */
376 cutelem = rowelem * ratiof0compl;
377 }
378 else
379 {
380 /* cut element if f >= 0 */
381 cutelem = -rowelem;
382 }
383 }
384
385 if( ! SCIPisZero(scip, cutelem) )
386 {
387 /* Unflip if necessary, and adjust rhs if at lower or upper bound. */
389 {
390 cutelem = -cutelem;
391 *cutrhs += cutelem * SCIPcolGetUb(col);
392 }
393 else
394 *cutrhs += cutelem * SCIPcolGetLb(col);
395
396 /* Add coefficient to cut in dense form. */
397 workcoefs[SCIPcolGetLPPos(col)] = cutelem;
398 }
399 } /* for( c = 0; c < ncols; ++c) */
400
401 /* Generate cut coefficients for the slack variables. */
402 for( c = 0; c < nrows; ++c )
403 {
404 row = rows[c];
405 assert( row != NULL );
406
407 /* Get simplex tableau element. */
408 switch ( SCIProwGetBasisStatus(row) )
409 {
411 /* Take element if nonbasic at lower bound. */
412 rowelem = binvrow[SCIProwGetLPPos(row)];
413 /* But if this is a >= or ranged constraint at the lower bound, we have to flip the row element. */
414 if( !SCIPisInfinity(scip, -SCIProwGetLhs(row)) )
415 rowelem = -rowelem;
416 break;
418 /* Take element if nonbasic at upper bound - see notes at beginning of file: only nonpositive slack variables
419 * can be nonbasic at upper, therefore they should be flipped twice and we can take the element directly. */
420 rowelem = binvrow[SCIProwGetLPPos(row)];
421 break;
423 /* Nonbasic free variable at zero: cut coefficient is zero, skip */
424 SCIPdebugMsg(scip, "Free nonbasic slack variable, this should not happen!\n");
425 continue;
427 default:
428 /* Basic variable: skip */
429 continue;
430 }
431
432 /* Check if row is integral and will stay integral through the Branch-and-Cut tree; if so, strengthen
433 * coefficient */
434 if( SCIProwIsIntegral(row) && !SCIProwIsModifiable(row) )
435 {
436 /* If cutelem < 0, then we know SCIPisZero(scip, cutelem) is true and hope it doesn't do much damage. */
437 cutelem = SCIPfrac(scip, rowelem);
438
439 if( cutelem > f0 )
440 {
441 /* cut element if f > f0 */
442 cutelem = -((1.0 - cutelem) * ratiof0compl);
443 }
444 else
445 {
446 /* cut element if f <= f0 */
447 cutelem = -cutelem;
448 }
449 }
450 else
451 {
452 if( rowelem < 0.0 )
453 {
454 /* cut element if f < 0 */
455 cutelem = rowelem * ratiof0compl;
456 }
457 else
458 {
459 /* cut element if f >= 0 */
460 cutelem = -rowelem;
461 }
462 }
463
464 if( ! SCIPisZero(scip, cutelem) )
465 {
466 /* Coefficient is large enough, we can keep it. */
467 SCIP_COL** rowcols;
468 SCIP_Real* rowvals;
469
470 SCIP_Real act;
471 SCIP_Real rlhs;
472 SCIP_Real rrhs;
473 SCIP_Real rhsslack;
474
475 /* get lhs/rhs */
476 rlhs = SCIProwGetLhs(row);
477 rrhs = SCIProwGetRhs(row);
478 assert( SCIPisLE(scip, rlhs, rrhs) );
479 assert( ! SCIPisInfinity(scip, rlhs) || ! SCIPisInfinity(scip, rrhs) );
480
481 /* If the slack variable is fixed, we can ignore this cut coefficient. */
482 if( SCIPisFeasZero(scip, rrhs - rlhs) )
483 continue;
484
485 act = SCIPgetRowLPActivity(scip, row);
486 rhsslack = rrhs - act;
487
488 /* Unflip slack variable and adjust rhs if necessary. */
490 {
491 /* If >= or ranged constraint, flip element back to original */
492 assert( ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) );
493 cutelem = -cutelem;
494 }
495
496 rowcols = SCIProwGetCols(row);
497 rowvals = SCIProwGetVals(row);
498
499 /* Eliminate slack variable. */
500 for( i = 0; i < SCIProwGetNLPNonz(row); ++i )
501 workcoefs[SCIPcolGetLPPos(rowcols[i])] -= cutelem * rowvals[i];
502
503 if ( SCIPisFeasZero(scip, rhsslack) )
504 *cutrhs -= cutelem * (rrhs - SCIProwGetConstant(row));
505 else
506 {
507 assert( SCIPisFeasZero(scip, act - rlhs) );
508 *cutrhs -= cutelem * (rlhs - SCIProwGetConstant(row));
509 }
510 }
511 } /* for( c = 0; c < nrows; ++c) */
512
513 /* Initialize cut activity. */
514 *cutact = 0.0;
515
516 /* Modify cut to make it numerically safer, and check that it is numerically safe. */
517 success = modifyAndPackCut(scip, sepadata, ncols, cols, workcoefs, cutcoefs, cutind, cutnz, cutrhs);
518 if ( success )
519 {
520 success = checkNumerics(scip, sepadata, ncols, cols, cutcoefs, cutind, *cutnz, *cutrhs, cutact);
521 SCIPdebugMsg(scip, "checkNumerics returned: %u.\n", success);
522 return success;
523 }
524 SCIPdebugMsg(scip, "modifyAndPackCut was not successful.\n");
525
526 return FALSE;
527}
528
529
530/*
531 * Callback methods
532 */
533
534/** copy method for separator plugins (called when SCIP copies plugins) */
535static
537{ /*lint --e{715}*/
538 assert(scip != NULL);
539 assert(sepa != NULL);
540 assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
541
542 /* call inclusion method of constraint handler */
544
545 return SCIP_OKAY;
546}
547
548/** destructor of separator to free user data (called when SCIP is exiting) */
549static
551{ /*lint --e{715}*/
552 SCIP_SEPADATA* sepadata;
553
554 assert(scip != NULL);
555 assert(sepa != NULL);
556 assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
557
558 /* free separator data */
559 sepadata = SCIPsepaGetData(sepa);
560 assert(sepadata != NULL);
561
562 SCIPfreeBlockMemory(scip, &sepadata);
563
564 SCIPsepaSetData(sepa, NULL);
565
566 return SCIP_OKAY;
567}
568
569/** LP solution separation method of separator */
570static
572{ /*lint --e{715}*/
573 char cutname[SCIP_MAXSTRLEN];
574 SCIP_SEPADATA* sepadata;
575 SCIP_VAR** vars;
576 SCIP_COL** cols;
577 SCIP_ROW** rows;
578 SCIP_Real* binvrow;
579 SCIP_Real* binvarow;
580 SCIP_Real* cutcoefs;
581 SCIP_Real* workcoefs;
582 SCIP_Real cutrhs;
583 int* cutind;
584 int* basisind;
585 int nvars;
586 int ncols;
587 int nrows;
588 int ncalls;
589 int maxsepacuts;
590 int ncuts;
591 int cutnz;
592 int c;
593 int i;
594 int j;
595
596 assert(sepa != NULL);
597 assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
598 assert(scip != NULL);
599 assert(result != NULL);
600
601 *result = SCIP_DIDNOTRUN;
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
619 sepadata = SCIPsepaGetData(sepa);
620 assert(sepadata != NULL);
621
622 ncalls = SCIPsepaGetNCallsAtNode(sepa);
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 */
630 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
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
640 *result = SCIP_DIDNOTFIND;
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;
667 SCIP_Real primsol;
668
669 tryrow = FALSE;
670 c = basisind[i];
671 primsol = SCIP_INVALID;
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)) )
703 primsol = SCIProwGetLhs(row) - SCIPgetRowLPActivity(scip, row);
704 else
705 primsol = SCIProwGetRhs(row) - SCIPgetRowLPActivity(scip, row);
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 {
761 assert(SCIPisFeasNegative(scip, cutrhs));
762 SCIPdebugMsg(scip, " -> GMI cut detected infeasibility with cut 0 <= %f.\n", cutrhs);
763 *result = SCIP_CUTOFF;
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 )
791 *result = SCIP_CUTOFF;
792 else
793 *result = SCIP_SEPARATED;
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{
828 SCIP_SEPADATA* sepadata;
829 SCIP_SEPA* sepa;
830
831 /* create separator data */
832 SCIP_CALL( SCIPallocBlockMemory(scip, &sepadata) );
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 NULL
Definition: def.h:266
#define SCIP_MAXSTRLEN
Definition: def.h:287
#define SCIP_REAL_MAX
Definition: def.h:173
#define SCIP_INVALID
Definition: def.h:192
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:242
#define SCIP_Real
Definition: def.h:172
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:238
#define REALABS(x)
Definition: def.h:196
#define EPSZ(x, eps)
Definition: def.h:202
#define SCIP_CALL(x)
Definition: def.h:373
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:734
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition: scip_prob.c:1866
#define SCIPdebugMsg
Definition: scip_message.h:78
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)
Definition: scip_branch.c:428
int SCIPcolGetLPPos(SCIP_COL *col)
Definition: lp.c:17093
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:17042
SCIP_Bool SCIPcolIsIntegral(SCIP_COL *col)
Definition: lp.c:17072
SCIP_Real SCIPcolGetLb(SCIP_COL *col)
Definition: lp.c:16963
SCIP_Real SCIPcolGetPrimsol(SCIP_COL *col)
Definition: lp.c:16996
SCIP_Real SCIPcolGetUb(SCIP_COL *col)
Definition: lp.c:16973
SCIP_BASESTAT SCIPcolGetBasisStatus(SCIP_COL *col)
Definition: lp.c:17031
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:361
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:250
SCIP_RETCODE SCIPgetLPBasisInd(SCIP *scip, int *basisind)
Definition: scip_lp.c:686
SCIP_RETCODE SCIPgetLPColsData(SCIP *scip, SCIP_COL ***cols, int *ncols)
Definition: scip_lp.c:471
SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition: scip_lp.c:570
SCIP_RETCODE SCIPgetLPBInvARow(SCIP *scip, int r, SCIP_Real *binvrow, SCIP_Real *coefs, int *inds, int *ninds)
Definition: scip_lp.c:785
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:168
SCIP_Bool SCIPisLPSolBasic(SCIP *scip)
Definition: scip_lp.c:667
SCIP_RETCODE SCIPgetLPBInvRow(SCIP *scip, int r, SCIP_Real *coefs, int *inds, int *ninds)
Definition: scip_lp.c:714
#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:17391
SCIP_Real SCIPgetRowMaxCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1922
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:17292
SCIP_Real SCIPgetRowMinCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1904
SCIP_Bool SCIProwIsModifiable(SCIP_ROW *row)
Definition: lp.c:17411
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1635
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:17213
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:17238
SCIP_Real SCIPgetRowLPActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1993
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17302
int SCIProwGetNLPNonz(SCIP_ROW *row)
Definition: lp.c:17227
SCIP_Real SCIProwGetNorm(SCIP_ROW *row)
Definition: lp.c:17268
int SCIProwGetLPPos(SCIP_ROW *row)
Definition: lp.c:17501
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1658
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1701
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2212
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:17351
SCIP_Real SCIPgetRowActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:2104
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1562
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:1453
SCIP_Real SCIProwGetConstant(SCIP_ROW *row)
Definition: lp.c:17258
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:17248
SCIP_BASESTAT SCIProwGetBasisStatus(SCIP_ROW *row)
Definition: lp.c:17340
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:109
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition: sepa.c:743
int SCIPsepaGetNCallsAtNode(SCIP_SEPA *sepa)
Definition: sepa.c:880
SCIP_RETCODE SCIPsetSepaFree(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAFREE((*sepafree)))
Definition: scip_sepa.c:167
SCIP_SEPADATA * SCIPsepaGetData(SCIP_SEPA *sepa)
Definition: sepa.c:633
void SCIPsepaSetData(SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata)
Definition: sepa.c:643
SCIP_RETCODE SCIPsetSepaCopy(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPACOPY((*sepacopy)))
Definition: scip_sepa.c:151
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)
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17583
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17418
SCIP_Real SCIPgetVarSol(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:2307
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10880
#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
Definition: sepa_gmi.c:81
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:276
#define SEPA_DELAY
Definition: sepa_gmi.c:85
#define DEFAULT_DYNAMICCUTS
Definition: sepa_gmi.c:91
#define SEPA_DESC
Definition: sepa_gmi.c:80
static SCIP_DECL_SEPAEXECLP(sepaExeclpGMI)
Definition: sepa_gmi.c:571
#define DEFAULT_MAX_SUPP_ABS
Definition: sepa_gmi.c:100
#define DEFAULT_MAXROUNDSROOT
Definition: sepa_gmi.c:88
#define SEPA_USESSUBSCIP
Definition: sepa_gmi.c:84
#define DEFAULT_MIN_VIOLATION
Definition: sepa_gmi.c:95
#define DEFAULT_EPS_COEFF
Definition: sepa_gmi.c:96
#define DEFAULT_MAXSEPACUTSROOT
Definition: sepa_gmi.c:90
#define DEFAULT_EPS_RELAX_REL
Definition: sepa_gmi.c:98
#define SEPA_MAXBOUNDDIST
Definition: sepa_gmi.c:83
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:135
#define DEFAULT_AWAY
Definition: sepa_gmi.c:94
#define SEPA_FREQ
Definition: sepa_gmi.c:82
static SCIP_DECL_SEPACOPY(sepaCopyGMI)
Definition: sepa_gmi.c:536
#define DEFAULT_MAX_SUPP_REL
Definition: sepa_gmi.c:101
#define DEFAULT_MAXSEPACUTS
Definition: sepa_gmi.c:89
#define SEPA_NAME
Definition: sepa_gmi.c:79
#define DEFAULT_MAXROUNDS
Definition: sepa_gmi.c:87
#define DEFAULT_MAX_DYN
Definition: sepa_gmi.c:99
static SCIP_DECL_SEPAFREE(sepaFreeGMI)
Definition: sepa_gmi.c:550
#define DEFAULT_EPS_RELAX_ABS
Definition: sepa_gmi.c:97
#define DEFAULT_SEPARATEROWS
Definition: sepa_gmi.c:92
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:212
Gomory Mixed-Integer Cuts.
@ SCIP_LPSOLSTAT_OPTIMAL
Definition: type_lp.h:43
@ 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_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
struct SCIP_SepaData SCIP_SEPADATA
Definition: type_sepa.h:52
@ SCIP_VARTYPE_CONTINUOUS
Definition: type_var.h:71