SCIP

    Solving Constraint Integer Programs

    cutsel_dynamic.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_dynamic.c
    26 * @ingroup DEFPLUGINS_CUTSEL
    27 * @brief dynamic cut selector
    28 * @author Christoph Graczyk
    29 */
    30
    31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    32
    33#include "scip/scip_cutsel.h"
    34#include "scip/scip_cut.h"
    35#include "scip/scip_lp.h"
    37#include "scip/cutsel_dynamic.h"
    38
    39
    40#define CUTSEL_NAME "dynamic"
    41#define CUTSEL_DESC "dynamic orthogonality for hybrid cutsel"
    42#define CUTSEL_PRIORITY 7000
    43
    44#define RANDSEED 0x5EED
    45
    46#define DEFAULT_EFFICACYWEIGHT 1.0 /**< weight of efficacy in score calculation */
    47#define DEFAULT_DIRCUTOFFDISTWEIGHT 0.0 /**< weight of directed cutoff distance in score calculation */
    48#define DEFAULT_OBJPARALWEIGHT 0.0 /**< weight of objective parallelism in score calculation */
    49#define DEFAULT_INTSUPPORTWEIGHT 0.0 /**< weight of integral support in cut score calculation */
    50#define DEFAULT_MINORTHO 0.9 /**< minimal orthogonality in percent for a cut to enter the LP */
    51#define DEFAULT_MINGAIN 0.01 /**< minimal efficacy gain for a cut to enter the LP */
    52#define DEFAULT_MAXDEPTH (-1) /**< maximum depth at which this cutselector is used (-1 : all nodes) */
    53#define DEFAULT_FILTERMODE 'd' /**< filtering strategy during cut selection (
    54 * 'd'ynamic- and 'f'ull dynamic parallelism) */
    55
    56
    57/*
    58 * Data structures
    59 */
    60
    61/** cut selector data */
    62struct SCIP_CutselData
    63{
    64 SCIP_RANDNUMGEN* randnumgen; /**< random generator for tiebreaking */
    65 SCIP_Real objparalweight; /**< weight of objective parallelism in cut score calculation */
    66 SCIP_Real efficacyweight; /**< weight of efficacy in cut score calculation */
    67 SCIP_Real dircutoffdistweight;/**< weight of directed cutoff distance in cut score calculation */
    68 SCIP_Real intsupportweight; /**< weight of integral support in cut score calculation */
    69 SCIP_Real mingain; /**< minimal projection efficacy gain for a cut to enter the LP in percent */
    70 SCIP_Real minortho; /**< minimal orthogonality for a cut to enter the LP */
    71 int maxdepth; /**< maximum depth at which this cutselector is used (-1 : all nodes) */
    72 char filtermode; /**< filtering strategy during cut selection (
    73 * 'd'ynamic- and 'f'ull dynamic parallelism) */
    74};
    75
    76/*
    77 * Local methods
    78 */
    79
    80/* put your local methods here, and declare them static */
    81
    82/** returns the maximum score of cuts; if scores is not NULL, then stores the individual score of each cut in scores */
    83static
    85 SCIP* scip, /**< SCIP data structure */
    86 SCIP_ROW** cuts, /**< array with cuts to score */
    87 SCIP_RANDNUMGEN* randnumgen, /**< random number generator for tie-breaking, or NULL */
    88 SCIP_Real dircutoffdistweight,/**< weight of directed cutoff distance in cut score calculation */
    89 SCIP_Real efficacyweight, /**< weight of efficacy in cut score calculation */
    90 SCIP_Real objparalweight, /**< weight of objective parallelism in cut score calculation */
    91 SCIP_Real intsupportweight, /**< weight of integral support in cut score calculation */
    92 int* currentncuts, /**< current number of cuts in cuts array */
    93 SCIP_Real* scores /**< array to store the score of cuts or NULL */
    94 )
    95{
    96 SCIP_Real maxscore = 0.0;
    97 SCIP_SOL* sol;
    98 int i;
    99 int ncuts = *currentncuts;
    100
    101 sol = SCIPgetBestSol(scip);
    102
    103 /* if there is an incumbent and the factor is not 0.0, compute directed cutoff distances for the incumbent */
    104 if( sol != NULL && dircutoffdistweight > 0.0 )
    105 {
    106 for( i = ncuts-1; i >= 0; --i )
    107 {
    108 SCIP_Real score;
    109 SCIP_Real objparallelism;
    110 SCIP_Real intsupport;
    111 SCIP_Real efficacy;
    112
    113 if( intsupportweight > 0.0 )
    114 intsupport = intsupportweight * SCIPgetRowNumIntCols(scip, cuts[i]) / (SCIP_Real) SCIProwGetNNonz(cuts[i]);
    115 else
    116 intsupport = 0.0;
    117
    118 if( objparalweight > 0.0 )
    119 objparallelism = objparalweight * SCIPgetRowObjParallelism(scip, cuts[i]);
    120 else
    121 objparallelism = 0.0;
    122
    123 efficacy = SCIPgetCutEfficacy(scip, NULL, cuts[i]);
    124
    125 if( SCIProwIsLocal(cuts[i]) )
    126 {
    127 score = dircutoffdistweight * efficacy;
    128 }
    129 else
    130 {
    131 score = SCIPgetCutLPSolCutoffDistance(scip, sol, cuts[i]);
    132 score = dircutoffdistweight * MAX(score, efficacy);
    133 }
    134
    135 score += objparallelism + intsupport + efficacyweight * efficacy;
    136
    137 /* add small term to prefer global pool cuts */
    138 if( SCIProwIsInGlobalCutpool(cuts[i]) )
    139 score += 1e-4;
    140
    141 if( randnumgen != NULL)
    142 {
    143 score += SCIPrandomGetReal(randnumgen, 0.0, 1e-6);
    144 }
    145
    146 maxscore = MAX(maxscore, score);
    147
    148 if( SCIPisLE(scip, score, 0.0) || efficacy == 0.0 ) /*lint !e777*/
    149 {
    150 --ncuts;
    151 SCIPswapPointers((void**) &cuts[i], (void**) &cuts[ncuts]);
    152 if( scores != NULL )
    153 SCIPswapReals(&scores[i], &scores[ncuts]);
    154 }
    155 else if( scores != NULL )
    156 {
    157 scores[i] = score;
    158 }
    159 }
    160 }
    161 else
    162 {
    163 /* in case there is no solution add the directed cutoff distance weight to the efficacy weight
    164 * since the efficacy underestimates the directed cuttoff distance
    165 */
    166 efficacyweight += dircutoffdistweight;
    167
    168 /*lint -e{850} i is modified in the body of the for loop */
    169 for( i = ncuts-1; i >= 0; --i )
    170 {
    171 SCIP_Real score;
    172 SCIP_Real objparallelism;
    173 SCIP_Real intsupport;
    174 SCIP_Real efficacy;
    175
    176 if( intsupportweight > 0.0 )
    177 intsupport = intsupportweight * SCIPgetRowNumIntCols(scip, cuts[i]) / (SCIP_Real) SCIProwGetNNonz(cuts[i]);
    178 else
    179 intsupport = 0.0;
    180
    181 if( objparalweight > 0.0 )
    182 objparallelism = objparalweight * SCIPgetRowObjParallelism(scip, cuts[i]);
    183 else
    184 objparallelism = 0.0;
    185
    186 efficacy = SCIPgetCutEfficacy(scip, NULL, cuts[i]);
    187
    188 score = objparallelism + intsupport + efficacyweight * efficacy;
    189
    190 /* add small term to prefer global pool cuts */
    191 if( SCIProwIsInGlobalCutpool(cuts[i]) )
    192 score += 1e-4;
    193
    194 if( randnumgen != NULL)
    195 {
    196 score += SCIPrandomGetReal(randnumgen, 0.0, 1e-6);
    197 }
    198
    199 maxscore = MAX(maxscore, score);
    200
    201 if( SCIPisLE(scip, score, 0.0) || efficacy == 0.0 ) /*lint !e777*/
    202 {
    203 --ncuts;
    204 SCIPswapPointers((void**) &cuts[i], (void**) &cuts[ncuts]);
    205 if( scores != NULL )
    206 SCIPswapReals(&scores[i], &scores[ncuts]);
    207 }
    208 else if( scores != NULL )
    209 {
    210 scores[i] = score;
    211 }
    212 }
    213 }
    214 *currentncuts = ncuts;
    215}
    216
    217/** compute projectioncut score for cuts from a given bestcut. **/
    218static
    220 SCIP* scip, /**< SCIP data structure */
    221 SCIP_ROW* bestcut, /**< cut to filter orthogonality with */
    222 SCIP_ROW* cut, /**< cut to perform scoring on */
    223 SCIP_Real* score /**< score for cut */
    224 )
    225{
    226 SCIP_Real efficacy;
    227 SCIP_Real currentbestefficacy;
    228 SCIP_Real cosineangle;
    229
    230 SCIPdebugMsg(scip, "\ncomputeProjectionScore.\n\n");
    231 currentbestefficacy = SCIPgetCutEfficacy(scip, NULL, bestcut);
    232 SCIPdebugMsg(scip, "currentbestefficacy = %g\n", currentbestefficacy);
    233
    234 efficacy = SCIPgetCutEfficacy(scip, NULL, cut);
    235 SCIPdebugMsg(scip, "efficacy[%s] = %g\n", SCIProwGetName(cut), efficacy);
    236
    237 cosineangle = SCIProwGetParallelism(bestcut, cut, 'e');
    238 if( SCIPisEQ(scip, cosineangle, 1.0))
    239 *score = -SCIPinfinity(scip);
    240 else
    241 {
    242 *score = sqrt(currentbestefficacy * currentbestefficacy + efficacy * efficacy
    243 - 2.0 * fabs(currentbestefficacy) * fabs(efficacy) * cosineangle)
    244 / sqrt((1.0 - (cosineangle * cosineangle)));
    245 *score -= currentbestefficacy;
    246 }
    247 SCIPdebugMsg(scip, "Projectionscore[%s] = %g\n", SCIProwGetName(cut), *score);
    248 return SCIP_OKAY;
    249}
    250
    251/** move the cut with the highest score to the first position in the array; there must be at least one cut */
    252static
    254 SCIP_ROW** cuts, /**< array with cuts to perform selection algorithm */
    255 SCIP_Real* scores, /**< array with scores of cuts to perform selection algorithm */
    256 int ncuts /**< number of cuts in given array */
    257 )
    258{
    259 int i;
    260 int bestpos;
    261 SCIP_Real bestscore;
    262
    263 assert(ncuts > 0);
    264 assert(cuts != NULL);
    265 assert(scores != NULL);
    266
    267 bestscore = scores[0];
    268 bestpos = 0;
    269
    270 for( i = 1; i < ncuts; ++i )
    271 {
    272 if( scores[i] > bestscore )
    273 {
    274 bestpos = i;
    275 bestscore = scores[i];
    276 }
    277 }
    278
    279 SCIPswapPointers((void**) &cuts[bestpos], (void**) &cuts[0]);
    280 SCIPswapReals(&scores[bestpos], &scores[0]);
    281}
    282
    283/** filters the given array of cuts to enforce a maximum parallelism constraint
    284 * w.r.t the given cut; moves filtered cuts to the end of the array and returns number of selected cuts */
    285static
    287 SCIP* scip, /**< SCIP data structure */
    288 SCIP_ROW* bestcut, /**< cut to filter orthogonality with */
    289 SCIP_ROW** cuts, /**< array with cuts to perform selection algorithm */
    290 SCIP_Real* scores, /**< array with scores of cuts to perform selection algorithm */
    291 SCIP_Real mingain, /**< minimum gain enforced on the two-cut efficacy */
    292 SCIP_Real maxparall, /**< maximal parallelism for all cuts that are not good */
    293 int ncuts /**< number of cuts in given array */
    294 )
    295{
    296 int i;
    297 SCIP_Bool filter;
    298 SCIP_Real bestcutefficacy;
    299
    300 SCIPdebugMsg(scip, "\nfilterWithDynamicParallelism.\n\n");
    301
    302 assert(bestcut != NULL);
    303 assert(ncuts == 0 || cuts != NULL);
    304 assert(ncuts == 0 || scores != NULL);
    305
    306 bestcutefficacy = SCIPgetCutEfficacy(scip, NULL, bestcut);
    307 assert(bestcutefficacy > 0.0); /* ensured in scoring() */
    308
    309 /*lint -e{850} i is modified in the body of the for loop */
    310 for( i = ncuts-1; i >= 0; --i )
    311 {
    312 SCIP_Real thisparall;
    313 SCIP_Real cosine;
    314 SCIP_Real currentcutefficacy;
    315 SCIP_Real minmaxparall;
    316
    317 currentcutefficacy = SCIPgetCutEfficacy(scip, NULL, cuts[i]);
    318 assert(currentcutefficacy > 0.0); /* ensured in scoring() */
    319
    320 if( SCIPisGE(scip, bestcutefficacy, currentcutefficacy))
    321 {
    322 cosine = SCIProwGetParallelism(bestcut, cuts[i], 'e');
    323 thisparall = cosine * bestcutefficacy / currentcutefficacy;
    324 SCIPdebugMsg(scip, "Thisparall(%g) = cosine(%g) * (bestcutefficacy(%g)/ currentcutefficacy(%g))\n\n", thisparall,
    325 cosine, bestcutefficacy, currentcutefficacy);
    326 }
    327 else
    328 {
    329 cosine = SCIProwGetParallelism(cuts[i], bestcut, 'e');
    330 thisparall = cosine * currentcutefficacy / bestcutefficacy;
    331 SCIPdebugMsg(scip, "Thisparall(%g) = cosine(%g) * (currentcutefficacy(%g) / bestcutefficacy(%g))\n\n", thisparall,
    332 cosine, currentcutefficacy, bestcutefficacy);
    333 }
    334
    335 /* compute the max-minimum angle for given the given cuts to enforce
    336 * norm(d) >= (1+mingain)*eff1 for non-negative cosine angle */
    337 minmaxparall = MAX( (bestcutefficacy * bestcutefficacy
    338 + currentcutefficacy * currentcutefficacy
    339 - (1 + mingain) * bestcutefficacy * (1 + mingain) * bestcutefficacy * (1 - cosine * cosine))
    340 / (2 * bestcutefficacy * currentcutefficacy),
    341 maxparall );
    342 filter = ( SCIPisGE(scip, thisparall, 1.0) || SCIPisGT(scip, cosine, minmaxparall) );
    343
    344 SCIPdebugMsg(scip, "Filter = %u\n", filter);
    345
    346 if( filter )
    347 {
    348 --ncuts;
    349 SCIPswapPointers((void**) &cuts[i], (void**) &cuts[ncuts]);
    350 SCIPswapReals(&scores[i], &scores[ncuts]);
    351 }
    352 }
    353
    354 return ncuts;
    355}
    356
    357
    358/*
    359 * Callback methods of cut selector
    360 */
    361
    362/** copy method for cut selector plugin (called when SCIP copies plugins) */
    363static
    364SCIP_DECL_CUTSELCOPY(cutselCopyDynamic)
    365{ /*lint --e{715}*/
    366 assert(scip != NULL);
    367 assert(cutsel != NULL);
    368
    370
    371 /* call inclusion method of cut selector */
    373
    374 return SCIP_OKAY;
    375}
    376
    377/** destructor of cut selector to free user data (called when SCIP is exiting) */
    378/**! [SnippetCutselFreeDynamic] */
    379static
    380SCIP_DECL_CUTSELFREE(cutselFreeDynamic)
    381{ /*lint --e{715}*/
    382 SCIP_CUTSELDATA* cutseldata;
    383
    384 cutseldata = SCIPcutselGetData(cutsel);
    385
    386 SCIPfreeBlockMemory(scip, &cutseldata);
    387
    388 SCIPcutselSetData(cutsel, NULL);
    389
    390 return SCIP_OKAY;
    391}
    392/**! [SnippetCutselFreeDynamic] */
    393
    394/** initialization method of cut selector (called after problem was transformed) */
    395static
    396SCIP_DECL_CUTSELINIT(cutselInitDynamic)
    397{ /*lint --e{715}*/
    398 SCIP_CUTSELDATA* cutseldata;
    399
    400 cutseldata = SCIPcutselGetData(cutsel);
    401 assert(cutseldata != NULL);
    402
    403 SCIP_CALL( SCIPcreateRandom(scip, &(cutseldata)->randnumgen, RANDSEED, TRUE) );
    404
    405 return SCIP_OKAY;
    406}
    407
    408/** deinitialization method of cut selector (called before transformed problem is freed) */
    409static
    410SCIP_DECL_CUTSELEXIT(cutselExitDynamic)
    411{ /*lint --e{715}*/
    412 SCIP_CUTSELDATA* cutseldata;
    413
    414 cutseldata = SCIPcutselGetData(cutsel);
    415 assert(cutseldata != NULL);
    416 assert(cutseldata->randnumgen != NULL);
    417
    418 SCIPfreeRandom(scip, &cutseldata->randnumgen);
    419
    420 return SCIP_OKAY;
    421}
    422
    423/** cut selection method of cut selector */
    424static
    425SCIP_DECL_CUTSELSELECT(cutselSelectDynamic)
    426{ /*lint --e{715}*/
    427 SCIP_CUTSELDATA *cutseldata;
    428
    429 assert(cutsel != NULL);
    430 assert(result != NULL);
    431
    432 *result = SCIP_SUCCESS;
    433
    434 cutseldata = SCIPcutselGetData(cutsel);
    435 assert(cutseldata != NULL);
    436 if (cutseldata->maxdepth != -1 && cutseldata->maxdepth < SCIPgetDepth(scip))
    437 {
    438 *result = SCIP_DIDNOTFIND;
    439 return SCIP_OKAY;
    440 }
    441
    442 SCIP_CALL( SCIPselectCutsDynamic(scip, cuts, forcedcuts, cutseldata->randnumgen, cutseldata->filtermode,
    443 cutseldata->mingain, 1-cutseldata->minortho, cutseldata->dircutoffdistweight, cutseldata->efficacyweight,
    444 cutseldata->objparalweight, cutseldata->intsupportweight, ncuts, nforcedcuts,
    445 maxnselectedcuts, nselectedcuts) );
    446
    447 return SCIP_OKAY;
    448}
    449
    450
    451/*
    452 * cut selector specific interface methods
    453 */
    454
    455/** creates the dynamic cut selector and includes it in SCIP */
    457 SCIP* scip /**< SCIP data structure */
    458 )
    459{
    460 SCIP_CUTSELDATA* cutseldata;
    461 SCIP_CUTSEL* cutsel;
    462
    463 /* create dynamic cut selector data */
    464 SCIP_CALL( SCIPallocBlockMemory(scip, &cutseldata) );
    465 BMSclearMemory(cutseldata);
    466
    467 SCIP_CALL( SCIPincludeCutselBasic(scip, &cutsel, CUTSEL_NAME, CUTSEL_DESC, CUTSEL_PRIORITY, cutselSelectDynamic, cutseldata) );
    468
    469 assert(cutsel != NULL);
    470
    471 /* set non fundamental callbacks via setter functions */
    472 SCIP_CALL( SCIPsetCutselCopy(scip, cutsel, cutselCopyDynamic) );
    473
    474 SCIP_CALL( SCIPsetCutselFree(scip, cutsel, cutselFreeDynamic) );
    475 SCIP_CALL( SCIPsetCutselInit(scip, cutsel, cutselInitDynamic) );
    476 SCIP_CALL( SCIPsetCutselExit(scip, cutsel, cutselExitDynamic) );
    477
    478 /* add dynamic cut selector parameters */
    480 "cutselection/" CUTSEL_NAME "/efficacyweight",
    481 "weight of efficacy in cut score calculation",
    482 &cutseldata->efficacyweight, FALSE,
    484
    486 "cutselection/" CUTSEL_NAME "/dircutoffdistweight",
    487 "weight of directed cutoff distance in cut score calculation",
    488 &cutseldata->dircutoffdistweight, FALSE,
    490
    492 "cutselection/" CUTSEL_NAME "/objparalweight",
    493 "weight of objective parallelism in cut score calculation",
    494 &cutseldata->objparalweight, FALSE,
    496
    498 "cutselection/" CUTSEL_NAME "/intsupportweight",
    499 "weight of integral support in cut score calculation",
    500 &cutseldata->intsupportweight, FALSE,
    502
    504 "cutselection/" CUTSEL_NAME "/mingain",
    505 "minimal efficacy gain for a cut to enter the LP",
    506 &cutseldata->mingain, FALSE,
    507 DEFAULT_MINGAIN, 0.0, 1.0, NULL, NULL) );
    508
    510 "cutselection/" CUTSEL_NAME "/filtermode",
    511 "filtering strategy during cut selection",
    512 &cutseldata->filtermode, FALSE,
    513 DEFAULT_FILTERMODE, "df", NULL, NULL) );
    514
    516 "cutselection/" CUTSEL_NAME "/minortho",
    517 "minimal orthogonality for a cut to enter the LP",
    518 &cutseldata->minortho, FALSE,
    519 DEFAULT_MINORTHO, 0.0, 1.0, NULL, NULL) );
    520
    522 "cutselection/" CUTSEL_NAME "/maxdepth",
    523 "maximum depth at which this cutselector is employed",
    524 &cutseldata->maxdepth, FALSE,
    526
    527 return SCIP_OKAY;
    528}
    529
    530
    531/** perform a cut selection algorithm for the given array of cuts
    532 *
    533 * This is the selection method of the dynamic cut selector which implements
    534 * the dynamic orthognality filtering based on the ratio of efficacies.
    535 * The input cuts array gets re-sorted s.t the selected cuts come first and the remaining
    536 * ones are the end.
    537 */
    539 SCIP* scip, /**< SCIP data structure */
    540 SCIP_ROW** cuts, /**< array with cuts to perform selection algorithm */
    541 SCIP_ROW** forcedcuts, /**< array with forced cuts */
    542 SCIP_RANDNUMGEN* randnumgen, /**< random number generator for tie-breaking, or NULL */
    543 char filtermode, /**< filtering strategy during cut selection (
    544 * 'd'ynamic- and 'f'ull dynamic parallelism) */
    545 SCIP_Real mingain, /**< minimum efficacy gain in percentage to filter cuts */
    546 SCIP_Real maxparall, /**< maximal parallelism for all cuts that are not good */
    547 SCIP_Real dircutoffdistweight,/**< weight of directed cutoff distance in cut score calculation */
    548 SCIP_Real efficacyweight, /**< weight of efficacy in cut score calculation */
    549 SCIP_Real objparalweight, /**< weight of objective parallelism in cut score calculation */
    550 SCIP_Real intsupportweight, /**< weight of integral support in cut score calculation */
    551 int ncuts, /**< number of cuts in cuts array */
    552 int nforcedcuts, /**< number of forced cuts */
    553 int maxselectedcuts, /**< maximal number of cuts from cuts array to select */
    554 int* nselectedcuts /**< pointer to return number of selected cuts from cuts array */
    555 )
    556{
    557 SCIP_ROW* selectedcut;
    558 SCIP_Real* scores;
    559 SCIP_Real* forcedscores;
    560 SCIP_Real* scoresptr;
    561 int ngoodforcedcuts;
    562 int i;
    563
    564 assert(cuts != NULL && ncuts > 0);
    565 assert(forcedcuts != NULL || nforcedcuts == 0);
    566 assert(nselectedcuts != NULL);
    567
    568 *nselectedcuts = 0;
    569 ngoodforcedcuts = 0;
    570
    571 SCIP_CALL( SCIPallocBufferArray(scip, &scores, ncuts) );
    572
    573 /* compute scores of cuts and max score of cuts and forced cuts (used to define goodscore) */
    574 scoring(scip, cuts, randnumgen, dircutoffdistweight, efficacyweight, objparalweight, intsupportweight, &ncuts,
    575 scores);
    576 scoresptr = scores;
    577
    578 SCIPdebugMsg(scip, "nforcedcuts = %i.\n", nforcedcuts);
    579
    580 /* perform cut selection algorithm for the cuts */
    581
    582 /* forced cuts are going to be selected so use them to filter cuts */
    583 for( i = 0; i < nforcedcuts && ncuts > 0; ++i )
    584 ncuts = filterWithDynamicParallelism(scip, forcedcuts[i], cuts, scores, mingain, maxparall, ncuts);
    585
    586 /* if all cuts are already filtered, we can stop */
    587 if( ncuts <= 0 )
    588 goto TERMINATE;
    589
    590 /* if the maximal number of cuts was selected, we can stop here */
    591 if( *nselectedcuts == maxselectedcuts )
    592 goto TERMINATE;
    593
    594 if( filtermode == 'f' && nforcedcuts > 0 )
    595 {
    596 SCIP_CALL( SCIPallocBufferArray(scip, &forcedscores, nforcedcuts) );
    597 ngoodforcedcuts = nforcedcuts;
    598 scoring(scip, forcedcuts, randnumgen, dircutoffdistweight, efficacyweight, objparalweight, intsupportweight,
    599 &ngoodforcedcuts, forcedscores);
    600
    601 if( ngoodforcedcuts != 0 )
    602 {
    603 selectBestCut(forcedcuts, forcedscores, ngoodforcedcuts);
    604 SCIPfreeBufferArray(scip, &forcedscores);
    605 SCIPdebugMsg(scip, "best forced cut: %s.\n", SCIProwGetName(forcedcuts[0]));
    606
    607 for( i = 0; i < ncuts; i++ )
    608 {
    609 SCIP_CALL( computeProjectionScore(scip, forcedcuts[0], cuts[i], &scores[i]) );
    610 SCIPdebugMsg(scip, "scores[%i] = %g\n", i, scores[i]);
    611 }
    612 }
    613 }
    614
    615 if( ngoodforcedcuts == 0 )
    616 {
    617 assert(filtermode == 'd' || ngoodforcedcuts == 0);
    618 selectBestCut(cuts, scores, ncuts);
    619
    620 selectedcut = cuts[0];
    621 SCIPdebugMsg(scip, "selectedcut = %s.\n", SCIProwGetName(selectedcut));
    622
    623 ++(*nselectedcuts);
    624
    625 /* if the maximal number of cuts was selected, we can stop here */
    626 if( *nselectedcuts == maxselectedcuts )
    627 goto TERMINATE;
    628
    629 /* move the pointers to the next position and filter the remaining cuts to enforce the dynamic parallelism constraint */
    630 ++cuts;
    631 ++scores;
    632 --ncuts;
    633
    634 ncuts = filterWithDynamicParallelism(scip, selectedcut, cuts, scores, mingain, maxparall, ncuts);
    635
    636 if( filtermode == 'f' )
    637 {
    638 for( i = 0; i < ncuts; i++ )
    639 {
    640 SCIP_CALL( computeProjectionScore(scip, selectedcut, cuts[i], &scores[i]) );
    641 }
    642 }
    643 }
    644
    645 SCIPdebugMsg(scip, "ncuts after forced cut filter = %i.\n", ncuts);
    646
    647 /* now greedily select the remaining cuts */
    648 while( ncuts > 0 )
    649 {
    650 selectBestCut(cuts, scores, ncuts);
    651 selectedcut = cuts[0];
    652 SCIPdebugMsg(scip, "selectedcut = %s.\n", SCIProwGetName(selectedcut));
    653
    654 ++(*nselectedcuts);
    655
    656 /* if the maximal number of cuts was selected, we can stop here */
    657 if( *nselectedcuts == maxselectedcuts )
    658 goto TERMINATE;
    659
    660 /* move the pointers to the next position and filter the remaining cuts to enforce the dynamic parallelism constraint */
    661 ++cuts;
    662 ++scores;
    663 --ncuts;
    664
    665 ncuts = filterWithDynamicParallelism(scip, selectedcut, cuts, scores, mingain, maxparall, ncuts);
    666
    667 if( filtermode == 'f' )
    668 {
    669 for( i = 0; i < ncuts; i++ )
    670 {
    671 SCIP_CALL( computeProjectionScore(scip, selectedcut, cuts[i], &scores[i]) );
    672 SCIPdebugMsg(scip, "nonforcedscores[%i] = %g\n", i, scores[i]);
    673 }
    674 }
    675 }
    676
    677 TERMINATE:
    678 SCIPfreeBufferArray(scip, &scoresptr);
    679 return SCIP_OKAY;
    680}
    #define DEFAULT_MINGAIN
    #define DEFAULT_EFFICACYWEIGHT
    #define DEFAULT_OBJPARALWEIGHT
    #define RANDSEED
    static int filterWithDynamicParallelism(SCIP *scip, SCIP_ROW *bestcut, SCIP_ROW **cuts, SCIP_Real *scores, SCIP_Real mingain, SCIP_Real maxparall, int ncuts)
    static SCIP_DECL_CUTSELSELECT(cutselSelectDynamic)
    #define DEFAULT_MAXDEPTH
    static SCIP_DECL_CUTSELFREE(cutselFreeDynamic)
    static void selectBestCut(SCIP_ROW **cuts, SCIP_Real *scores, int ncuts)
    #define CUTSEL_DESC
    static SCIP_DECL_CUTSELCOPY(cutselCopyDynamic)
    #define DEFAULT_FILTERMODE
    #define CUTSEL_PRIORITY
    static SCIP_RETCODE computeProjectionScore(SCIP *scip, SCIP_ROW *bestcut, SCIP_ROW *cut, SCIP_Real *score)
    #define DEFAULT_MINORTHO
    #define DEFAULT_DIRCUTOFFDISTWEIGHT
    static SCIP_DECL_CUTSELINIT(cutselInitDynamic)
    static void scoring(SCIP *scip, SCIP_ROW **cuts, SCIP_RANDNUMGEN *randnumgen, SCIP_Real dircutoffdistweight, SCIP_Real efficacyweight, SCIP_Real objparalweight, SCIP_Real intsupportweight, int *currentncuts, SCIP_Real *scores)
    #define CUTSEL_NAME
    static SCIP_DECL_CUTSELEXIT(cutselExitDynamic)
    #define DEFAULT_INTSUPPORTWEIGHT
    dynamic cut selector
    #define NULL
    Definition: def.h:257
    #define SCIP_MAXTREEDEPTH
    Definition: def.h:306
    #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 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
    SCIP_RETCODE SCIPselectCutsDynamic(SCIP *scip, SCIP_ROW **cuts, SCIP_ROW **forcedcuts, SCIP_RANDNUMGEN *randnumgen, char filtermode, SCIP_Real mingain, SCIP_Real maxparall, SCIP_Real dircutoffdistweight, SCIP_Real efficacyweight, SCIP_Real objparalweight, SCIP_Real intsupportweight, int ncuts, int nforcedcuts, int maxselectedcuts, int *nselectedcuts)
    SCIP_RETCODE SCIPincludeCutselDynamic(SCIP *scip)
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    SCIP_RETCODE SCIPaddCharParam(SCIP *scip, const char *name, const char *desc, char *valueptr, SCIP_Bool isadvanced, char defaultvalue, const char *allowedvalues, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:167
    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
    void SCIPswapPointers(void **pointer1, void **pointer2)
    Definition: misc.c:10511
    void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
    Definition: misc.c:10498
    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
    #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 SCIProwGetParallelism(SCIP_ROW *row1, SCIP_ROW *row2, char orthofunc)
    Definition: lp.c:7970
    int SCIProwGetNNonz(SCIP_ROW *row)
    Definition: lp.c:17607
    SCIP_Bool SCIProwIsInGlobalCutpool(SCIP_ROW *row)
    Definition: lp.c:17885
    SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
    Definition: lp.c:17795
    const char * SCIProwGetName(SCIP_ROW *row)
    Definition: lp.c:17745
    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_SOL * SCIPgetBestSol(SCIP *scip)
    Definition: scip_sol.c:2986
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    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