Scippy

    SCIP

    Solving Constraint Integer Programs

    branch_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-2025 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 branch_gomory.c
    26 * @ingroup DEFPLUGINS_BRANCH
    27 * @brief Gomory cut branching rule
    28 * @author Mark Turner
    29 *
    30 * The approach is based on the following papers.
    31 *
    32 * M. Turner, T. Berthold, M. Besancon, T. Koch@n
    33 * Branching via Cutting Plane Selection: Improving Hybrid Branching,@n
    34 * arXiv preprint arXiv:2306.06050
    35 *
    36 * The Gomory cut branching rule selects a candidate integer variable $j$ with a fractional solution value.
    37 * Each candidate variable must be a basic variable in the LP Tableau (if not then it would have to be at its bound
    38 * that is integer-valued)
    39 * This branching rule calculates the GMI cut for the aggregated row of the LP tableau associated with the
    40 * candidate variable.
    41 * The generated cut is then scored using a weighted sum rule.
    42 * The branching candidate whose cut is highest scoring is then selected.
    43 * For more details on the method, see:
    44 *
    45 * @par
    46 * Mark Turner, Timo Berthold, Mathieu Besançon, Thorsten Koch@n
    47 * Branching via Cutting Plane Selection: Improving Hybrid Branching@n
    48 * 2023@n
    49 */
    50
    51/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    52
    53#include "scip/branch_gomory.h"
    54#include "scip/pub_branch.h"
    55#include "scip/pub_var.h"
    56#include "scip/pub_lp.h"
    57#include "scip/pub_tree.h"
    58#include "scip/pub_message.h"
    59#include "scip/scip_branch.h"
    60#include "scip/scip_cut.h"
    61#include "scip/scip_mem.h"
    62#include "scip/scip_message.h"
    63#include "scip/scip_numerics.h"
    64#include "scip/scip_lp.h"
    65#include "scip/scip_tree.h"
    66#include "scip/scip_param.h"
    68#include <string.h>
    69#include <assert.h>
    70
    71
    72
    73#define BRANCHRULE_NAME "gomory"
    74#define BRANCHRULE_DESC "Gomory cut score branching"
    75#define BRANCHRULE_PRIORITY -1000
    76#define BRANCHRULE_MAXDEPTH -1
    77#define BRANCHRULE_MAXBOUNDDIST 1.0
    78
    79#define DEFAULT_MAXNCANDS -1 /**< maximum number of branching candidates to produce a cut for */
    80#define DEFAULT_EFFICACYWEIGHT 1.0 /**< the weight of efficacy in weighted sum cut scoring rule */
    81#define DEFAULT_OBJPARALLELWEIGHT 0.0 /**< the weight of objective parallelism in weighted sum scoring rule */
    82#define DEFAULT_INTSUPPORTWEIGHT 0.0 /**< the weight of integer support in weighted sum cut scoring rule */
    83#define DEFAULT_PERFORMRELPSCOST FALSE /**< if relpscost branching should be called without actual branching */
    84#define DEFAULT_USEWEAKERCUTS TRUE /**< use weaker cuts derived from the exact branching split */
    85
    86
    87/*
    88 * Data structures
    89 */
    90
    91/** branching rule data */
    92struct SCIP_BranchruleData
    93{
    94 int maxncands; /**< maximum number of variable candidates to produce cut for */
    95 SCIP_Real efficacyweight; /**< the weight of efficacy in weighted sum cut scoring rule */
    96 SCIP_Real objparallelweight; /**< the weight of objective parallelism in weighted sum scoring rule */
    97 SCIP_Real intsupportweight; /**< the weight of integer support in weighted sum cut scoring rule */
    98 SCIP_Bool performrelpscost; /**< if relpscost branching should be called without actual branching */
    99 SCIP_Bool useweakercuts; /**< use weaker cuts derived from the exact branching split */
    100};
    101
    102
    103/*
    104 * Local methods
    105 */
    106
    107/** Generate GMI cut: The GMI is given by
    108 * sum(f_j x_j , j in J_I s.t. f_j <= f_0) +
    109 * sum((1-f_j)*f_0/(1 - f_0) x_j, j in J_I s.t. f_j > f_0) +
    110 * sum(a_j x_j, , j in J_C s.t. a_j >= 0) -
    111 * sum(a_j*f_0/(1-f_0) x_j , j in J_C s.t. a_j < 0) >= f_0.
    112 * where J_I are the integer non-basic variables and J_C are the continuous.
    113 * f_0 is the fractional part of lpval
    114 * a_j is the j-th coefficient of the tableau row and f_j its fractional part
    115 * Note: we create -% <= -f_0 !!
    116 * Note: this formula is valid for a problem of the form Ax = b, x>= 0. Since we do not have
    117 * such problem structure in general, we have to (implicitly) transform whatever we are given
    118 * to that form. Specifically, non-basic variables at their lower bound are shifted so that the lower
    119 * bound is 0 and non-basic at their upper bound are complemented. */
    120static
    122 SCIP* scip, /**< SCIP data structure */
    123 int ncols, /**< Number of columns (original variables) in the LP */
    124 int nrows, /**< Number of rows (slack variables) in the LP */
    125 SCIP_COL** cols, /**< Column data of the LP */
    126 SCIP_ROW** rows, /**< Row data of the LP */
    127 const SCIP_Real* binvrow, /**< row of B^-1 for current basic variable */
    128 const SCIP_Real* binvarow, /**< row of B^-1A for current basic variable */
    129 const SCIP_Real* lpval, /**< value of variable at current LP solution */
    130 SCIP_Real* cutcoefs, /**< array to store cut coefficients */
    131 SCIP_Real* cutrhs, /**< pointer to store rhs of cut */
    132 SCIP_Bool useweakerscuts /**< use weakener cuts derived from the exact branching split */
    133 )
    134{
    135 SCIP_COL** rowcols;
    136 SCIP_COL* col;
    137 SCIP_ROW* row;
    138 SCIP_Real* rowvals;
    139 SCIP_BASESTAT basestat;
    140 SCIP_Real rowelem;
    141 SCIP_Real cutelem;
    142 SCIP_Real f0;
    143 SCIP_Real f0complementratio;
    144 SCIP_Real rowrhs;
    145 SCIP_Real rowlhs;
    146 SCIP_Real rowact;
    147 SCIP_Real rowrhsslack;
    148 int i;
    149 int c;
    150
    151 /* Clear the memory array of cut coefficients. It may store that of the last computed cut */
    152 BMSclearMemoryArray(cutcoefs, ncols);
    153
    154 /* compute fractionality f0 and f0/(1-f0) */
    155 f0 = SCIPfeasFrac(scip, *lpval);
    156 f0complementratio = f0 / (1.0 - f0);
    157
    158 /* The rhs of the cut is the fractional part of the LP solution of the basic variable */
    159 *cutrhs = -f0;
    160
    161 /* Generate cut coefficient for the original variables */
    162 for ( c = 0; c < ncols; c++ )
    163 {
    164 col = cols[c];
    165 assert( col != NULL );
    166
    167 basestat = SCIPcolGetBasisStatus(col);
    168 /* Get simplex tableau coefficient */
    169 if ( basestat == SCIP_BASESTAT_LOWER )
    170 {
    171 /* Take coefficient if nonbasic at lower bound */
    172 rowelem = binvarow[c];
    173 }
    174 else if ( basestat == SCIP_BASESTAT_UPPER )
    175 {
    176 /* Flip coefficient if nonbasic at upper bound: x --> u - x */
    177 rowelem = -binvarow[c];
    178 }
    179 else
    180 {
    181 /* Nonbasic free variable at zero or basic variable. Just skip it. */
    182 continue;
    183 }
    184
    185 /* Integer variables */
    186 if ( SCIPcolIsIntegral(col) && !useweakerscuts )
    187 {
    188 /* Warning: Because of numerics we can have cutelem < 0
    189 * In such a case it is very close to 0, so isZero will catch and we can ignore the coefficient */
    190 cutelem = SCIPfrac(scip, rowelem);
    191 if ( cutelem > f0 )
    192 {
    193 /* sum((1 - f_j) * f_0/(1 - f_0) x_j, j in J_I s.t. f_j > f_0 */
    194 cutelem = -((1.0 - cutelem) * f0complementratio);
    195 }
    196 else
    197 {
    198 /* sum(f_j * x_j, j in J_I s.t. f_j <= 0 */
    199 cutelem = -cutelem;
    200 }
    201 }
    202 /* Then continuous variables */
    203 else
    204 {
    205 if ( rowelem < 0 )
    206 {
    207 /* sum(a_j* f_0/(1 - f_0) x_j, j in J_C s.t. a_j < 0 */
    208 cutelem = rowelem * f0complementratio;
    209 }
    210 else
    211 {
    212 /* sum(a_j * x_j, j in J_C s.t. a_j >= 0 */
    213 cutelem = -rowelem;
    214 }
    215 }
    216
    217 /* Cut is defined when variables are in [0, infinity). Translate to general bounds. */
    218 if ( !SCIPisZero(scip, cutelem) )
    219 {
    220 if ( basestat == SCIP_BASESTAT_UPPER )
    221 {
    222 cutelem = -cutelem;
    223 *cutrhs += cutelem * SCIPcolGetUb(col);
    224 }
    225 else
    226 {
    227 *cutrhs += cutelem * SCIPcolGetLb(col);
    228 }
    229 /* Add coefficient to cut */
    230 cutcoefs[SCIPcolGetLPPos(col)] = cutelem;
    231 }
    232 }
    233
    234 /* generate cut coefficient for the slack variables. Skip the basic ones */
    235 for ( c = 0; c < nrows; c++ )
    236 {
    237 row = rows[c];
    238 assert( row != NULL );
    239 basestat = SCIProwGetBasisStatus(row);
    240
    241 /* Get the simplex tableau coefficient */
    242 if ( basestat == SCIP_BASESTAT_LOWER )
    243 {
    244 /* Take coefficient if nonbasic at lower bound */
    245 rowelem = binvrow[SCIProwGetLPPos(row)];
    246 /* If there is a >= constraint or ranged constraint at the lower bound, we have to flip the row element */
    247 if ( !SCIPisInfinity(scip, -SCIProwGetLhs(row)) )
    248 rowelem = -rowelem;
    249 }
    250 else if ( basestat == SCIP_BASESTAT_UPPER )
    251 {
    252 /* Take element if nonbasic at upper bound. Only non-positive slack variables can be nonbasic at upper,
    253 * therefore they should be flipped twice, meaning we can take the element directly */
    254 rowelem = binvrow[SCIProwGetLPPos(row)];
    255 }
    256 else
    257 {
    258 /* Nonbasic free variable at zero or basic variable. Free variable should not happen here. Just skip if free */
    259 assert( basestat == SCIP_BASESTAT_BASIC );
    260 continue;
    261 }
    262
    263 /* Integer rows */
    264 if ( SCIProwIsIntegral(row) && !SCIProwIsModifiable(row) && !useweakerscuts )
    265 {
    266 /* Warning: Because of numerics we can have cutelem < 0
    267 * In such a case it is very close to 0, so isZero will catch and we can ignore the coefficient */
    268 cutelem = SCIPfrac(scip, rowelem);
    269 if ( cutelem > f0 )
    270 {
    271 /* sum((1 - f_j) * f_0/(1 - f_0) x_j, j in J_I s.t. f_j > f_0 */
    272 cutelem = -((1.0 - cutelem) * f0complementratio);
    273 }
    274 else
    275 {
    276 /* sum(f_j * x_j, j in J_I s.t. f_j <= 0 */
    277 cutelem = -cutelem;
    278 }
    279 }
    280 /* Then continuous variables */
    281 else
    282 {
    283 if ( rowelem < 0 )
    284 {
    285 /* sum(a_j* f_0/(1 - f_0) x_j, j in J_C s.t. a_j < 0 */
    286 cutelem = rowelem * f0complementratio;
    287 }
    288 else
    289 {
    290 /* sum(a_j * x_j, j in J_C s.t. a_j >= 0 */
    291 cutelem = -rowelem;
    292 }
    293 }
    294
    295 /* Cut is defined in original variables, so we replace slack variables by their original definition */
    296 if ( !SCIPisZero(scip, cutelem) )
    297 {
    298 /* Coefficient is large enough so we keep it */
    299 rowlhs = SCIProwGetLhs(row);
    300 rowrhs = SCIProwGetRhs(row);
    301 assert( SCIPisLE(scip, rowlhs, rowrhs) );
    302 assert( !SCIPisInfinity(scip, rowlhs) || !SCIPisInfinity(scip, rowrhs) );
    303
    304 /* If the slack variable is fixed we can ignore this cut coefficient */
    305 if ( SCIPisFeasZero(scip, rowrhs - rowlhs) )
    306 continue;
    307
    308 /* Un-flip sack variable and adjust rhs if necessary.
    309 * Row at lower basis means the slack variable is at its upper bound.
    310 * Since SCIP adds +1 slacks, this can only happen when constraints have finite lhs */
    312 {
    313 assert( !SCIPisInfinity(scip, -rowlhs) );
    314 cutelem = -cutelem;
    315 }
    316
    317 rowcols = SCIProwGetCols(row);
    318 rowvals = SCIProwGetVals(row);
    319
    320 /* Eliminate slack variables. rowcols is sorted [columns in LP, columns not in LP] */
    321 for ( i = 0; i < SCIProwGetNLPNonz(row); i++ )
    322 cutcoefs[SCIPcolGetLPPos(rowcols[i])] -= cutelem * rowvals[i];
    323
    324 /* Modify the rhs */
    325 rowact = SCIPgetRowActivity(scip, row);
    326 rowrhsslack = rowrhs - rowact;
    327
    328 if ( SCIPisFeasZero(scip, rowrhsslack) )
    329 *cutrhs -= cutelem * (rowrhs - SCIProwGetConstant(row));
    330 else
    331 {
    332 assert( SCIPisFeasZero(scip, rowact - rowlhs) );
    333 *cutrhs -= cutelem * (rowlhs - SCIProwGetConstant(row));
    334 }
    335 }
    336 }
    337}
    338
    339
    340/*
    341 * Callback methods of branching rule
    342 */
    343
    344
    345/** copy method for branchrule plugins (called when SCIP copies plugins) */
    346static
    347SCIP_DECL_BRANCHCOPY(branchCopyGomory)
    348{ /*lint --e{715}*/
    349 assert(scip != NULL);
    350 assert(branchrule != NULL);
    351 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
    352
    353 /* call inclusion method of branchrule */
    355
    356 return SCIP_OKAY;
    357}
    358
    359
    360/** destructor of branching rule to free user data (called when SCIP is exiting) */
    361static
    362SCIP_DECL_BRANCHFREE(branchFreeGomory)
    363{ /*lint --e{715}*/
    364 SCIP_BRANCHRULEDATA* branchruledata;
    365
    366 /* free branching rule data */
    367 branchruledata = SCIPbranchruleGetData(branchrule);
    368 assert(branchruledata != NULL);
    369
    370 SCIPfreeBlockMemoryNull(scip, &branchruledata);
    371
    372 return SCIP_OKAY;
    373}
    374
    375
    376/** branching execution method for fractional LP solutions */
    377static
    378SCIP_DECL_BRANCHEXECLP(branchExeclpGomory)
    379{ /*lint --e{715}*/
    380 SCIP_BRANCHRULEDATA* branchruledata;
    381 SCIP_VAR** lpcands;
    382 SCIP_COL** cols;
    383 SCIP_ROW** rows;
    384 SCIP_Real* lpcandssol;
    385 SCIP_Real* lpcandsfrac;
    386 SCIP_Real* binvrow;
    387 SCIP_Real* binvarow;
    388 SCIP_Real* cutcoefs;
    389 SCIP_ROW* cut;
    390 SCIP_COL* col;
    391 int* basisind;
    392 int* basicvarpos2tableaurow;
    393 int* inds;
    394 const char* name;
    395 SCIP_Real cutrhs;
    396 SCIP_Real score;
    397 SCIP_Real bestscore;
    398 int nlpcands;
    399 int maxncands;
    400 int ncols;
    401 int nrows;
    402 int lppos;
    403 int ninds;
    404 int bestcand;
    405 int i;
    406 int j;
    407
    408 name = (char *) "test";
    409
    410 assert(branchrule != NULL);
    411 assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
    412 assert(scip != NULL);
    413 assert(result != NULL);
    414
    415 SCIPdebugMsg(scip, "Execlp method of Gomory branching in node %" SCIP_LONGINT_FORMAT "\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip)));
    416
    418 {
    419 *result = SCIP_DIDNOTRUN;
    420 SCIPdebugMsg(scip, "Could not apply Gomory branching, as the current LP was not solved to optimality.\n");
    421
    422 return SCIP_OKAY;
    423 }
    424
    425 /* Get branching candidates */
    426 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, NULL, &nlpcands, NULL) );
    427 assert(nlpcands > 0);
    428
    429 *result = SCIP_DIDNOTRUN;
    430
    431 /* Get branching rule data */
    432 branchruledata = SCIPbranchruleGetData(branchrule);
    433 assert(branchruledata != NULL);
    434
    435 /* Compute the reliability pseudo-cost branching scores for the candidates */
    436 if ( branchruledata->performrelpscost )
    437 {
    438 /* We do not branch using this rule, but if enabled do take all the bound and conflict inferences made */
    439 SCIP_CALL( SCIPexecRelpscostBranching(scip, lpcands, lpcandssol, lpcandsfrac, nlpcands, FALSE, result) );
    440 assert(*result == SCIP_DIDNOTRUN || *result == SCIP_CUTOFF || *result == SCIP_REDUCEDDOM);
    441 }
    442
    443 /* Return SCIP_OKAY if relpscost has shown that this node can be cutoff or some variable domains have changed */
    444 if( *result == SCIP_CUTOFF || *result == SCIP_REDUCEDDOM )
    445 {
    446 return SCIP_OKAY;
    447 }
    448
    449 /* Get the maximum number of LP branching candidates that we generate cuts for and score */
    450 if( branchruledata->maxncands >= 0 )
    451 {
    452 maxncands = MIN(nlpcands, branchruledata->maxncands);
    453 }
    454 else
    455 {
    456 maxncands = nlpcands;
    457 }
    458
    459 /* Get the Column and Row data */
    460 SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
    461 SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
    462
    463 /* Allocate temporary memory */
    464 SCIP_CALL( SCIPallocBufferArray(scip, &cutcoefs, ncols) );
    465 SCIP_CALL( SCIPallocBufferArray(scip, &basisind, nrows) );
    466 SCIP_CALL( SCIPallocBufferArray(scip, &basicvarpos2tableaurow, ncols) );
    467 SCIP_CALL( SCIPallocBufferArray(scip, &binvrow, nrows) );
    468 SCIP_CALL( SCIPallocBufferArray(scip, &binvarow, ncols) );
    469 SCIP_CALL( SCIPallocBufferArray(scip, &inds, nrows) );
    470
    471 /* Create basis indices mapping (from the column position to LP tableau rox index) */
    472 for( i = 0; i < ncols; ++i )
    473 {
    474 basicvarpos2tableaurow[i] = -1;
    475 }
    476 SCIP_CALL( SCIPgetLPBasisInd(scip, basisind) );
    477 for( i = 0; i < nrows; ++i )
    478 {
    479 if( basisind[i] >= 0 )
    480 basicvarpos2tableaurow[basisind[i]] = i;
    481 }
    482
    483 /* Initialise the best candidate */
    484 bestcand = 0;
    485 bestscore = -SCIPinfinity(scip);
    486 ninds = -1;
    487
    488 /* Iterate over candidates and get best cut score */
    489 for( i = 0; i < maxncands; i++ )
    490 {
    491 /* Initialise the score of the cut */
    492 score = 0;
    493
    494 /* Get the LP position of the branching candidate */
    495 col = SCIPvarGetCol(lpcands[i]);
    496 lppos = SCIPcolGetLPPos(col);
    497 assert(lppos != -1);
    498
    499 /* get the row of B^-1 for this basic integer variable with fractional solution value */
    500 SCIP_CALL( SCIPgetLPBInvRow(scip, basicvarpos2tableaurow[lppos], binvrow, inds, &ninds) );
    501
    502 /* Get the Tableau row for this basic integer variable with fractional solution value */
    503 SCIP_CALL( SCIPgetLPBInvARow(scip, basicvarpos2tableaurow[lppos], binvrow, binvarow, inds, &ninds) );
    504
    505 /* Compute the GMI cut */
    506 getGMIFromRow(scip, ncols, nrows, cols, rows, binvrow, binvarow, &lpcandssol[i], cutcoefs,
    507 &cutrhs, branchruledata->useweakercuts);
    508
    509 /* Calculate the weighted sum score of measures */
    510 cut = NULL;
    512 for( j = 0; j < ncols; ++j )
    513 {
    514 if( !SCIPisZero(scip, cutcoefs[j]) )
    515 {
    516 SCIP_CALL( SCIPaddVarToRow(scip, cut, SCIPcolGetVar(cols[j]), cutcoefs[SCIPcolGetLPPos(cols[j])]) );
    517 }
    518 }
    519 assert( SCIPgetCutEfficacy(scip, NULL, cut) >= -SCIPfeastol(scip) );
    520 if ( branchruledata-> efficacyweight != 0 )
    521 score += branchruledata->efficacyweight * SCIPgetCutEfficacy(scip, NULL, cut);
    522 if ( branchruledata->objparallelweight != 0 )
    523 score += branchruledata->objparallelweight * SCIPgetRowObjParallelism(scip, cut);
    524 if ( branchruledata->intsupportweight != 0 )
    525 score += branchruledata->intsupportweight * SCIPgetRowNumIntCols(scip, cut) / (SCIP_Real) SCIProwGetNNonz(cut);
    526 SCIP_CALL( SCIPreleaseRow(scip, &cut) );
    527
    528 /* Replace the best cut if score is higher */
    529 if (score > bestscore)
    530 {
    531 bestscore = score;
    532 bestcand = i;
    533 }
    534 }
    535
    536 /* Free temporary memory */
    538 SCIPfreeBufferArray(scip, &binvrow);
    539 SCIPfreeBufferArray(scip, &binvarow);
    540 SCIPfreeBufferArray(scip, &basicvarpos2tableaurow);
    541 SCIPfreeBufferArray(scip, &basisind);
    542 SCIPfreeBufferArray(scip, &cutcoefs);
    543
    544 SCIPdebugMsg(scip, " -> %d candidates, selected candidate %d: variable <%s> (frac=%g, factor=%g, score=%g)\n",
    545 nlpcands, bestcand, SCIPvarGetName(lpcands[bestcand]), lpcandsfrac[bestcand],
    546 SCIPvarGetBranchFactor(lpcands[bestcand]), bestscore);
    547
    548 /* Perform the branching */
    549 SCIP_CALL( SCIPbranchVar(scip, lpcands[bestcand], NULL, NULL, NULL) );
    550 *result = SCIP_BRANCHED;
    551
    552 return SCIP_OKAY;
    553}
    554
    555
    556/*
    557 * branching rule specific interface methods
    558 */
    559
    560/** creates the Gomory cut branching rule and includes it in SCIP */
    562 SCIP* scip /**< SCIP data structure */
    563 )
    564{
    565 SCIP_BRANCHRULEDATA* branchruledata;
    566 SCIP_BRANCHRULE* branchrule;
    567
    568 /* create branching rule data */
    569 SCIP_CALL( SCIPallocBlockMemory(scip, &branchruledata) );
    570
    571 /* include branching rule */
    574
    575 assert(branchrule != NULL);
    576
    577 /* set non-fundamental callbacks via specific setter functions*/
    578 SCIP_CALL( SCIPsetBranchruleCopy(scip, branchrule, branchCopyGomory) );
    579 SCIP_CALL( SCIPsetBranchruleFree(scip, branchrule, branchFreeGomory) );
    580 SCIP_CALL( SCIPsetBranchruleExecLp(scip, branchrule, branchExeclpGomory) );
    581
    582 /* Gomory cut branching rule parameters */
    583 SCIP_CALL( SCIPaddIntParam(scip,"branching/gomory/maxncands",
    584 "maximum amount of branching candidates to generate Gomory cuts for (-1: all candidates)",
    585 &branchruledata->maxncands, FALSE, DEFAULT_MAXNCANDS, -1, INT_MAX, NULL, NULL) );
    586 SCIP_CALL( SCIPaddRealParam(scip,"branching/gomory/efficacyweight",
    587 "weight of efficacy in the weighted sum cut scoring rule",
    588 &branchruledata->efficacyweight, FALSE, DEFAULT_EFFICACYWEIGHT, -1.0, 1.0, NULL, NULL) );
    589 SCIP_CALL( SCIPaddRealParam(scip,"branching/gomory/objparallelweight",
    590 "weight of objective parallelism in the weighted sum cut scoring rule",
    591 &branchruledata->objparallelweight, FALSE, DEFAULT_OBJPARALLELWEIGHT, -1.0, 1.0, NULL, NULL) );
    592 SCIP_CALL( SCIPaddRealParam(scip,"branching/gomory/intsupportweight",
    593 "weight of integer support in the weighted sum cut scoring rule",
    594 &branchruledata->intsupportweight, FALSE, DEFAULT_INTSUPPORTWEIGHT, -1.0, 1.0, NULL, NULL) );
    595 SCIP_CALL( SCIPaddBoolParam(scip,"branching/gomory/performrelpscost",
    596 "whether relpscost branching should be called without branching (used for bound inferences and conflicts)",
    597 &branchruledata->performrelpscost, FALSE, DEFAULT_PERFORMRELPSCOST, NULL, NULL) );
    598 SCIP_CALL( SCIPaddBoolParam(scip,"branching/gomory/useweakercuts",
    599 "use weaker cuts that are exactly derived from the branching split disjunction",
    600 &branchruledata->useweakercuts, FALSE, DEFAULT_USEWEAKERCUTS, NULL, NULL) );
    601
    602 return SCIP_OKAY;
    603}
    #define BRANCHRULE_DESC
    Definition: branch_gomory.c:74
    static SCIP_DECL_BRANCHFREE(branchFreeGomory)
    #define BRANCHRULE_PRIORITY
    Definition: branch_gomory.c:75
    #define DEFAULT_EFFICACYWEIGHT
    Definition: branch_gomory.c:80
    #define BRANCHRULE_NAME
    Definition: branch_gomory.c:73
    static SCIP_DECL_BRANCHCOPY(branchCopyGomory)
    static void getGMIFromRow(SCIP *scip, int ncols, int nrows, SCIP_COL **cols, SCIP_ROW **rows, const SCIP_Real *binvrow, const SCIP_Real *binvarow, const SCIP_Real *lpval, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, SCIP_Bool useweakerscuts)
    #define DEFAULT_OBJPARALLELWEIGHT
    Definition: branch_gomory.c:81
    static SCIP_DECL_BRANCHEXECLP(branchExeclpGomory)
    #define DEFAULT_PERFORMRELPSCOST
    Definition: branch_gomory.c:83
    #define BRANCHRULE_MAXDEPTH
    Definition: branch_gomory.c:76
    #define BRANCHRULE_MAXBOUNDDIST
    Definition: branch_gomory.c:77
    #define DEFAULT_USEWEAKERCUTS
    Definition: branch_gomory.c:84
    #define DEFAULT_INTSUPPORTWEIGHT
    Definition: branch_gomory.c:82
    #define DEFAULT_MAXNCANDS
    Definition: branch_gomory.c:79
    Gomory cut branching rule.
    reliable pseudo costs branching rule
    #define NULL
    Definition: def.h:248
    #define SCIP_Bool
    Definition: def.h:91
    #define MIN(x, y)
    Definition: def.h:224
    #define SCIP_Real
    Definition: def.h:156
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:148
    #define SCIP_CALL(x)
    Definition: def.h:355
    SCIP_RETCODE SCIPexecRelpscostBranching(SCIP *scip, SCIP_VAR **branchcands, SCIP_Real *branchcandssol, SCIP_Real *branchcandsfrac, int nbranchcands, SCIP_Bool executebranching, SCIP_RESULT *result)
    SCIP_RETCODE SCIPincludeBranchruleGomory(SCIP *scip)
    #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
    SCIP_RETCODE SCIPsetBranchruleExecLp(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHEXECLP((*branchexeclp)))
    Definition: scip_branch.c:256
    SCIP_RETCODE SCIPsetBranchruleCopy(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHCOPY((*branchcopy)))
    Definition: scip_branch.c:160
    SCIP_RETCODE SCIPincludeBranchruleBasic(SCIP *scip, SCIP_BRANCHRULE **branchruleptr, const char *name, const char *desc, int priority, int maxdepth, SCIP_Real maxbounddist, SCIP_BRANCHRULEDATA *branchruledata)
    Definition: scip_branch.c:123
    const char * SCIPbranchruleGetName(SCIP_BRANCHRULE *branchrule)
    Definition: branch.c:2018
    SCIP_BRANCHRULEDATA * SCIPbranchruleGetData(SCIP_BRANCHRULE *branchrule)
    Definition: branch.c:1886
    SCIP_RETCODE SCIPsetBranchruleFree(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_DECL_BRANCHFREE((*branchfree)))
    Definition: scip_branch.c:176
    SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
    Definition: scip_branch.c:402
    SCIP_RETCODE SCIPbranchVar(SCIP *scip, SCIP_VAR *var, SCIP_NODE **downchild, SCIP_NODE **eqchild, SCIP_NODE **upchild)
    Definition: scip_branch.c:1058
    int SCIPcolGetLPPos(SCIP_COL *col)
    Definition: lp.c:17487
    SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
    Definition: lp.c:17425
    SCIP_Bool SCIPcolIsIntegral(SCIP_COL *col)
    Definition: lp.c:17455
    SCIP_Real SCIPcolGetLb(SCIP_COL *col)
    Definition: lp.c:17346
    SCIP_Real SCIPcolGetUb(SCIP_COL *col)
    Definition: lp.c:17356
    SCIP_BASESTAT SCIPcolGetBasisStatus(SCIP_COL *col)
    Definition: lp.c:17414
    SCIP_Real SCIPgetCutEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
    Definition: scip_cut.c:94
    SCIP_RETCODE SCIPgetLPBasisInd(SCIP *scip, int *basisind)
    Definition: scip_lp.c:692
    SCIP_RETCODE SCIPgetLPColsData(SCIP *scip, SCIP_COL ***cols, int *ncols)
    Definition: scip_lp.c:477
    SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
    Definition: scip_lp.c:576
    SCIP_RETCODE SCIPgetLPBInvARow(SCIP *scip, int r, SCIP_Real *binvrow, SCIP_Real *coefs, int *inds, int *ninds)
    Definition: scip_lp.c:791
    SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
    Definition: scip_lp.c:174
    SCIP_RETCODE SCIPgetLPBInvRow(SCIP *scip, int r, SCIP_Real *coefs, int *inds, int *ninds)
    Definition: scip_lp.c:720
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #define SCIPfreeBlockMemoryNull(scip, ptr)
    Definition: scip_mem.h:109
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
    Definition: tree.c:8483
    SCIP_Bool SCIProwIsIntegral(SCIP_ROW *row)
    Definition: lp.c:17785
    SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
    Definition: lp.c:17686
    SCIP_Bool SCIProwIsModifiable(SCIP_ROW *row)
    Definition: lp.c:17805
    int SCIProwGetNNonz(SCIP_ROW *row)
    Definition: lp.c:17607
    SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
    Definition: lp.c:17632
    SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
    Definition: lp.c:17696
    int SCIProwGetNLPNonz(SCIP_ROW *row)
    Definition: lp.c:17621
    int SCIProwGetLPPos(SCIP_ROW *row)
    Definition: lp.c:17895
    SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_lp.c:1646
    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 SCIPcreateEmptyRowUnspec(SCIP *scip, SCIP_ROW **row, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
    Definition: scip_lp.c:1458
    SCIP_Real SCIProwGetConstant(SCIP_ROW *row)
    Definition: lp.c:17652
    SCIP_Real SCIPgetRowObjParallelism(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:2154
    int SCIPgetRowNumIntCols(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1832
    SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
    Definition: lp.c:17642
    SCIP_BASESTAT SCIProwGetBasisStatus(SCIP_ROW *row)
    Definition: lp.c:17734
    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_Real SCIPfeastol(SCIP *scip)
    SCIP_Real SCIPfrac(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
    SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
    Definition: scip_tree.c:91
    SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
    Definition: var.c:23683
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23267
    SCIP_Real SCIPvarGetBranchFactor(SCIP_VAR *var)
    Definition: var.c:24450
    #define BMSclearMemoryArray(ptr, num)
    Definition: memory.h:130
    public methods for branching rules
    public methods for LP management
    public methods for message output
    public methods for branch and bound tree
    public methods for problem variables
    public methods for branching rule plugins and branching
    public methods for cuts and aggregation rows
    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 the branch-and-bound tree
    struct SCIP_BranchruleData SCIP_BRANCHRULEDATA
    Definition: type_branch.h:57
    @ SCIP_LPSOLSTAT_OPTIMAL
    Definition: type_lp.h:44
    @ SCIP_BASESTAT_BASIC
    Definition: type_lpi.h:92
    @ SCIP_BASESTAT_UPPER
    Definition: type_lpi.h:93
    @ SCIP_BASESTAT_LOWER
    Definition: type_lpi.h:91
    enum SCIP_BaseStat SCIP_BASESTAT
    Definition: type_lpi.h:96
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_CUTOFF
    Definition: type_result.h:48
    @ SCIP_REDUCEDDOM
    Definition: type_result.h:51
    @ SCIP_BRANCHED
    Definition: type_result.h:54
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63