SCIP

    Solving Constraint Integer Programs

    sepa_gomory.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-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/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file sepa_gomory.c
    26 * @ingroup DEFPLUGINS_SEPA
    27 * @brief Gomory MIR Cuts
    28 * @author Tobias Achterberg
    29 * @author Stefan Heinz
    30 * @author Domenico Salvagnin
    31 * @author Marc Pfetsch
    32 * @author Leona Gottwald
    33 */
    34
    35/**@todo try k-Gomory-cuts (s. Cornuejols: K-Cuts: A Variation of Gomory Mixed Integer Cuts from the LP Tableau)
    36 *
    37 * @todo Try cuts on the objective tableau row.
    38 *
    39 * @todo Also try negative basis inverse row?
    40 *
    41 * @todo It happens that the SCIPcalcMIR() function returns with the same cut for different calls. Check if this is a
    42 * bug or do not use it for the MIP below and turn off presolving and all heuristics:
    43 *
    44 * Max y
    45 * Subject to
    46 * c1: -x + y <= 1
    47 * c2: 2x + 3y <= 12
    48 * c3: 3x + 2y <= 12
    49 * Bounds
    50 * 0 <= x
    51 * 0 <= y
    52 * General
    53 * x
    54 * y
    55 * END
    56 */
    57
    58/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    59
    61#include "scip/cuts.h"
    62#include "scip/pub_lp.h"
    63#include "scip/pub_lpexact.h"
    64#include "scip/pub_message.h"
    65#include "scip/pub_misc.h"
    66#include "scip/pub_misc_sort.h"
    67#include "scip/pub_sepa.h"
    68#include "scip/pub_var.h"
    69#include "scip/scip_branch.h"
    71#include "scip/scip_cut.h"
    72#include "scip/scip_exact.h"
    73#include "scip/scip_general.h"
    74#include "scip/scip_lp.h"
    75#include "scip/scip_lpexact.h"
    76#include "scip/scip_mem.h"
    77#include "scip/scip_message.h"
    78#include "scip/scip_numerics.h"
    79#include "scip/scip_param.h"
    80#include "scip/scip_prob.h"
    82#include "scip/scip_sepa.h"
    84#include "scip/scip_tree.h"
    85#include "scip/scip_var.h"
    86#include "scip/sepa_gomory.h"
    87
    88
    89#define SEPA_NAME "gomory"
    90#define SEPA_DESC "separator for Gomory mixed-integer and strong CG cuts from LP tableau rows"
    91#define SEPA_PRIORITY -1000
    92#define SEPA_FREQ 10
    93#define SEPA_MAXBOUNDDIST 1.0
    94#define SEPA_USESSUBSCIP FALSE /**< does the separator use a secondary SCIP instance? */
    95#define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
    96
    97#define DEFAULT_MAXROUNDS 5 /**< maximal number of gomory separation rounds per node (-1: unlimited) */
    98#define DEFAULT_MAXROUNDSROOT 10 /**< maximal number of gomory separation rounds in the root node (-1: unlimited) */
    99#define DEFAULT_MAXSEPACUTS 50 /**< maximal number of gomory cuts separated per separation round */
    100#define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of gomory cuts separated per separation round in root node */
    101#define DEFAULT_MAXRANK -1 /**< maximal rank of a gomory cut that could not be scaled to integral coefficients (-1: unlimited) */
    102#define DEFAULT_MAXRANKINTEGRAL -1 /**< maximal rank of a gomory cut that could be scaled to integral coefficients (-1: unlimited) */
    103#define DEFAULT_DYNAMICCUTS TRUE /**< should generated cuts be removed from the LP if they are no longer tight? */
    104#define DEFAULT_AWAY 0.01 /**< minimal integrality violation of a basis variable in order to try Gomory cut */
    105#define DEFAULT_MAKEINTEGRAL FALSE /**< try to scale all cuts to integral coefficients */
    106#define DEFAULT_FORCECUTS TRUE /**< if conversion to integral coefficients failed still consider the cut */
    107#define DEFAULT_SEPARATEROWS TRUE /**< separate rows with integral slack */
    108#define DEFAULT_DELAYEDCUTS FALSE /**< should cuts be added to the delayed cut pool? */
    109#define DEFAULT_SIDETYPEBASIS TRUE /**< choose side types of row (lhs/rhs) based on basis information? */
    110#define DEFAULT_TRYSTRONGCG TRUE /**< try to generate strengthened Chvatal-Gomory cuts? */
    111#define DEFAULT_GENBOTHGOMSCG TRUE /**< should both Gomory and strong CG cuts be generated (otherwise take best) */
    112#define DEFAULT_RANDSEED 53 /**< initial random seed */
    113
    114#define BOUNDSWITCH 0.9999 /**< threshold for bound switching - see SCIPcalcMIR() */
    115#define POSTPROCESS TRUE /**< apply postprocessing after MIR calculation - see SCIPcalcMIR() */
    116#define VARTYPEUSEVBDS 2 /**< We allow variable bound substitution for variables with continuous vartype only.
    117 * See SCIPcalcMIR() for more information. */
    118#define FIXINTEGRALRHS FALSE /**< try to generate an integral rhs - see SCIPcalcMIR() */
    119#define MAKECONTINTEGRAL FALSE /**< convert continuous variable to integral variables in SCIPmakeRowIntegral() */
    120
    121#define MAXAGGRLEN(nvars) (0.1*(nvars)+1000) /**< maximal length of base inequality */
    122
    123
    124/** separator data */
    125struct SCIP_SepaData
    126{
    127 SCIP_RANDNUMGEN* randnumgen; /**< random number generator */
    128 SCIP_SEPA* strongcg; /**< strong CG cut separator */
    129 SCIP_SEPA* gomory; /**< gomory cut separator */
    130 SCIP_Real away; /**< minimal integrality violation of a basis variable in order to try Gomory cut */
    131 int maxrounds; /**< maximal number of gomory separation rounds per node (-1: unlimited) */
    132 int maxroundsroot; /**< maximal number of gomory separation rounds in the root node (-1: unlimited) */
    133 int maxsepacuts; /**< maximal number of gomory cuts separated per separation round */
    134 int maxsepacutsroot; /**< maximal number of gomory cuts separated per separation round in root node */
    135 int maxrank; /**< maximal rank of a gomory cut that could not be scaled to integral coefficients (-1: unlimited) */
    136 int maxrankintegral; /**< maximal rank of a gomory cut that could be scaled to integral coefficients (-1: unlimited) */
    137 int lastncutsfound; /**< total number of cuts found after last call of separator */
    138 SCIP_Bool dynamiccuts; /**< should generated cuts be removed from the LP if they are no longer tight? */
    139 SCIP_Bool makeintegral; /**< try to scale all cuts to integral coefficients */
    140 SCIP_Bool forcecuts; /**< if conversion to integral coefficients failed still consider the cut */
    141 SCIP_Bool separaterows; /**< separate rows with integral slack */
    142 SCIP_Bool delayedcuts; /**< should cuts be added to the delayed cut pool? */
    143 SCIP_Bool sidetypebasis; /**< choose side types of row (lhs/rhs) based on basis information? */
    144 SCIP_Bool trystrongcg; /**< try to generate strengthened Chvatal-Gomory cuts? */
    145 SCIP_Bool genbothgomscg; /**< should both Gomory and strong CG cuts be generated (otherwise take best) */
    146};
    147
    148
    149/** returns TRUE if the cut can be taken, otherwise FALSE if there some numerical evidences */
    150static
    152 SCIP* scip, /**< SCIP data structure */
    153 SCIP_SEPADATA* sepadata, /**< data of the separator */
    154 SCIP_ROW* cut, /**< cut to check */
    155 SCIP_Longint maxdnom, /**< maximal denominator to use for scaling */
    156 SCIP_Real maxscale, /**< maximal scaling factor */
    157 SCIP_Bool* useful /**< pointer to store if the cut is useful */
    158 )
    159{
    160 SCIP_Bool madeintegral = FALSE;
    161
    162 assert(useful != NULL);
    163
    164 *useful = FALSE;
    165
    166 if( sepadata->makeintegral && SCIPgetRowNumIntCols(scip, cut) == SCIProwGetNNonz(cut) )
    167 {
    168 /* try to scale the cut to integral values */
    170 maxdnom, maxscale, MAKECONTINTEGRAL, &madeintegral) );
    171
    172 if( !madeintegral && !sepadata->forcecuts )
    173 return SCIP_OKAY;
    174
    175 /* in case the right hand side is plus infinity (due to scaling) the cut is useless so we are not taking it at all */
    176 if( madeintegral && SCIPisInfinity(scip, SCIProwGetRhs(cut)) )
    177 return SCIP_OKAY;
    178 }
    179
    180 /* discard integral cut if the rank is too high */
    181 if( madeintegral && sepadata->maxrankintegral != -1 && (SCIProwGetRank(cut) > sepadata->maxrankintegral) )
    182 return SCIP_OKAY;
    183
    184 /* discard cut if the rank is too high */
    185 if( !madeintegral && (sepadata->maxrank != -1) && (SCIProwGetRank(cut) > sepadata->maxrank) )
    186 return SCIP_OKAY;
    187
    188 *useful = TRUE;
    189
    190 return SCIP_OKAY;
    191}
    192
    193
    194/** add cut */
    195static
    197 SCIP* scip, /**< SCIP instance */
    198 SCIP_SEPADATA* sepadata, /**< separator data */
    199 SCIP_VAR** vars, /**< array of variables */
    200 int c, /**< index of basic variable (< 0 for slack variables) */
    201 SCIP_Longint maxdnom, /**< maximal denominator to use for scaling */
    202 SCIP_Real maxscale, /**< maximal scaling factor */
    203 int cutnnz, /**< number of nonzeros in cut */
    204 int* cutinds, /**< variable indices in cut */
    205 SCIP_Real* cutcoefs, /**< cut cofficients */
    206 SCIP_Real cutefficacy, /**< cut efficacy */
    207 SCIP_Real cutrhs, /**< rhs of cut */
    208 SCIP_Bool cutislocal, /**< whether cut is local */
    209 int cutrank, /**< rank of cut */
    210 SCIP_Bool strongcg, /**< whether the cut arises from the strong-CG procedure */
    211 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff appeared */
    212 int* naddedcuts /**< pointer to store number of added cuts */
    213 )
    214{
    215 int j;
    216
    217 assert(scip != NULL);
    218 assert(cutoff != NULL);
    219 assert(naddedcuts != NULL);
    220
    221 if( cutnnz == 0 && SCIPisFeasNegative(scip, cutrhs) && !SCIPisExact(scip) ) /*lint !e644*/
    222 {
    223 SCIPdebugMsg(scip, " -> gomory cut detected infeasibility with cut 0 <= %g.\n", cutrhs);
    224 *cutoff = TRUE;
    225 return SCIP_OKAY;
    226 }
    227
    228 /* Only take efficient cuts, except for cuts with one non-zero coefficient (= bound
    229 * changes); the latter cuts will be handled internally in sepastore. */
    230 if( SCIPisEfficacious(scip, cutefficacy) || ( cutnnz == 1 && SCIPisFeasPositive(scip, cutefficacy) ) )
    231 {
    232 SCIP_ROW* cut;
    233 SCIP_SEPA* cutsepa;
    234 char cutname[SCIP_MAXSTRLEN];
    235 int v;
    236
    237 /* construct cut name */
    238 if( strongcg )
    239 {
    240 cutsepa = sepadata->strongcg;
    241
    242 if( c >= 0 )
    243 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "scg%" SCIP_LONGINT_FORMAT "_x%d", SCIPgetNLPs(scip), c);
    244 else
    245 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "scg%" SCIP_LONGINT_FORMAT "_s%d", SCIPgetNLPs(scip), -c-1);
    246 }
    247 else
    248 {
    249 cutsepa = sepadata->gomory;
    250
    251 if( c >= 0 )
    252 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "gom%" SCIP_LONGINT_FORMAT "_x%d", SCIPgetNLPs(scip), c);
    253 else
    254 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "gom%" SCIP_LONGINT_FORMAT "_s%d", SCIPgetNLPs(scip), -c-1);
    255 }
    256
    257 if( SCIPisExact(scip) )
    258 {
    259 SCIP_ROUNDMODE roundmode;
    260
    261 roundmode = SCIPintervalGetRoundingMode();
    263 /* postprocess cut for exact solving, i.e. change almost integer values to integer by weakening side */
    264 for( j = 0; j < cutnnz; j++ )
    265 {
    266 if( SCIPisIntegral(scip, cutcoefs[j]) )
    267 {
    268 SCIP_Real roundedval = SCIPround(scip, cutcoefs[j]);
    269 SCIP_Real delta = roundedval - cutcoefs[j];
    270 SCIP_VAR* var = vars[cutinds[j]];
    271 SCIP_Real sideval;
    272
    273 if( delta == 0 )
    274 continue;
    275
    276 if( cutislocal )
    277 sideval = delta > 0 ? SCIPvarGetUbLocal(var) : SCIPvarGetLbLocal(var);
    278 else
    279 sideval = delta > 0 ? SCIPvarGetUbGlobal(var) : SCIPvarGetLbGlobal(var);
    280
    281 if( SCIPisInfinity(scip, REALABS(sideval)) )
    282 continue;
    283
    284 cutcoefs[j]= roundedval;
    285 cutrhs += delta * sideval;
    286 }
    287 }
    289 }
    290
    291 /* create empty cut */
    292 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, cutsepa, cutname, -SCIPinfinity(scip), cutrhs,
    293 cutislocal, FALSE, sepadata->dynamiccuts) );
    294
    295 /* set cut rank */
    296 SCIProwChgRank(cut, cutrank); /*lint !e644*/
    297
    298 /* cache the row extension and only flush them if the cut gets added */
    300
    301 /* collect all non-zero coefficients */
    302 for( v = 0; v < cutnnz; ++v )
    303 {
    304 SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[cutinds[v]], cutcoefs[v]) );
    305 }
    306
    307 /* flush all changes before adding the cut */
    309
    310 if( SCIProwGetNNonz(cut) == 0 && !SCIPisExact(scip) )
    311 {
    312 assert( SCIPisFeasNegative(scip, cutrhs) );
    313 SCIPdebugMsg(scip, " -> gomory cut detected infeasibility with cut 0 <= %g.\n", cutrhs);
    314 *cutoff = TRUE;
    315 return SCIP_OKAY;
    316 }
    317 else if( SCIProwGetNNonz(cut) == 1 )
    318 {
    319 /* Add the bound change as cut to avoid that the LP gets modified. This would mean that the LP is not flushed
    320 * and the method SCIPgetLPBInvRow() fails; SCIP internally will apply this bound change automatically. */
    321 SCIP_CALL( SCIPaddRow(scip, cut, TRUE, cutoff) );
    322 ++(*naddedcuts);
    323 if( SCIPisCertified(scip) )
    324 {
    327 }
    328 }
    329 else
    330 {
    331 SCIP_Bool useful;
    332
    333 assert(SCIPisInfinity(scip, -SCIProwGetLhs(cut)));
    334 assert(!SCIPisInfinity(scip, SCIProwGetRhs(cut)));
    335
    336 SCIPdebugMsg(scip, " -> %s cut <%s>: rhs=%f, eff=%f\n", strongcg ? "strong-CG" : "gomory", cutname, cutrhs, cutefficacy);
    337
    338 SCIP_CALL( evaluateCutNumerics(scip, sepadata, cut, maxdnom, maxscale, &useful) );
    339
    340 if( useful )
    341 {
    342 SCIPdebugMsg(scip, " -> found %s cut <%s>: act=%f, rhs=%f, norm=%f, eff=%f, min=%f, max=%f (range=%f)\n",
    343 strongcg ? "strong-CG" : "gomory", cutname, SCIPgetRowLPActivity(scip, cut), SCIProwGetRhs(cut),
    347
    349
    350 if( SCIPisCutNew(scip, cut) )
    351 {
    352 /* add global cuts which are not implicit bound changes to the cut pool */
    353 if( !cutislocal )
    354 {
    355 if( sepadata->delayedcuts )
    356 {
    358 }
    359 else
    360 {
    362 }
    363 }
    364 else
    365 {
    366 /* local cuts we add to the sepastore */
    367 SCIP_CALL( SCIPaddRow(scip, cut, FALSE, cutoff) );
    368 }
    369
    370 ++(*naddedcuts);
    371
    372 /* For certification we need to create the exact representation of the row; we need to perform this here
    373 * because the certificate uses the current variable bounds; if certification is not active, we delay the
    374 * creation of the exact row until the cut is actually selected to enter the LP, see sepastore.c.
    375 *
    376 * Note that this can lead to different solving paths when solving with/without certification, because
    377 * the floating-point coefficients can change slightly during the creation of the exact row (if rational
    378 * coefficients are rounded to smaller denominators) and this may affect cut selection.
    379 */
    380 if( SCIPisCertified(scip) )
    381 {
    384
    385 if( SCIProwGetRowExact(cut) == NULL )
    386 {
    387 /**@todo delay creation of exact row for globally valid cuts */
    388 if( !cutislocal )
    389 {
    393 }
    394 else
    395 {
    397 }
    398 }
    399
    401 }
    402 }
    403 }
    404 }
    405 /* release the row */
    406 SCIP_CALL( SCIPreleaseRow(scip, &cut) );
    407 }
    408
    409 return SCIP_OKAY;
    410}
    411
    412/*
    413 * Callback methods
    414 */
    415
    416/** copy method for separator plugins (called when SCIP copies plugins) */
    417static
    418SCIP_DECL_SEPACOPY(sepaCopyGomory)
    419{ /*lint --e{715}*/
    420 assert(scip != NULL);
    421 assert(sepa != NULL);
    422
    424
    425 /* call inclusion method of separator */
    427
    428 return SCIP_OKAY;
    429}
    430
    431/** destructor of separator to free user data (called when SCIP is exiting) */
    432/**! [SnippetSepaFreeGomory] */
    433static
    434SCIP_DECL_SEPAFREE(sepaFreeGomory)
    435{ /*lint --e{715}*/
    436 SCIP_SEPADATA* sepadata;
    437
    439
    440 /* free separator data */
    441 sepadata = SCIPsepaGetData(sepa);
    442 assert(sepadata != NULL);
    443
    444 SCIPfreeBlockMemory(scip, &sepadata);
    445
    446 SCIPsepaSetData(sepa, NULL);
    447
    448 return SCIP_OKAY;
    449}
    450/**! [SnippetSepaFreeGomory] */
    451
    452/** initialization method of separator (called after problem was transformed) */
    453static
    454SCIP_DECL_SEPAINIT(sepaInitGomory)
    455{
    456 SCIP_SEPADATA* sepadata;
    457
    458 sepadata = SCIPsepaGetData(sepa);
    459 assert(sepadata != NULL);
    460
    461 /* create and initialize random number generator */
    462 SCIP_CALL( SCIPcreateRandom(scip, &sepadata->randnumgen, DEFAULT_RANDSEED, TRUE) );
    463
    464 return SCIP_OKAY;
    465}
    466
    467/** deinitialization method of separator (called before transformed problem is freed) */
    468static
    469SCIP_DECL_SEPAEXIT(sepaExitGomory)
    470{ /*lint --e{715}*/
    471 SCIP_SEPADATA* sepadata;
    472
    473 sepadata = SCIPsepaGetData(sepa);
    474 assert(sepadata != NULL);
    475
    476 SCIPfreeRandom(scip, &sepadata->randnumgen);
    477
    478 return SCIP_OKAY;
    479}
    480
    481
    482/** LP solution separation method of separator */
    483static
    484SCIP_DECL_SEPAEXECLP(sepaExeclpGomory)
    485{ /*lint --e{715}*/
    486 SCIP_SEPADATA* sepadata;
    487 SCIP_VAR** vars;
    488 SCIP_COL** cols;
    489 SCIP_ROW** rows;
    490 SCIP_AGGRROW* aggrrow;
    491 SCIP_VAR* var;
    492 SCIP_Real* binvrow;
    493 SCIP_Real* cutcoefs;
    494 SCIP_Real* basisfrac;
    495 SCIP_Real* cutefficacies;
    496 int* basisind;
    497 int* basisperm;
    498 int* inds;
    499 int* cutinds;
    500 int* colindsproducedcut;
    501 SCIP_Real maxscale;
    502 SCIP_Real minfrac;
    503 SCIP_Real maxfrac;
    504 SCIP_Real maxcutefficacy;
    505 SCIP_Longint maxdnom;
    506 SCIP_Bool cutoff;
    507 SCIP_Bool separatescg;
    508 SCIP_Bool separategmi;
    509 int naddedcuts;
    510 int nvars;
    511 int ncols;
    512 int nrows;
    513 int ncalls;
    514 int maxdepth;
    515 int maxsepacuts;
    516 int freq;
    517 int c;
    518 int i;
    519 int j;
    520
    521 assert(sepa != NULL);
    522 assert(scip != NULL);
    523 assert(result != NULL);
    524
    526
    527 *result = SCIP_DIDNOTRUN;
    528
    529 sepadata = SCIPsepaGetData(sepa);
    530 assert(sepadata != NULL);
    531
    532 ncalls = SCIPsepaGetNCallsAtNode(sepa);
    533
    534 minfrac = sepadata->away;
    535 maxfrac = 1.0 - sepadata->away;
    536
    537 /* only call separator, if we are not close to terminating */
    538 if( SCIPisStopped(scip) )
    539 return SCIP_OKAY;
    540
    541 /* only call the gomory cut separator a given number of times at each node */
    542 if( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot)
    543 || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) )
    544 return SCIP_OKAY;
    545
    546 /* only call separator, if an optimal LP solution is at hand */
    548 return SCIP_OKAY;
    549
    550 /* only call separator, if the LP solution is basic */
    551 if( !SCIPisLPSolBasic(scip) )
    552 return SCIP_OKAY;
    553
    554 /* only call separator, if there are fractional variables */
    555 if( SCIPgetNLPBranchCands(scip) == 0 )
    556 return SCIP_OKAY;
    557
    558 /* check whether strong CG cuts should be separated */
    559 freq = SCIPsepaGetFreq(sepadata->strongcg);
    560 if( freq > 0 )
    561 separatescg = (depth % freq == 0);
    562 else
    563 separatescg = (freq == depth);
    564
    565 /* check whether Gomory MI cuts should be separated */
    566 freq = SCIPsepaGetFreq(sepadata->gomory);
    567 if( freq > 0 )
    568 separategmi = (depth % freq == 0);
    569 else
    570 separategmi = (freq == depth);
    571
    572 if( !separatescg && !separategmi )
    573 return SCIP_OKAY;
    574
    575 /* get variables data */
    576 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
    577
    578 /* get LP data */
    579 SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
    580 SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
    581 if( ncols == 0 || nrows == 0 )
    582 return SCIP_OKAY;
    583
    584 /* set the maximal denominator in rational representation of gomory cut and the maximal scale factor to
    585 * scale resulting cut to integral values to avoid numerical instabilities
    586 */
    587 /**@todo find better but still stable gomory cut settings: look at dcmulti, gesa3, khb0525, misc06, p2756 */
    588 maxdepth = SCIPgetMaxDepth(scip);
    589 if( depth == 0 )
    590 {
    591 maxdnom = 1000;
    592 maxscale = 1000.0;
    593 }
    594 else if( depth <= maxdepth/4 )
    595 {
    596 maxdnom = 1000;
    597 maxscale = 1000.0;
    598 }
    599 else if( depth <= maxdepth/2 )
    600 {
    601 maxdnom = 100;
    602 maxscale = 100.0;
    603 }
    604 else
    605 {
    606 maxdnom = 10;
    607 maxscale = 10.0;
    608 }
    609
    610 /* allocate temporary memory */
    611 SCIP_CALL( SCIPallocBufferArray(scip, &cutcoefs, nvars) );
    612 SCIP_CALL( SCIPallocClearBufferArray(scip, &cutinds, nvars) );
    613 SCIP_CALL( SCIPallocBufferArray(scip, &basisind, nrows) );
    614 SCIP_CALL( SCIPallocBufferArray(scip, &basisperm, nrows) );
    615 SCIP_CALL( SCIPallocBufferArray(scip, &basisfrac, nrows) );
    616 SCIP_CALL( SCIPallocBufferArray(scip, &binvrow, nrows) );
    617 SCIP_CALL( SCIPallocBufferArray(scip, &inds, nrows) );
    618 SCIP_CALL( SCIPallocBufferArray(scip, &cutefficacies, nrows) );
    619 SCIP_CALL( SCIPallocBufferArray(scip, &colindsproducedcut, nrows) );
    620 SCIP_CALL( SCIPaggrRowCreate(scip, &aggrrow) );
    621
    622 /* get basis indices */
    623 SCIP_CALL( SCIPgetLPBasisInd(scip, basisind) );
    624
    625 for( i = 0; i < nrows; ++i )
    626 {
    627 SCIP_Real frac = 0.0;
    628
    629 c = basisind[i];
    630 cutefficacies[i] = 0.0;
    631
    632 basisperm[i] = i;
    633
    634 colindsproducedcut[i] = -1;
    635
    636 if( c >= 0 )
    637 {
    638 assert(c < ncols);
    639 var = SCIPcolGetVar(cols[c]);
    641 {
    642 frac = SCIPfeasFrac(scip, SCIPcolGetPrimsol(cols[c]));
    643 frac = MIN(frac, 1.0 - frac);
    644 }
    645 }
    646 else if( sepadata->separaterows )
    647 {
    648 SCIP_ROW* row;
    649
    650 assert(0 <= -c-1 && -c-1 < nrows);
    651 row = rows[-c-1];
    652 /* We allow separating on rows with a 'slack' implied integral variable */
    654 {
    656 frac = MIN(frac, 1.0 - frac);
    657 }
    658 }
    659
    660 if( frac >= minfrac )
    661 {
    662 /* slightly change fractionality to have random order for equal fractions */
    663 basisfrac[i] = frac + SCIPrandomGetReal(sepadata->randnumgen, -1e-6, 1e-6);
    664 }
    665 else
    666 {
    667 basisfrac[i] = 0.0;
    668 }
    669 }
    670
    671 /* sort basis indices by fractionality */
    672 SCIPsortDownRealInt(basisfrac, basisperm, nrows);
    673
    674 /* get the maximal number of cuts allowed in a separation round */
    675 if( depth == 0 )
    676 maxsepacuts = sepadata->maxsepacutsroot;
    677 else
    678 maxsepacuts = sepadata->maxsepacuts;
    679
    680 SCIPdebugMsg(scip, "searching gomory cuts: %d cols, %d rows, maxdnom=%" SCIP_LONGINT_FORMAT ", maxscale=%g, maxcuts=%d\n",
    681 ncols, nrows, maxdnom, maxscale, maxsepacuts);
    682
    683 cutoff = FALSE;
    684 naddedcuts = 0;
    685
    686 /* for all basic columns belonging to integer variables, try to generate a gomory cut */
    687 for( i = 0; i < nrows && naddedcuts < maxsepacuts && !SCIPisStopped(scip) && !cutoff; ++i )
    688 {
    689 SCIP_Real cutrhs;
    690 SCIP_Real cutefficacy = 0.0;
    691 SCIP_Bool success;
    692 SCIP_Bool cutislocal;
    693 SCIP_Bool strongcgsuccess = FALSE;
    694 int ninds = -1;
    695 int cutnnz;
    696 int cutrank;
    697
    698 if( basisfrac[i] == 0.0 )
    699 break;
    700
    701 j = basisperm[i];
    702 c = basisind[j];
    703
    704 /* get the row of B^-1 for this basic integer variable with fractional solution value */
    705 SCIP_CALL( SCIPgetLPBInvRow(scip, j, binvrow, inds, &ninds) );
    706
    707 SCIP_CALL( SCIPaggrRowSumRows(scip, aggrrow, binvrow, inds, ninds,
    708 sepadata->sidetypebasis, allowlocal, SCIPallowNegSlack(scip) ? 2 : 0, (int) MAXAGGRLEN(nvars), &success) );
    709
    710 if( !success )
    711 continue;
    712
    713 /* try to create a strong CG cut out of the aggregation row */
    714 if( separatescg && !SCIPisExact(scip) )
    715 {
    716 SCIP_CALL( SCIPcalcStrongCG(scip, NULL, POSTPROCESS, BOUNDSWITCH, VARTYPEUSEVBDS, allowlocal, minfrac, maxfrac,
    717 1.0, aggrrow, cutcoefs, &cutrhs, cutinds, &cutnnz, &cutefficacy, &cutrank, &cutislocal, &strongcgsuccess) );
    718
    719 /* if we want to generate both cuts, add cut and reset cutefficacy and strongcgsuccess */
    720 if( strongcgsuccess && sepadata->genbothgomscg )
    721 {
    722 assert(allowlocal || !cutislocal); /*lint !e644*/
    723 SCIP_CALL( addCut(scip, sepadata, vars, c, maxdnom, maxscale, cutnnz, cutinds, cutcoefs, cutefficacy, cutrhs,
    724 cutislocal, cutrank, TRUE, &cutoff, &naddedcuts) );
    725 if( c >= 0 )
    726 {
    727 cutefficacies[i] = cutefficacy;
    728 colindsproducedcut[i] = c;
    729 }
    730 cutefficacy = 0.0;
    731 strongcgsuccess = FALSE;
    732 if( cutoff )
    733 break;
    734 }
    735 }
    736 /* try to create Gomory cut out of the aggregation row */
    737 if( separategmi )
    738 {
    739 /* SCIPcalcMIR will only override the cut if its efficacy is larger than the one of the strongcg cut */
    741 minfrac, maxfrac, 1.0, aggrrow, cutcoefs, &cutrhs, cutinds, &cutnnz, &cutefficacy, &cutrank, &cutislocal, &success) );
    742
    743 if( success || strongcgsuccess )
    744 {
    745 assert(allowlocal || !cutislocal); /*lint !e644*/
    746 if( success )
    747 strongcgsuccess = FALSE; /* Set strongcgsuccess to FALSE, since the MIR cut has overriden the strongcg cut. */
    748
    749 SCIP_CALL( addCut(scip, sepadata, vars, c, maxdnom, maxscale, cutnnz, cutinds, cutcoefs, cutefficacy, cutrhs,
    750 cutislocal, cutrank, strongcgsuccess, &cutoff, &naddedcuts) );
    751 if( c >= 0 )
    752 {
    753 cutefficacies[i] = cutefficacy;
    754 colindsproducedcut[i] = c;
    755 }
    756 }
    757 }
    758 if( SCIPisCertified(scip) )
    759 {
    762 }
    763 }
    764
    765 /* Add normalized efficacy GMI statistics to history */
    766 maxcutefficacy = 0.0;
    767 for( i = 0; i < nrows; ++i )
    768 {
    769 if( cutefficacies[i] > maxcutefficacy && colindsproducedcut[i] >= 0 )
    770 {
    771 maxcutefficacy = cutefficacies[i];
    772 }
    773 }
    774
    775 for( i = 0; i < nrows; ++i )
    776 {
    777 if( colindsproducedcut[i] >= 0 && SCIPisEfficacious(scip, cutefficacies[i]) )
    778 {
    779 assert( maxcutefficacy > 0.0 );
    780 var = SCIPcolGetVar(cols[colindsproducedcut[i]]);
    781 SCIP_CALL( SCIPsetVarLastGMIScore(scip, var, cutefficacies[i] / maxcutefficacy) );
    782 SCIP_CALL( SCIPincVarGMISumScore(scip, var, cutefficacies[i] / maxcutefficacy) );
    783 }
    784 }
    785
    786 /* free temporary memory */
    787 SCIPaggrRowFree(scip, &aggrrow);
    788 SCIPfreeBufferArray(scip, &colindsproducedcut);
    789 SCIPfreeBufferArray(scip, &cutefficacies);
    791 SCIPfreeBufferArray(scip, &binvrow);
    792 SCIPfreeBufferArray(scip, &basisfrac);
    793 SCIPfreeBufferArray(scip, &basisperm);
    794 SCIPfreeBufferArray(scip, &basisind);
    795 SCIPfreeBufferArray(scip, &cutinds);
    796 SCIPfreeBufferArray(scip, &cutcoefs);
    797
    798 SCIPdebugMsg(scip, "end searching gomory cuts: found %d cuts\n", naddedcuts);
    799
    800 sepadata->lastncutsfound = SCIPgetNCutsFound(scip);
    801
    802 /* evaluate the result of the separation */
    803 if( cutoff )
    804 *result = SCIP_CUTOFF;
    805 else if ( naddedcuts > 0 )
    806 *result = SCIP_SEPARATED;
    807 else
    808 *result = SCIP_DIDNOTFIND;
    809
    810 return SCIP_OKAY;
    811}
    812
    813
    814/*
    815 * separator specific interface methods
    816 */
    817
    818/** LP solution separation method of dummy separator */
    819static
    820SCIP_DECL_SEPAEXECLP(sepaExeclpDummy)
    821{ /*lint --e{715}*/
    822 assert( result != NULL );
    823
    824 *result = SCIP_DIDNOTRUN;
    825
    826 return SCIP_OKAY;
    827}
    828
    829/** arbitrary primal solution separation method of dummy separator */
    830static
    831SCIP_DECL_SEPAEXECSOL(sepaExecsolDummy)
    832{ /*lint --e{715}*/
    833 assert( result != NULL );
    834
    835 *result = SCIP_DIDNOTRUN;
    836
    837 return SCIP_OKAY;
    838}
    839
    840/** creates the Gomory MIR cut separator and includes it in SCIP */
    842 SCIP* scip /**< SCIP data structure */
    843 )
    844{
    845 SCIP_SEPADATA* sepadata;
    846 SCIP_SEPA* sepa;
    847
    848 /* create separator data */
    849 SCIP_CALL( SCIPallocBlockMemory(scip, &sepadata) );
    850 sepadata->lastncutsfound = 0;
    851
    852 /* include separator */
    855 sepaExeclpGomory, NULL,
    856 sepadata) );
    857
    858 assert(sepa != NULL);
    859
    860 /* gomory is safe to use in exact solving mode */
    861 SCIPsepaMarkExact(sepa);
    862
    863 SCIP_CALL( SCIPincludeSepaBasic(scip, &sepadata->strongcg, "strongcg", "separator for strong CG cuts", -100000, SEPA_FREQ, 0.0,
    864 SEPA_USESSUBSCIP, FALSE, sepaExeclpDummy, sepaExecsolDummy, NULL) );
    865 assert(sepadata->strongcg != NULL);
    866
    867 SCIP_CALL( SCIPincludeSepaBasic(scip, &sepadata->gomory, "gomorymi", "separator for Gomory mixed-integer cuts", -100000, SEPA_FREQ, 0.0,
    868 SEPA_USESSUBSCIP, FALSE, sepaExeclpDummy, sepaExecsolDummy, NULL) );
    869 assert(sepadata->gomory != NULL);
    870
    871 /* set non-NULL pointers to callback methods */
    872 SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyGomory) );
    873 SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeGomory) );
    874 SCIP_CALL( SCIPsetSepaInit(scip, sepa, sepaInitGomory) );
    875 SCIP_CALL( SCIPsetSepaExit(scip, sepa, sepaExitGomory) );
    876
    877 /* mark main separator as a parent */
    879
    880 /* set pointer from child separators to main separator */
    881 SCIPsetSepaParentsepa(scip, sepadata->strongcg, sepa);
    882 SCIPsetSepaParentsepa(scip, sepadata->gomory, sepa);
    883
    884 /* add separator parameters */
    886 "separating/gomory/maxrounds",
    887 "maximal number of gomory separation rounds per node (-1: unlimited)",
    888 &sepadata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
    890 "separating/gomory/maxroundsroot",
    891 "maximal number of gomory separation rounds in the root node (-1: unlimited)",
    892 &sepadata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
    894 "separating/gomory/maxsepacuts",
    895 "maximal number of gomory cuts separated per separation round",
    896 &sepadata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
    898 "separating/gomory/maxsepacutsroot",
    899 "maximal number of gomory cuts separated per separation round in the root node",
    900 &sepadata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
    902 "separating/gomory/maxrank",
    903 "maximal rank of a gomory cut that could not be scaled to integral coefficients (-1: unlimited)",
    904 &sepadata->maxrank, FALSE, DEFAULT_MAXRANK, -1, INT_MAX, NULL, NULL) );
    906 "separating/gomory/maxrankintegral",
    907 "maximal rank of a gomory cut that could be scaled to integral coefficients (-1: unlimited)",
    908 &sepadata->maxrankintegral, FALSE, DEFAULT_MAXRANKINTEGRAL, -1, INT_MAX, NULL, NULL) );
    910 "separating/gomory/away",
    911 "minimal integrality violation of a basis variable in order to try Gomory cut",
    912 &sepadata->away, FALSE, DEFAULT_AWAY, 1e-4, 0.5, NULL, NULL) );
    914 "separating/gomory/dynamiccuts",
    915 "should generated cuts be removed from the LP if they are no longer tight?",
    916 &sepadata->dynamiccuts, FALSE, DEFAULT_DYNAMICCUTS, NULL, NULL) );
    918 "separating/gomory/makeintegral",
    919 "try to scale cuts to integral coefficients",
    920 &sepadata->makeintegral, TRUE, DEFAULT_MAKEINTEGRAL, NULL, NULL) );
    922 "separating/gomory/forcecuts",
    923 "if conversion to integral coefficients failed still consider the cut",
    924 &sepadata->forcecuts, TRUE, DEFAULT_FORCECUTS, NULL, NULL) );
    926 "separating/gomory/separaterows",
    927 "separate rows with integral slack",
    928 &sepadata->separaterows, TRUE, DEFAULT_SEPARATEROWS, NULL, NULL) );
    930 "separating/gomory/delayedcuts",
    931 "should cuts be added to the delayed cut pool?",
    932 &sepadata->delayedcuts, TRUE, DEFAULT_DELAYEDCUTS, NULL, NULL) );
    934 "separating/gomory/sidetypebasis",
    935 "choose side types of row (lhs/rhs) based on basis information?",
    936 &sepadata->sidetypebasis, TRUE, DEFAULT_SIDETYPEBASIS, NULL, NULL) );
    938 "separating/gomory/trystrongcg",
    939 "try to generate strengthened Chvatal-Gomory cuts?",
    940 &sepadata->trystrongcg, TRUE, DEFAULT_TRYSTRONGCG, NULL, NULL) );
    942 "separating/gomory/genbothgomscg",
    943 "Should both Gomory and strong CG cuts be generated (otherwise take best)?",
    944 &sepadata->genbothgomscg, TRUE, DEFAULT_GENBOTHGOMSCG, NULL, NULL) );
    945
    946 return SCIP_OKAY;
    947}
    methods for the aggregation rows
    #define NULL
    Definition: def.h:257
    #define SCIP_MAXSTRLEN
    Definition: def.h:278
    #define SCIP_Longint
    Definition: def.h:150
    #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 SCIP_LONGINT_FORMAT
    Definition: def.h:157
    #define REALABS(x)
    Definition: def.h:191
    #define SCIP_CALL(x)
    Definition: def.h:364
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:767
    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
    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:436
    SCIP_RETCODE SCIPfreeCertificateActiveMirInfo(SCIP *scip)
    SCIP_RETCODE SCIPstoreCertificateActiveAggrInfo(SCIP *scip, SCIP_ROW *row)
    SCIP_Bool SCIPisCertified(SCIP *scip)
    SCIP_RETCODE SCIPfreeCertificateActiveAggrInfo(SCIP *scip)
    SCIP_RETCODE SCIPcertifyMirCut(SCIP *scip, SCIP_ROW *row)
    SCIP_RETCODE SCIPstoreCertificateActiveMirInfo(SCIP *scip, SCIP_ROW *row)
    SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
    Definition: lp.c:17425
    SCIP_Real SCIPcolGetPrimsol(SCIP_COL *col)
    Definition: lp.c:17379
    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_RETCODE SCIPcalcMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, int vartypeusevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real scale, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
    Definition: cuts.c:7934
    SCIP_RETCODE SCIPaggrRowCreate(SCIP *scip, SCIP_AGGRROW **aggrrow)
    Definition: cuts.c:2679
    SCIP_Bool SCIPisCutNew(SCIP *scip, SCIP_ROW *row)
    Definition: scip_cut.c:318
    SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
    Definition: scip_cut.c:135
    SCIP_RETCODE SCIPcalcStrongCG(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, int vartypeusevbds, SCIP_Bool allowlocal, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real scale, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
    Definition: cuts.c:13313
    void SCIPaggrRowFree(SCIP *scip, SCIP_AGGRROW **aggrrow)
    Definition: cuts.c:2711
    SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
    Definition: scip_cut.c:225
    SCIP_RETCODE SCIPaggrRowSumRows(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Real *weights, int *rowinds, int nrowinds, SCIP_Bool sidetypebasis, SCIP_Bool allowlocal, int negslack, int maxaggrlen, SCIP_Bool *valid)
    Definition: cuts.c:3534
    SCIP_RETCODE SCIPdelPoolCut(SCIP *scip, SCIP_ROW *row)
    Definition: scip_cut.c:356
    SCIP_RETCODE SCIPaddDelayedPoolCut(SCIP *scip, SCIP_ROW *row)
    Definition: scip_cut.c:616
    SCIP_Bool SCIPallowNegSlack(SCIP *scip)
    Definition: scip_exact.c:212
    SCIP_Bool SCIPisExact(SCIP *scip)
    Definition: scip_exact.c:193
    void SCIPintervalSetRoundingModeUpwards(void)
    SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
    void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
    int SCIP_ROUNDMODE
    Definition: intervalarith.h:65
    SCIP_RETCODE SCIPcreateRowExactFromRow(SCIP *scip, SCIP_ROW *fprow)
    Definition: scip_lpexact.c:285
    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_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 SCIPallocClearBufferArray(scip, ptr, num)
    Definition: scip_mem.h:126
    #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_Real SCIPgetRowLPActivity(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1957
    SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
    Definition: lp.c:17696
    SCIP_Real SCIProwGetNorm(SCIP_ROW *row)
    Definition: lp.c:17662
    SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1604
    int SCIPgetRowNumImpliedIntCols(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1850
    SCIP_RETCODE SCIPmakeRowIntegral(SCIP *scip, SCIP_ROW *row, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Bool usecontvars, SCIP_Bool *success)
    Definition: scip_lp.c:1790
    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
    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
    int SCIProwGetRank(SCIP_ROW *row)
    Definition: lp.c:17775
    void SCIProwChgRank(SCIP_ROW *row, int rank)
    Definition: lp.c:17928
    SCIP_ROWEXACT * SCIProwGetRowExact(SCIP_ROW *row)
    Definition: lp.c:17959
    int SCIPgetRowNumIntCols(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1832
    SCIP_RETCODE SCIPsetSepaExit(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAEXIT((*sepaexit)))
    Definition: scip_sepa.c:205
    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
    int SCIPsepaGetFreq(SCIP_SEPA *sepa)
    Definition: sepa.c:790
    const char * SCIPsepaGetName(SCIP_SEPA *sepa)
    Definition: sepa.c:746
    int SCIPsepaGetNCallsAtNode(SCIP_SEPA *sepa)
    Definition: sepa.c:893
    SCIP_RETCODE SCIPsetSepaFree(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAFREE((*sepafree)))
    Definition: scip_sepa.c:173
    void SCIPsepaMarkExact(SCIP_SEPA *sepa)
    Definition: sepa.c:811
    SCIP_SEPADATA * SCIPsepaGetData(SCIP_SEPA *sepa)
    Definition: sepa.c:636
    void SCIPsepaSetData(SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata)
    Definition: sepa.c:646
    void SCIPsetSepaIsParentsepa(SCIP *scip, SCIP_SEPA *sepa)
    Definition: scip_sepa.c:309
    SCIP_RETCODE SCIPsetSepaCopy(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPACOPY((*sepacopy)))
    Definition: scip_sepa.c:157
    void SCIPsetSepaParentsepa(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPA *parentsepa)
    Definition: scip_sepa.c:324
    SCIP_RETCODE SCIPsetSepaInit(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAINIT((*sepainit)))
    Definition: scip_sepa.c:189
    int SCIPgetMaxDepth(SCIP *scip)
    SCIP_Longint SCIPgetNLPs(SCIP *scip)
    int SCIPgetNCutsFound(SCIP *scip)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPfeasFrac(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPepsilon(SCIP *scip)
    SCIP_Real SCIPsumepsilon(SCIP *scip)
    SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
    SCIP_RETCODE SCIPincVarGMISumScore(SCIP *scip, SCIP_VAR *var, SCIP_Real gmieff)
    Definition: scip_var.c:12375
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24300
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23485
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24174
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24266
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24152
    SCIP_RETCODE SCIPsetVarLastGMIScore(SCIP *scip, SCIP_VAR *var, SCIP_Real gmieff)
    Definition: scip_var.c:12429
    void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
    SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
    Definition: misc.c:10245
    SCIP_RETCODE SCIPcreateRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen, unsigned int initialseed, SCIP_Bool useglobalseed)
    SCIP_RETCODE SCIPincludeSepaGomory(SCIP *scip)
    Definition: sepa_gomory.c:841
    void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    memory allocation routines
    public methods for LP management
    public methods for LP management
    public methods for message output
    #define SCIPdebug(x)
    Definition: pub_message.h:93
    public data structures and miscellaneous methods
    methods for sorting joint arrays of various types
    public methods for separators
    public methods for problem variables
    public methods for branching rule plugins and branching
    public methods for certified solving
    public methods for cuts and aggregation rows
    public methods for exact solving
    general public methods
    public methods for the LP relaxation, rows and columns
    public methods for the LP relaxation, rows and columns
    public methods for memory management
    public methods for message handling
    public methods for numerical tolerances
    public methods for SCIP parameter handling
    public methods for global and local (sub)problems
    public methods for random numbers
    public methods for separator plugins
    public methods for querying solving statistics
    public methods for the branch-and-bound tree
    public methods for SCIP variables
    #define SEPA_PRIORITY
    Definition: sepa_gomory.c:91
    static SCIP_RETCODE addCut(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_VAR **vars, int c, SCIP_Longint maxdnom, SCIP_Real maxscale, int cutnnz, int *cutinds, SCIP_Real *cutcoefs, SCIP_Real cutefficacy, SCIP_Real cutrhs, SCIP_Bool cutislocal, int cutrank, SCIP_Bool strongcg, SCIP_Bool *cutoff, int *naddedcuts)
    Definition: sepa_gomory.c:196
    static SCIP_DECL_SEPAEXECLP(sepaExeclpGomory)
    Definition: sepa_gomory.c:484
    static SCIP_DECL_SEPAEXIT(sepaExitGomory)
    Definition: sepa_gomory.c:469
    #define DEFAULT_TRYSTRONGCG
    Definition: sepa_gomory.c:110
    #define BOUNDSWITCH
    Definition: sepa_gomory.c:114
    #define SEPA_DELAY
    Definition: sepa_gomory.c:95
    #define DEFAULT_DYNAMICCUTS
    Definition: sepa_gomory.c:103
    #define DEFAULT_MAKEINTEGRAL
    Definition: sepa_gomory.c:105
    #define POSTPROCESS
    Definition: sepa_gomory.c:115
    #define SEPA_DESC
    Definition: sepa_gomory.c:90
    #define DEFAULT_MAXRANKINTEGRAL
    Definition: sepa_gomory.c:102
    static SCIP_DECL_SEPAFREE(sepaFreeGomory)
    Definition: sepa_gomory.c:434
    #define MAKECONTINTEGRAL
    Definition: sepa_gomory.c:119
    #define DEFAULT_MAXROUNDSROOT
    Definition: sepa_gomory.c:98
    #define SEPA_USESSUBSCIP
    Definition: sepa_gomory.c:94
    #define DEFAULT_DELAYEDCUTS
    Definition: sepa_gomory.c:108
    #define VARTYPEUSEVBDS
    Definition: sepa_gomory.c:116
    #define DEFAULT_SIDETYPEBASIS
    Definition: sepa_gomory.c:109
    #define FIXINTEGRALRHS
    Definition: sepa_gomory.c:118
    static SCIP_DECL_SEPACOPY(sepaCopyGomory)
    Definition: sepa_gomory.c:418
    #define DEFAULT_MAXSEPACUTSROOT
    Definition: sepa_gomory.c:100
    #define DEFAULT_MAXRANK
    Definition: sepa_gomory.c:101
    #define SEPA_MAXBOUNDDIST
    Definition: sepa_gomory.c:93
    static SCIP_DECL_SEPAINIT(sepaInitGomory)
    Definition: sepa_gomory.c:454
    static SCIP_RETCODE evaluateCutNumerics(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_ROW *cut, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Bool *useful)
    Definition: sepa_gomory.c:151
    #define DEFAULT_AWAY
    Definition: sepa_gomory.c:104
    #define DEFAULT_FORCECUTS
    Definition: sepa_gomory.c:106
    #define SEPA_FREQ
    Definition: sepa_gomory.c:92
    #define DEFAULT_RANDSEED
    Definition: sepa_gomory.c:112
    #define MAXAGGRLEN(nvars)
    Definition: sepa_gomory.c:121
    static SCIP_DECL_SEPAEXECSOL(sepaExecsolDummy)
    Definition: sepa_gomory.c:831
    #define DEFAULT_MAXSEPACUTS
    Definition: sepa_gomory.c:99
    #define SEPA_NAME
    Definition: sepa_gomory.c:89
    #define DEFAULT_MAXROUNDS
    Definition: sepa_gomory.c:97
    #define DEFAULT_SEPARATEROWS
    Definition: sepa_gomory.c:107
    #define DEFAULT_GENBOTHGOMSCG
    Definition: sepa_gomory.c:111
    Gomory MIR Cuts.
    @ SCIP_LPSOLSTAT_OPTIMAL
    Definition: type_lp.h:44
    @ 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
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    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