SCIP

    Solving Constraint Integer Programs

    cutsel_ensemble.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 cutsel_ensemble.c
    26 * @ingroup DEFPLUGINS_CUTSEL
    27 * @brief ensemble cut selector
    28 * @author Mark Turner
    29 *
    30 * @todo separator hard limit on density is inappropriate for MINLP. Need to relax hard limit in case of all cuts dense
    31 * @todo penalising via parallelism is overly costly if many cuts. Hash cuts before and find appropriate groups?
    32 */
    33
    34/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    35
    36#include "scip/scip_cutsel.h"
    37#include "scip/scip_cut.h"
    38#include "scip/scip_lp.h"
    41
    42
    43#define CUTSEL_NAME "ensemble"
    44#define CUTSEL_DESC "weighted sum of many terms with optional filtering and penalties"
    45#define CUTSEL_PRIORITY 7000
    46
    47#define RANDSEED 0x5EED
    48
    49#define DEFAULT_MINSCORE 0.0 /**< minimum score s.t. a cut can be selected */
    50#define DEFAULT_EFFICACYWEIGHT 0.75 /**< weight of normed-efficacy in score calculation */
    51#define DEFAULT_DIRCUTOFFDISTWEIGHT 0.0 /**< weight of normed-directed cutoff distance in score calculation */
    52#define DEFAULT_OBJPARALWEIGHT 0.25 /**< weight of objective parallelism in score calculation */
    53#define DEFAULT_INTSUPPORTWEIGHT 0.45 /**< weight of integral support in cut score calculation */
    54#define DEFAULT_EXPIMPROVWEIGHT 0.1 /**< weight of normed-expected improvement in cut score calculation */
    55#define DEFAULT_PSCOSTWEIGHT 0.75 /**< weight of normalised pseudo-costs in cut score calculation */
    56#define DEFAULT_NLOCKSWEIGHT 0.25 /**< weight of normalised number of locks in cut score calculation */
    57#define DEFAULT_MAXSPARSITYBONUS 0.5 /**< score given to a cut with complete sparsity */
    58#define DEFAULT_SPARSITYENDBONUS 0.2 /**< the density at which a cut no longer receives additional score */
    59#define DEFAULT_GOODNUMERICBONUS 0.0 /**< bonus provided for good numerics */
    60#define DEFAULT_MAXCOEFRATIOBONUS 10000 /**< maximum coefficient ratio of cut for which numeric bonus is given */
    61#define DEFAULT_PENALISELOCKS TRUE /**< whether having less locks should be rewarded instead of more */
    62#define DEFAULT_PENALISEOBJPARAL TRUE /**< whether objective parallelism should be penalised not rewarded */
    63#define DEFAULT_FILTERPARALCUTS FALSE /**< should cuts be filtered so no two parallel cuts are added */
    64#define DEFAULT_MAXPARAL 0.95 /**< threshold for when two cuts are considered parallel to each other */
    65#define DEFAULT_PENALISEPARALCUTS TRUE /**< should two parallel cuts be penalised instead of outright filtered */
    66#define DEFAULT_PARALPENALTY 0.25 /**< penalty for weaker of two parallel cuts if penalising parallel cuts */
    67#define DEFAULT_FILTERDENSECUTS TRUE /**< should cuts over a given density threshold be filtered */
    68#define DEFAULT_MAXCUTDENSITY 0.425 /**< max allowed cut density if filtering dense cuts */
    69#define DEFAULT_MAXNONZEROROOTROUND 4.5 /**< max nonzeros per round (root). Gets multiplied by num LP cols */
    70#define DEFAULT_MAXNONZEROTREEROUND 9.5 /**< max nonzeros per round (tree). Gets multiplied by num LP cols */
    71#define DEFAULT_MAXCUTS 200 /**< maximum number of cuts that can be considered by this cut selector */
    72#define DEFAULT_MAXNUMVARS 50000 /**< maximum number of variables that a problem can have while calling this cut selector */
    73
    74/*
    75 * Data structures
    76 */
    77
    78/** cut selector data */
    79struct SCIP_CutselData
    80{
    81 SCIP_RANDNUMGEN* randnumgen; /**< random generator for tie-breaking */
    82 SCIP_Real minscore; /**< minimum score for a cut to be added to the LP */
    83 SCIP_Real objparalweight; /**< weight of objective parallelism in cut score calculation */
    84 SCIP_Real efficacyweight; /**< weight of normed-efficacy in cut score calculation */
    85 SCIP_Real dircutoffdistweight;/**< weight of normed-directed cutoff distance in cut score calculation */
    86 SCIP_Real expimprovweight; /**< weight of normed-expected improvement in cut score calculation */
    87 SCIP_Real intsupportweight; /**< weight of integral support in cut score calculation */
    88 SCIP_Real pscostweight; /**< weight of normalised pseudo-costs in cut score calculation */
    89 SCIP_Real locksweight; /**< weight of normed-number of active locks in cut score calculation */
    90 SCIP_Real maxsparsitybonus; /**< weight of maximum sparsity reward in cut score calculation */
    91 SCIP_Real goodnumericsbonus; /**< weight of good numeric bonus in cut score calculation */
    92 SCIP_Real endsparsitybonus; /**< max sparsity value for which a bonus is applied */
    93 SCIP_Real maxparal; /**< threshold for when two cuts are considered parallel to each other */
    94 SCIP_Real paralpenalty; /**< penalty for weaker of two parallel cuts if penalising parallel cuts */
    95 SCIP_Real maxcutdensity; /**< max allowed cut density if filtering dense cuts */
    96 SCIP_Real maxnonzerorootround;/**< max nonzeros per round (root). Gets multiplied by num LP cols */
    97 SCIP_Real maxnonzerotreeround;/**< max nonzeros per round (tree). Gets multiplied by num LP cols */
    98 SCIP_Bool filterparalcuts; /**< should cuts be filtered so no two parallel cuts are added */
    99 SCIP_Bool penaliseparalcuts; /**< should two parallel cuts be penalised instead of outright filtered */
    100 SCIP_Bool filterdensecuts; /**< should cuts over a given density threshold be filtered */
    101 SCIP_Bool penaliselocks; /**< whether the number of locks should be penalised instead of rewarded */
    102 SCIP_Bool penaliseobjparal; /**< whether objective parallelism should be penalised */
    103 int maxcoefratiobonus; /**< maximum coefficient ratio for which numeric bonus is applied */
    104 int maxcuts; /**< maximum number of cuts that can be considered by this cut selector */
    105 int maxnumvars; /**< maximum number of variables that a problem can have while calling this cut selector */
    106};
    107
    108
    109/*
    110 * Local methods
    111 */
    112
    113/** returns the maximum score of cuts; if scores is not NULL, then stores the individual score of each cut in scores */
    114static
    116 SCIP* scip, /**< SCIP data structure */
    117 SCIP_ROW** cuts, /**< array with cuts to score */
    118 SCIP_CUTSELDATA* cutseldata, /**< cut selector data */
    119 SCIP_Real* scores, /**< array to store the score of cuts or NULL */
    120 SCIP_Bool root, /**< whether we are at the root node or not */
    121 int ncuts /**< number of cuts in cuts array */
    122 )
    123{
    124 SCIP_Real* effs;
    125 SCIP_Real* dcds;
    126 SCIP_Real* exps;
    127 SCIP_Real* cutdensities;
    128 SCIP_Real* cutlocks;
    129 SCIP_Real* pscosts;
    130 SCIP_SOL* sol;
    131 SCIP_Real maxdcd = 0.0;
    132 SCIP_Real maxeff = 0.0;
    133 SCIP_Real maxexp = 0.0;
    134 SCIP_Real maxpscost = 0.0;
    135 SCIP_Real maxlocks = 0.0;
    136 SCIP_Real ncols;
    137
    138 /* Get the solution that we use for directed cutoff distance calculations. Get the number of columns too */
    139 sol = SCIPgetBestSol(scip);
    140 ncols = SCIPgetNLPCols(scip);
    141
    142 /* Initialise all array information that we're going to use for scoring */
    143 SCIP_CALL( SCIPallocBufferArray(scip, &effs, ncuts) );
    144 SCIP_CALL( SCIPallocBufferArray(scip, &dcds, ncuts) );
    145 SCIP_CALL( SCIPallocBufferArray(scip, &exps, ncuts) );
    146 SCIP_CALL( SCIPallocBufferArray(scip, &cutdensities, ncuts) );
    147 SCIP_CALL( SCIPallocBufferArray(scip, &cutlocks, ncuts) );
    148 SCIP_CALL( SCIPallocBufferArray(scip, &pscosts, ncuts) );
    149
    150 /* Populate the number of cut locks, the pseudo-cost scores, and the cut densities */
    151 for (int i = 0; i < ncuts; ++i )
    152 {
    153 SCIP_COL** cols;
    154 SCIP_Real* cutvals;
    155 SCIP_Real sqrcutnorm;
    156 SCIP_Real ncutcols;
    157 SCIP_Real cutalpha;
    158
    159 cols = SCIProwGetCols(cuts[i]);
    160 cutvals = SCIProwGetVals(cuts[i]);
    161 sqrcutnorm = MAX(SCIPsumepsilon(scip), SQR(SCIProwGetNorm(cuts[i]))); /*lint !e666*/
    162 cutalpha = -SCIPgetRowFeasibility(scip, cuts[i]) / sqrcutnorm;
    163 ncutcols = SCIProwGetNNonz(cuts[i]);
    164 cutdensities[i] = ncutcols / ncols;
    165 cutlocks[i] = 0;
    166 pscosts[i] = 0;
    167
    168 for ( int j = 0; j < (int) ncutcols; ++j )
    169 {
    170 SCIP_VAR* colvar;
    171 SCIP_Real colval;
    172 SCIP_Real l1dist;
    173
    174 colval = SCIPcolGetPrimsol(cols[j]);
    175 colvar = SCIPcolGetVar(cols[j]);
    176 /* Get the number of active locks feature in the cut */
    177 if( ! SCIPisInfinity(scip, SCIProwGetRhs(cuts[i])) && cutvals[j] > 0.0 )
    178 cutlocks[i] += SCIPvarGetNLocksUp(colvar);
    179 if( ! SCIPisInfinity(scip, -SCIProwGetLhs(cuts[i])) && cutvals[j] < 0.0 )
    180 cutlocks[i] += SCIPvarGetNLocksUp(colvar);
    181 if( ! SCIPisInfinity(scip, SCIProwGetRhs(cuts[i])) && cutvals[j] < 0.0 )
    182 cutlocks[i] += SCIPvarGetNLocksDown(colvar);
    183 if( ! SCIPisInfinity(scip, -SCIProwGetLhs(cuts[i])) && cutvals[j] > 0.0 )
    184 cutlocks[i] += SCIPvarGetNLocksDown(colvar);
    185
    186 /* Get the L1 distance from the projection onto the cut and the LP solution in the variable direction */
    187 l1dist = ABS(colval - (cutalpha * cutvals[j]));
    188 pscosts[i] += SCIPgetVarPseudocostScore(scip, colvar, colval) * l1dist;
    189 }
    190 cutlocks[i] = cutlocks[i] / ncutcols; /*lint !e414*/
    191
    192 if( cutlocks[i] > maxlocks )
    193 maxlocks = cutlocks[i];
    194
    195 if( pscosts[i] > maxpscost )
    196 maxpscost = pscosts[i];
    197 }
    198
    199 /* account for the case where maxlocks or maxpscost is 0 */
    200 maxpscost = MAX(maxpscost, SCIPepsilon(scip)); /*lint !e666*/
    201 maxlocks = MAX(maxlocks, 1);
    202
    203 for ( int i = 0; i < ncuts; i++ )
    204 {
    205 cutlocks[i] = cutlocks[i] / maxlocks; /*lint !e414*/
    206 /* if locks are penalized, we complement the corresponding score */
    207 if( cutseldata->penaliselocks )
    208 cutlocks[i] = 1 - cutlocks[i];
    209 pscosts[i] = pscosts[i] / maxpscost; /*lint !e414*/
    210 }
    211
    212 /* Get the arrays / maximums of directed cutoff distance, efficacy, and expected improvement values. */
    213 if ( sol != NULL && root )
    214 {
    215 for ( int i = 0; i < ncuts; i++ )
    216 {
    217 dcds[i] = SCIPgetCutLPSolCutoffDistance(scip, sol, cuts[i]);
    218 maxdcd = MAX(maxdcd, dcds[i]);
    219 }
    220 }
    221
    222 for ( int i = 0; i < ncuts; ++i )
    223 {
    224 effs[i] = SCIPgetCutEfficacy(scip, NULL, cuts[i]);
    225 exps[i] = effs[i] * SCIPgetRowObjParallelism(scip, cuts[i]);
    226 maxeff = MAX(maxeff, effs[i]);
    227 maxexp = MAX(maxexp, exps[i]);
    228 }
    229
    230 /* Now score the cuts */
    231 for ( int i = 0; i < ncuts; ++i )
    232 {
    233 SCIP_Real score;
    234 SCIP_Real scaleddcd;
    235 SCIP_Real scaledeff;
    236 SCIP_Real scaledexp;
    237 SCIP_Real objparallelism;
    238 SCIP_Real intsupport;
    240 SCIP_Real dynamism;
    241 SCIP_Real mincutval;
    242 SCIP_Real maxcutval;
    243 SCIP_Real pscost;
    244 SCIP_Real cutlock;
    245
    246 /* Get the integer support */
    247 intsupport = SCIPgetRowNumIntCols(scip, cuts[i]) / (SCIP_Real) SCIProwGetNNonz(cuts[i]);
    248 intsupport *= cutseldata->intsupportweight;
    249
    250 /* Get the objective parallelism and orthogonality */
    251 if( ! cutseldata->penaliseobjparal )
    252 objparallelism = cutseldata->objparalweight * SCIPgetRowObjParallelism(scip, cuts[i]);
    253 else
    254 objparallelism = cutseldata->objparalweight * (1 - SCIPgetRowObjParallelism(scip, cuts[i]));
    255
    256 /* Get the density score */
    257 density = (cutseldata->maxsparsitybonus / cutseldata->endsparsitybonus) * -1 * cutdensities[i];
    258 density += cutseldata->maxsparsitybonus;
    259 density = MAX(density, 0.0);
    260
    261 /* Get the normalised pseudo-cost and number of locks score */
    262 if( root )
    263 pscost = 0.0;
    264 else
    265 pscost = cutseldata->pscostweight * pscosts[i];
    266 cutlock = cutseldata->locksweight * cutlocks[i];
    267
    268 /* Get the dynamism (good numerics) score */
    269 maxcutval = SCIPgetRowMaxCoef(scip, cuts[i]);
    270 mincutval = SCIPgetRowMinCoef(scip, cuts[i]);
    271 mincutval = mincutval > 0.0 ? mincutval : 1.0;
    272 dynamism = cutseldata->maxcoefratiobonus >= maxcutval / mincutval ? cutseldata->goodnumericsbonus : 0.0;
    273
    274 /* Get the dcd / eff / exp score */
    275 if ( sol != NULL && root )
    276 {
    277 if ( SCIPisSumLE(scip, dcds[i], 0.0))
    278 scaleddcd = 0.0;
    279 else
    280 scaleddcd = cutseldata->dircutoffdistweight * SQR(LOG1P(dcds[i]) / LOG1P(maxdcd)); /*lint !e666*/
    281 }
    282 else
    283 {
    284 scaleddcd = 0.0;
    285 }
    286
    287 if ( SCIPisSumLE(scip, exps[i], 0.0))
    288 scaledexp = 0.0;
    289 else
    290 scaledexp = cutseldata->expimprovweight * SQR(LOG1P(exps[i]) / LOG1P(maxexp)); /*lint !e666*/
    291
    292 if ( SCIPisSumLE(scip, effs[i], 0.0))
    293 {
    294 scaledeff = 0.0;
    295 }
    296 else
    297 {
    298 if ( sol != NULL && root )
    299 scaledeff = cutseldata->efficacyweight * SQR(LOG1P(effs[i]) / LOG1P(maxeff)); /*lint !e666*/
    300 else
    301 scaledeff = (cutseldata->efficacyweight + cutseldata->dircutoffdistweight) * SQR(LOG1P(effs[i]) / LOG1P(maxeff)); /*lint !e666*/
    302 }
    303
    304 /* Combine all scores and introduce some minor randomness */
    305 score = scaledeff + scaleddcd + scaledexp + objparallelism + intsupport + density + dynamism + pscost + cutlock;
    306
    307 score += SCIPrandomGetReal(cutseldata->randnumgen, 0.0, 1e-6);
    308
    309 scores[i] = score;
    310 }
    311
    315 SCIPfreeBufferArray(scip, &cutdensities);
    316 SCIPfreeBufferArray(scip, &cutlocks);
    317 SCIPfreeBufferArray(scip, &pscosts);
    318
    319 return SCIP_OKAY;
    320}
    321
    322
    323/** move the cut with the highest score to the first position in the array; there must be at least one cut */
    324static
    326 SCIP_ROW** cuts, /**< array with cuts to perform selection algorithm */
    327 SCIP_Real* scores, /**< array with scores of cuts to perform selection algorithm */
    328 int ncuts /**< number of cuts in given array */
    329 )
    330{
    331 int bestpos;
    332 SCIP_Real bestscore;
    333
    334 assert(ncuts > 0);
    335 assert(cuts != NULL);
    336 assert(scores != NULL);
    337
    338 bestscore = scores[0];
    339 bestpos = 0;
    340
    341 for( int i = 1; i < ncuts; ++i )
    342 {
    343 if( scores[i] > bestscore )
    344 {
    345 bestpos = i;
    346 bestscore = scores[i];
    347 }
    348 }
    349
    350 SCIPswapPointers((void**) &cuts[bestpos], (void**) &cuts[0]);
    351 SCIPswapReals(&scores[bestpos], &scores[0]);
    352}
    353
    354/** filters the given array of cuts to enforce a maximum parallelism constraint
    355 * w.r.t the given cut; moves filtered cuts to the end of the array and returns number of selected cuts */
    356static
    358 SCIP_ROW* cut, /**< cut to filter orthogonality with */
    359 SCIP_ROW** cuts, /**< array with cuts to perform selection algorithm */
    360 SCIP_Real* scores, /**< array with scores of cuts to perform selection algorithm */
    361 int ncuts, /**< number of cuts in given array */
    362 SCIP_Real maxparallel /**< maximal parallelism for all cuts that are not good */
    363 )
    364{
    365 assert( cut != NULL );
    366 assert( ncuts == 0 || cuts != NULL );
    367 assert( ncuts == 0 || scores != NULL );
    368
    369 for( int i = ncuts - 1; i >= 0; --i )
    370 {
    371 SCIP_Real thisparallel;
    372
    373 thisparallel = SCIProwGetParallelism(cut, cuts[i], 'e');
    374
    375 if( thisparallel > maxparallel )
    376 {
    377 --ncuts;
    378 SCIPswapPointers((void**) &cuts[i], (void**) &cuts[ncuts]);
    379 SCIPswapReals(&scores[i], &scores[ncuts]);
    380 }
    381 }
    382
    383 return ncuts;
    384}
    385
    386/** penalises any cut too parallel to cut by reducing the parallel cut's score. */
    387static
    389 SCIP* scip, /**< SCIP data structure */
    390 SCIP_ROW* cut, /**< cut to filter orthogonality with */
    391 SCIP_ROW** cuts, /**< array with cuts to perform selection algorithm */
    392 SCIP_Real* scores, /**< array with scores of cuts to perform selection algorithm */
    393 int ncuts, /**< number of cuts in given array */
    394 SCIP_Real maxparallel, /**< maximal parallelism for all cuts that are not good */
    395 SCIP_Real paralpenalty /**< penalty for weaker of two parallel cuts if penalising parallel cuts */
    396 )
    397{
    398 assert( cut != NULL );
    399 assert( ncuts == 0 || cuts != NULL );
    400 assert( ncuts == 0 || scores != NULL );
    401
    402 for( int i = ncuts - 1; i >= 0; --i )
    403 {
    404 SCIP_Real thisparallel;
    405
    406 thisparallel = SCIProwGetParallelism(cut, cuts[i], 'e');
    407
    408 /* Filter cuts that are absolutely parallel still. Otherwise penalise if closely parallel */
    409 if( thisparallel > 1 - SCIPsumepsilon(scip) )
    410 {
    411 --ncuts;
    412 SCIPswapPointers((void**) &cuts[i], (void**) &cuts[ncuts]);
    413 SCIPswapReals(&scores[i], &scores[ncuts]);
    414 }
    415 else if( thisparallel > maxparallel )
    416 {
    417 scores[i] -= paralpenalty;
    418 }
    419 }
    420
    421 return ncuts;
    422}
    423
    424/** filters the given array of cuts to enforce a maximum density constraint,
    425 * Moves filtered cuts to the end of the array and returns number of selected cuts */
    426static
    428 SCIP* scip, /**< SCIP data structure */
    429 SCIP_ROW** cuts, /**< array with cuts to perform selection algorithm */
    430 SCIP_Real maxdensity, /**< maximum density s.t. a cut is not filtered */
    431 int ncuts /**< number of cuts in given array */
    432 )
    433{
    434 SCIP_Real ncols;
    435
    436 assert( ncuts == 0 || cuts != NULL );
    437
    438 ncols = SCIPgetNLPCols(scip);
    439
    440 for( int i = ncuts - 1; i >= 0; --i )
    441 {
    442 SCIP_Real nvals;
    443
    444 nvals = SCIProwGetNNonz(cuts[i]);
    445
    446 if( maxdensity < nvals / ncols )
    447 {
    448 --ncuts;
    449 SCIPswapPointers((void**) &cuts[i], (void**) &cuts[ncuts]);
    450 }
    451 }
    452
    453 return ncuts;
    454}
    455
    456
    457/*
    458 * Callback methods of cut selector
    459 */
    460
    461
    462/** copy method for cut selector plugin (called when SCIP copies plugins) */
    463static
    464SCIP_DECL_CUTSELCOPY(cutselCopyEnsemble)
    465{ /*lint --e{715}*/
    466 assert(scip != NULL);
    467 assert(cutsel != NULL);
    468
    470
    471 /* call inclusion method of cut selector */
    473
    474 return SCIP_OKAY;
    475}
    476
    477/** destructor of cut selector to free user data (called when SCIP is exiting) */
    478/**! [SnippetCutselFreeEnsemble] */
    479static
    480SCIP_DECL_CUTSELFREE(cutselFreeEnsemble)
    481{ /*lint --e{715}*/
    482 SCIP_CUTSELDATA* cutseldata;
    483
    484 cutseldata = SCIPcutselGetData(cutsel);
    485
    486 SCIPfreeBlockMemory(scip, &cutseldata);
    487
    488 SCIPcutselSetData(cutsel, NULL);
    489
    490 return SCIP_OKAY;
    491}
    492/**! [SnippetCutselFreeEnsemble] */
    493
    494/** initialization method of cut selector (called after problem was transformed) */
    495static
    496SCIP_DECL_CUTSELINIT(cutselInitEnsemble)
    497{ /*lint --e{715}*/
    498 SCIP_CUTSELDATA* cutseldata;
    499
    500 cutseldata = SCIPcutselGetData(cutsel);
    501 assert(cutseldata != NULL);
    502
    503 SCIP_CALL( SCIPcreateRandom(scip, &(cutseldata)->randnumgen, RANDSEED, TRUE) );
    504
    505 return SCIP_OKAY;
    506}
    507
    508/** deinitialization method of cut selector (called before transformed problem is freed) */
    509static
    510SCIP_DECL_CUTSELEXIT(cutselExitEnsemble)
    511{ /*lint --e{715}*/
    512 SCIP_CUTSELDATA* cutseldata;
    513
    514 cutseldata = SCIPcutselGetData(cutsel);
    515 assert(cutseldata != NULL);
    516 assert(cutseldata->randnumgen != NULL);
    517
    518 SCIPfreeRandom(scip, &cutseldata->randnumgen);
    519
    520 return SCIP_OKAY;
    521}
    522
    523/** cut selection method of cut selector */
    524static
    525SCIP_DECL_CUTSELSELECT(cutselSelectEnsemble)
    526{ /*lint --e{715}*/
    527 SCIP_CUTSELDATA* cutseldata;
    528
    529 assert(cutsel != NULL);
    530 assert(result != NULL);
    531
    532 cutseldata = SCIPcutselGetData(cutsel);
    533 assert(cutseldata != NULL);
    534
    535 if( ncuts > cutseldata->maxcuts || SCIPgetNVars(scip) > cutseldata->maxnumvars )
    536 {
    537 *result = SCIP_DIDNOTFIND;
    538 return SCIP_OKAY;
    539 }
    540
    541 *result = SCIP_SUCCESS;
    542
    543 SCIP_CALL( SCIPselectCutsEnsemble(scip, cuts, forcedcuts, cutseldata, root, ncuts, nforcedcuts,
    544 maxnselectedcuts, nselectedcuts) );
    545
    546 return SCIP_OKAY;
    547}
    548
    549
    550/*
    551 * cut selector specific interface methods
    552 */
    553
    554/** creates the ensemble cut selector and includes it in SCIP */
    556 SCIP* scip /**< SCIP data structure */
    557 )
    558{
    559 SCIP_CUTSELDATA* cutseldata;
    560 SCIP_CUTSEL* cutsel;
    561
    562 /* create ensemble cut selector data */
    563 SCIP_CALL( SCIPallocBlockMemory(scip, &cutseldata) );
    564 BMSclearMemory(cutseldata);
    565
    567 cutseldata) );
    568
    569 assert(cutsel != NULL);
    570
    571 /* set non fundamental callbacks via setter functions */
    572 SCIP_CALL( SCIPsetCutselCopy(scip, cutsel, cutselCopyEnsemble) );
    573
    574 SCIP_CALL( SCIPsetCutselFree(scip, cutsel, cutselFreeEnsemble) );
    575 SCIP_CALL( SCIPsetCutselInit(scip, cutsel, cutselInitEnsemble) );
    576 SCIP_CALL( SCIPsetCutselExit(scip, cutsel, cutselExitEnsemble) );
    577
    578 /* add ensemble cut selector parameters */
    579 SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/efficacyweight", "weight of normed-efficacy in cut "
    580 "score calculation", &cutseldata->efficacyweight, FALSE, DEFAULT_EFFICACYWEIGHT, 0.0, SCIP_INVALID/10.0, NULL,
    581 NULL) );
    582
    583 SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/dircutoffdistweight", "weight of normed-directed "
    584 "cutoff distance in cut score calculation", &cutseldata->dircutoffdistweight, FALSE,
    586
    587 SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/objparalweight", "weight of objective parallelism "
    588 "in cut score calculation", &cutseldata->objparalweight, FALSE, DEFAULT_OBJPARALWEIGHT, 0.0, SCIP_INVALID/10.0,
    589 NULL, NULL) );
    590
    591 SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/intsupportweight", "weight of integral support in "
    592 "cut score calculation", &cutseldata->intsupportweight, FALSE, DEFAULT_INTSUPPORTWEIGHT, 0.0,
    593 SCIP_INVALID/10.0, NULL, NULL) );
    594
    595 SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/expimprovweight", "weight of normed-expected obj "
    596 "improvement in cut score calculation", &cutseldata->expimprovweight, FALSE, DEFAULT_EXPIMPROVWEIGHT, 0.0,
    597 SCIP_INVALID/10.0, NULL, NULL) );
    598
    599 SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/minscore", "minimum score s.t. a cut can be added",
    600 &cutseldata->minscore, FALSE, DEFAULT_MINSCORE, -SCIP_INVALID/10.0, SCIP_INVALID/10.0, NULL, NULL) );
    601
    602 SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/pscostweight", "weight of normed-pseudo-costs in "
    603 "cut score calculation", &cutseldata->pscostweight, FALSE, DEFAULT_PSCOSTWEIGHT, 0.0, SCIP_INVALID/10.0, NULL,
    604 NULL) );
    605
    606 SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/locksweight", "weight of normed-num-locks in cut "
    607 "score calculation", &cutseldata->locksweight, FALSE, DEFAULT_NLOCKSWEIGHT, 0.0, SCIP_INVALID/10.0, NULL,
    608 NULL) );
    609
    610 SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/maxsparsitybonus", "weight of maximum sparsity "
    611 "reward in cut score calculation", &cutseldata->maxsparsitybonus, FALSE, DEFAULT_MAXSPARSITYBONUS, 0.0,
    612 SCIP_INVALID/10.0, NULL, NULL) );
    613
    614 SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/goodnumericsbonus", "weight of good numerics bonus "
    615 "(ratio of coefficients) in cut score calculation", &cutseldata->goodnumericsbonus, FALSE,
    617
    618 SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/endsparsitybonus", "max sparsity value for which a "
    619 "bonus is applied in cut score calculation", &cutseldata->endsparsitybonus, FALSE, DEFAULT_SPARSITYENDBONUS,
    620 0.0, SCIP_INVALID/10.0, NULL, NULL) );
    621
    622 SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/maxparal", "threshold for when two cuts are "
    623 "considered parallel to each other", &cutseldata->maxparal, FALSE, DEFAULT_MAXPARAL, 0.0, 1.0, NULL, NULL) );
    624
    625 SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/paralpenalty", "penalty for weaker of two parallel "
    626 "cuts if penalising parallel cuts", &cutseldata->paralpenalty, TRUE, DEFAULT_PARALPENALTY, 0.0,
    627 SCIP_INVALID/10.0, NULL, NULL) );
    628
    629 SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/maxcutdensity", "max allowed cut density if "
    630 "filtering dense cuts", &cutseldata->maxcutdensity, TRUE, DEFAULT_MAXCUTDENSITY, 0.0, 1.0, NULL, NULL) );
    631
    632 SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/maxnonzerorootround", "max non-zeros per round "
    633 "applied cuts (root). multiple num LP cols.", &cutseldata->maxnonzerorootround, FALSE,
    635
    636 SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/maxnonzerotreeround", "max non-zeros per round "
    637 "applied cuts (tree). multiple num LP cols.", &cutseldata->maxnonzerotreeround, FALSE,
    639
    640 SCIP_CALL( SCIPaddBoolParam(scip, "cutselection/" CUTSEL_NAME "/filterparalcuts", "should cuts be filtered so no "
    641 "two parallel cuts are added", &cutseldata->filterparalcuts, FALSE, DEFAULT_FILTERPARALCUTS, NULL, NULL) );
    642
    643 SCIP_CALL( SCIPaddBoolParam(scip, "cutselection/" CUTSEL_NAME "/penaliseparalcuts", "should two parallel cuts be "
    644 "penalised instead of outright filtered", &cutseldata->penaliseparalcuts, TRUE, DEFAULT_PENALISEPARALCUTS,
    645 NULL, NULL) );
    646
    647 SCIP_CALL( SCIPaddBoolParam(scip, "cutselection/" CUTSEL_NAME "/filterdensecuts", "should cuts over a given density "
    648 "threshold be filtered", &cutseldata->filterdensecuts, TRUE, DEFAULT_FILTERDENSECUTS, NULL, NULL) );
    649
    650 SCIP_CALL( SCIPaddBoolParam(scip, "cutselection/" CUTSEL_NAME "/penaliselocks", "should the number of locks be "
    651 "penalised instead of rewarded", &cutseldata->penaliselocks, TRUE, DEFAULT_PENALISELOCKS, NULL, NULL) );
    652
    653 SCIP_CALL( SCIPaddBoolParam(scip, "cutselection/" CUTSEL_NAME "/penaliseobjparal", "should objective parallelism "
    654 "be penalised instead of rewarded", &cutseldata->penaliseobjparal, TRUE, DEFAULT_PENALISEOBJPARAL, NULL, NULL)
    655 );
    656
    657 SCIP_CALL( SCIPaddIntParam(scip, "cutselection/" CUTSEL_NAME "/maxcoefratiobonus", "max coefficient ratio for "
    658 "which numeric bonus is applied.", &cutseldata->maxcoefratiobonus, TRUE, DEFAULT_MAXCOEFRATIOBONUS, 1, 1000000,
    659 NULL, NULL) );
    660
    661 SCIP_CALL( SCIPaddIntParam(scip, "cutselection/" CUTSEL_NAME "/maxcuts", "max number of cuts such that cut "
    662 "selector is applied.", &cutseldata->maxcuts, TRUE, DEFAULT_MAXCUTS, 1, 1000000, NULL, NULL) );
    663
    664 SCIP_CALL( SCIPaddIntParam(scip, "cutselection/" CUTSEL_NAME "/maxnumvars", "max number of variables such that cut "
    665 "selector is applied.", &cutseldata->maxnumvars, TRUE, DEFAULT_MAXNUMVARS, 1, 1000000, NULL, NULL) );
    666
    667 return SCIP_OKAY;
    668}
    669
    670/** perform a cut selection algorithm for the given array of cuts
    671 *
    672 * This is the selection method of the ensemble cut selector. It uses a weighted sum of normalised efficacy,
    673 * normalised directed cutoff distance, normalised expected improvements, objective parallelism,
    674 * integer support, sparsity, dynamism, pseudo-costs, and variable locks.
    675 * In addition to the weighted sum score, there are optionally parallelism-based filtering and penalties,
    676 * and density filtering.
    677 * There are also additional budget constraints on the number of cuts that should be added.
    678 * The input cuts array gets re-sorted such that the selected cuts come first and the remaining ones are the end.
    679 */
    681 SCIP* scip, /**< SCIP data structure */
    682 SCIP_ROW** cuts, /**< array with cuts to perform selection algorithm */
    683 SCIP_ROW** forcedcuts, /**< array with forced cuts */
    684 SCIP_CUTSELDATA* cutseldata, /**< cut selector data */
    685 SCIP_Bool root, /**< whether we are at the root node or not */
    686 int ncuts, /**< number of cuts in cuts array */
    687 int nforcedcuts, /**< number of forced cuts */
    688 int maxselectedcuts, /**< maximal number of cuts from cuts array to select */
    689 int* nselectedcuts /**< pointer to return number of selected cuts from cuts array */
    690 )
    691{
    692 SCIP_Real* scores;
    693 SCIP_Real* origscoresptr;
    694 SCIP_Real nonzerobudget;
    695 SCIP_Real budgettaken = 0.0;
    696 SCIP_Real ncols;
    697
    698 assert(cuts != NULL && ncuts > 0);
    699 assert(forcedcuts != NULL || nforcedcuts == 0);
    700 assert(nselectedcuts != NULL);
    701
    702 *nselectedcuts = 0;
    703 ncols = SCIPgetNLPCols(scip);
    704
    705 /* filter dense cuts */
    706 if( cutseldata->filterdensecuts )
    707 {
    708 ncuts = filterWithDensity(scip, cuts, cutseldata->maxcutdensity, ncuts);
    709 if( ncuts == 0 )
    710 return SCIP_OKAY;
    711 }
    712
    713 /* Initialise the score array */
    714 SCIP_CALL( SCIPallocBufferArray(scip, &scores, ncuts) );
    715 origscoresptr = scores;
    716
    717 /* compute scores of cuts */
    718 SCIP_CALL( scoring(scip, cuts, cutseldata, scores, root, ncuts) );
    719
    720 /* perform cut selection algorithm for the cuts */
    721
    722 /* forced cuts are going to be selected so use them to filter cuts */
    723 for( int i = 0; i < nforcedcuts && ncuts > 0; ++i )
    724 {
    725 if( cutseldata->filterparalcuts )
    726 ncuts = filterWithParallelism(forcedcuts[i], cuts, scores, ncuts, cutseldata->maxparal);
    727 else if( cutseldata->penaliseparalcuts )
    728 ncuts = penaliseWithParallelism(scip, forcedcuts[i], cuts, scores, ncuts, cutseldata->maxparal, cutseldata->paralpenalty);
    729 }
    730
    731 /* Get the budget depending on if we are the root or not */
    732 nonzerobudget = root ? cutseldata->maxnonzerorootround : cutseldata->maxnonzerotreeround;
    733
    734 /* now greedily select the remaining cuts */
    735 while( ncuts > 0 )
    736 {
    737 SCIP_ROW* selectedcut;
    738
    739 selectBestCut(cuts, scores, ncuts);
    740 selectedcut = cuts[0];
    741
    742 /* if the best cut of the remaining cuts is considered bad, we discard it and all remaining cuts */
    743 if( scores[0] < cutseldata->minscore )
    744 break;
    745
    746 ++(*nselectedcuts);
    747
    748 /* if the maximal number of cuts was selected, we can stop here */
    749 if( *nselectedcuts == maxselectedcuts )
    750 break;
    751
    752 /* increase the non-zero budget counter of added cuts */
    753 budgettaken += SCIProwGetNNonz(cuts[0]) / ncols;
    754
    755 /* move the pointers to the next position and filter the remaining cuts to enforce the maximum parallelism constraint */
    756 ++cuts;
    757 ++scores;
    758 --ncuts;
    759
    760 if( cutseldata->filterparalcuts && ncuts > 0)
    761 ncuts = filterWithParallelism(selectedcut, cuts, scores, ncuts, cutseldata->maxparal);
    762 else if( cutseldata->penaliseparalcuts && ncuts > 0 )
    763 ncuts = penaliseWithParallelism(scip, selectedcut, cuts, scores, ncuts, cutseldata->maxparal, cutseldata->paralpenalty);
    764
    765 /* Filter out all remaining cuts that would go over the non-zero budget threshold */
    766 if( nonzerobudget - budgettaken < 1 && ncuts > 0 )
    767 ncuts = filterWithDensity(scip, cuts, nonzerobudget - budgettaken, ncuts);
    768 }
    769
    770 SCIPfreeBufferArray(scip, &origscoresptr);
    771
    772 return SCIP_OKAY;
    773}
    #define DEFAULT_MAXCUTS
    #define DEFAULT_SPARSITYENDBONUS
    static SCIP_DECL_CUTSELEXIT(cutselExitEnsemble)
    #define DEFAULT_EFFICACYWEIGHT
    #define DEFAULT_MAXNONZEROTREEROUND
    #define DEFAULT_OBJPARALWEIGHT
    #define RANDSEED
    #define DEFAULT_FILTERDENSECUTS
    #define DEFAULT_MAXSPARSITYBONUS
    #define DEFAULT_MINSCORE
    #define DEFAULT_PARALPENALTY
    #define DEFAULT_PENALISEPARALCUTS
    #define DEFAULT_GOODNUMERICBONUS
    #define DEFAULT_PENALISELOCKS
    static SCIP_DECL_CUTSELCOPY(cutselCopyEnsemble)
    static SCIP_DECL_CUTSELINIT(cutselInitEnsemble)
    #define DEFAULT_NLOCKSWEIGHT
    static SCIP_RETCODE scoring(SCIP *scip, SCIP_ROW **cuts, SCIP_CUTSELDATA *cutseldata, SCIP_Real *scores, SCIP_Bool root, int ncuts)
    static void selectBestCut(SCIP_ROW **cuts, SCIP_Real *scores, int ncuts)
    static int filterWithDensity(SCIP *scip, SCIP_ROW **cuts, SCIP_Real maxdensity, int ncuts)
    static int penaliseWithParallelism(SCIP *scip, SCIP_ROW *cut, SCIP_ROW **cuts, SCIP_Real *scores, int ncuts, SCIP_Real maxparallel, SCIP_Real paralpenalty)
    static SCIP_DECL_CUTSELSELECT(cutselSelectEnsemble)
    #define CUTSEL_DESC
    #define CUTSEL_PRIORITY
    static int filterWithParallelism(SCIP_ROW *cut, SCIP_ROW **cuts, SCIP_Real *scores, int ncuts, SCIP_Real maxparallel)
    #define DEFAULT_EXPIMPROVWEIGHT
    #define DEFAULT_MAXCOEFRATIOBONUS
    #define DEFAULT_DIRCUTOFFDISTWEIGHT
    #define DEFAULT_MAXCUTDENSITY
    #define DEFAULT_MAXNONZEROROOTROUND
    static SCIP_DECL_CUTSELFREE(cutselFreeEnsemble)
    #define CUTSEL_NAME
    #define DEFAULT_PENALISEOBJPARAL
    #define DEFAULT_MAXNUMVARS
    #define DEFAULT_PSCOSTWEIGHT
    #define DEFAULT_FILTERPARALCUTS
    #define DEFAULT_MAXPARAL
    #define DEFAULT_INTSUPPORTWEIGHT
    ensemble cut selector
    #define NULL
    Definition: def.h:257
    #define LOG1P(x)
    Definition: def.h:213
    #define SCIP_INVALID
    Definition: def.h:187
    #define SCIP_Bool
    Definition: def.h:100
    #define SCIP_STRINGEQ(name, reference, retcode)
    Definition: def.h:454
    #define SCIP_Real
    Definition: def.h:165
    #define ABS(x)
    Definition: def.h:225
    #define SQR(x)
    Definition: def.h:208
    #define TRUE
    Definition: def.h:102
    #define FALSE
    Definition: def.h:103
    #define MAX(x, y)
    Definition: def.h:229
    #define SCIP_CALL(x)
    Definition: def.h:364
    static const SCIP_Real density
    Definition: gastrans.c:145
    SCIP_RETCODE SCIPselectCutsEnsemble(SCIP *scip, SCIP_ROW **cuts, SCIP_ROW **forcedcuts, SCIP_CUTSELDATA *cutseldata, SCIP_Bool root, int ncuts, int nforcedcuts, int maxselectedcuts, int *nselectedcuts)
    SCIP_RETCODE SCIPincludeCutselEnsemble(SCIP *scip)
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    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
    void SCIPswapPointers(void **pointer1, void **pointer2)
    Definition: misc.c:10511
    void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
    Definition: misc.c:10498
    SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
    Definition: lp.c:17425
    SCIP_Real SCIPcolGetPrimsol(SCIP_COL *col)
    Definition: lp.c:17379
    SCIP_Real SCIPgetCutEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
    Definition: scip_cut.c:94
    SCIP_Real SCIPgetCutLPSolCutoffDistance(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
    Definition: scip_cut.c:72
    SCIP_RETCODE SCIPsetCutselInit(SCIP *scip, SCIP_CUTSEL *cutsel, SCIP_DECL_CUTSELINIT((*cutselinit)))
    Definition: scip_cutsel.c:163
    SCIP_RETCODE SCIPincludeCutselBasic(SCIP *scip, SCIP_CUTSEL **cutsel, const char *name, const char *desc, int priority, SCIP_DECL_CUTSELSELECT((*cutselselect)), SCIP_CUTSELDATA *cutseldata)
    Definition: scip_cutsel.c:98
    SCIP_RETCODE SCIPsetCutselCopy(SCIP *scip, SCIP_CUTSEL *cutsel, SCIP_DECL_CUTSELCOPY((*cutselcopy)))
    Definition: scip_cutsel.c:131
    SCIP_CUTSELDATA * SCIPcutselGetData(SCIP_CUTSEL *cutsel)
    Definition: cutsel.c:419
    SCIP_RETCODE SCIPsetCutselFree(SCIP *scip, SCIP_CUTSEL *cutsel, SCIP_DECL_CUTSELFREE((*cutselfree)))
    Definition: scip_cutsel.c:147
    void SCIPcutselSetData(SCIP_CUTSEL *cutsel, SCIP_CUTSELDATA *cutseldata)
    Definition: cutsel.c:429
    const char * SCIPcutselGetName(SCIP_CUTSEL *cutsel)
    Definition: cutsel.c:159
    SCIP_RETCODE SCIPsetCutselExit(SCIP *scip, SCIP_CUTSEL *cutsel, SCIP_DECL_CUTSELEXIT((*cutselexit)))
    Definition: scip_cutsel.c:179
    int SCIPgetNLPCols(SCIP *scip)
    Definition: scip_lp.c:533
    #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_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_Real SCIPgetRowFeasibility(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:2088
    SCIP_Real SCIProwGetParallelism(SCIP_ROW *row1, SCIP_ROW *row2, char orthofunc)
    Definition: lp.c:7970
    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
    SCIP_Real SCIProwGetNorm(SCIP_ROW *row)
    Definition: lp.c:17662
    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_SOL * SCIPgetBestSol(SCIP *scip)
    Definition: scip_sol.c:2986
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPepsilon(SCIP *scip)
    SCIP_Real SCIPsumepsilon(SCIP *scip)
    SCIP_Bool SCIPisSumLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    int SCIPvarGetNLocksDown(SCIP_VAR *var)
    Definition: var.c:4443
    int SCIPvarGetNLocksUp(SCIP_VAR *var)
    Definition: var.c:4456
    SCIP_Real SCIPgetVarPseudocostScore(SCIP *scip, SCIP_VAR *var, SCIP_Real solval)
    Definition: scip_var.c:11531
    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)
    #define BMSclearMemory(ptr)
    Definition: memory.h:129
    public methods for cuts and aggregation rows
    public methods for cut selector plugins
    public methods for the LP relaxation, rows and columns
    public methods for random numbers
    struct SCIP_CutselData SCIP_CUTSELDATA
    Definition: type_cutsel.h:53
    @ SCIP_DIDNOTFIND
    Definition: type_result.h:44
    @ SCIP_SUCCESS
    Definition: type_result.h:58
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63