SCIP

    Solving Constraint Integer Programs

    sepa_aggregation.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2026 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file sepa_aggregation.c
    26 * @ingroup DEFPLUGINS_SEPA
    27 * @brief flow cover and complemented mixed integer rounding cuts separator (Marchand's version)
    28 * @author Leona Gottwald
    29 * @author Kati Wolter
    30 * @author Tobias Achterberg
    31 *
    32 * For an overview see:
    33 *
    34 * Marchand, H., & Wolsey, L. A. (2001).@n
    35 * Aggregation and mixed integer rounding to solve MIPs.@n
    36 * Operations research, 49(3), 363-371.
    37 *
    38 * Some remarks:
    39 * - In general, continuous variables are less prefered than integer variables, since their cut
    40 * coefficient is worse.
    41 * - We seek for aggregations that project out continuous variables that are far away from their bound,
    42 * since if it is at its bound then it doesn't contribute to the violation
    43 * - These aggregations are also useful for the flowcover separation, so after building an aggregation
    44 * we try to generate a MIR cut and a flowcover cut.
    45 * - We only keep the best cut.
    46 */
    47
    48/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    49
    51#include "scip/cuts.h"
    52#include "scip/pub_lp.h"
    53#include "scip/pub_message.h"
    54#include "scip/pub_misc.h"
    55#include "scip/pub_misc_sort.h"
    56#include "scip/pub_sepa.h"
    57#include "scip/pub_var.h"
    58#include "scip/scip_branch.h"
    59#include "scip/scip_cut.h"
    60#include "scip/scip_general.h"
    61#include "scip/scip_lp.h"
    62#include "scip/scip_mem.h"
    63#include "scip/scip_message.h"
    64#include "scip/scip_numerics.h"
    65#include "scip/scip_param.h"
    66#include "scip/scip_prob.h"
    67#include "scip/scip_sepa.h"
    68#include "scip/scip_sol.h"
    70#include "scip/scip_tree.h"
    71#include "scip/scip_var.h"
    73
    74
    75#define SEPA_NAME "aggregation"
    76#define SEPA_DESC "aggregation heuristic for complemented mixed integer rounding cuts and flowcover cuts"
    77#define SEPA_PRIORITY -3000
    78#define SEPA_FREQ 10
    79#define SEPA_MAXBOUNDDIST 1.0
    80#define SEPA_USESSUBSCIP FALSE /**< does the separator use a secondary SCIP instance? */
    81#define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
    82
    83#define DEFAULT_MAXROUNDS -1 /**< maximal number of cmir separation rounds per node (-1: unlimited) */
    84#define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of cmir separation rounds in the root node (-1: unlimited) */
    85#define DEFAULT_MAXTRIES 200 /**< maximal number of rows to start aggregation with per separation round
    86 * (-1: unlimited) */
    87#define DEFAULT_MAXTRIESROOT -1 /**< maximal number of rows to start aggregation with per round in the root node
    88 * (-1: unlimited) */
    89#define DEFAULT_MAXFAILS 20 /**< maximal number of consecutive unsuccessful aggregation tries (-1: unlimited) */
    90#define DEFAULT_MAXFAILSROOT 100 /**< maximal number of consecutive unsuccessful aggregation tries in the root node
    91 * (-1: unlimited) */
    92#define DEFAULT_MAXAGGRS 3 /**< maximal number of aggregations for each row per separation round */
    93#define DEFAULT_MAXAGGRSROOT 6 /**< maximal number of aggregations for each row per round in the root node */
    94#define DEFAULT_MAXSEPACUTS 100 /**< maximal number of cmir cuts separated per separation round */
    95#define DEFAULT_MAXSEPACUTSROOT 500 /**< maximal number of cmir cuts separated per separation round in root node */
    96#define DEFAULT_MAXSLACK 0.0 /**< maximal slack of rows to be used in aggregation */
    97#define DEFAULT_MAXSLACKROOT 0.1 /**< maximal slack of rows to be used in aggregation in the root node */
    98#define DEFAULT_DENSITYSCORE 1e-4 /**< weight of row density in the aggregation scoring of the rows */
    99#define DEFAULT_SLACKSCORE 1e-3 /**< weight of slack in the aggregation scoring of the rows */
    100#define DEFAULT_MAXAGGDENSITY 0.20 /**< maximal density of aggregated row */
    101#define DEFAULT_MAXROWDENSITY 0.05 /**< maximal density of row to be used in aggregation */
    102#define DEFAULT_DENSITYOFFSET 100 /**< additional number of variables allowed in row on top of density */
    103#define DEFAULT_MAXROWFAC 1e+4 /**< maximal row aggregation factor */
    104#define DEFAULT_MAXTESTDELTA (-1) /**< maximal number of different deltas to try (-1: unlimited) */
    105#define DEFAULT_AGGRTOL 1e-2 /**< aggregation heuristic: we try to delete continuous variables from the current
    106 * aggregation, whose distance to its tightest bound is >= L - DEFAULT_AGGRTOL,
    107 * where L is the largest of the distances between a continuous variable's value
    108 * and its tightest bound in the current aggregation */
    109#define DEFAULT_TRYNEGSCALING TRUE /**< should negative values also be tested in scaling? */
    110#define DEFAULT_FIXINTEGRALRHS TRUE /**< should an additional variable be complemented if f0 = 0? */
    111#define DEFAULT_DYNAMICCUTS TRUE /**< should generated cuts be removed from the LP if they are no longer tight? */
    112
    113#define MAKECONTINTEGRAL FALSE
    114#define IMPLINTSARECONT
    115
    116
    117/*
    118 * Data structures
    119 */
    120
    121/** separator data */
    122struct SCIP_SepaData
    123{
    124 SCIP_Real maxslack; /**< maximal slack of rows to be used in aggregation */
    125 SCIP_Real maxslackroot; /**< maximal slack of rows to be used in aggregation in the root node */
    126 SCIP_Real densityscore; /**< weight of row density in the aggregation scoring of the rows */
    127 SCIP_Real slackscore; /**< weight of slack in the aggregation scoring of the rows */
    128 SCIP_Real maxaggdensity; /**< maximal density of aggregated row */
    129 SCIP_Real maxrowdensity; /**< maximal density of row to be used in aggregation */
    130 SCIP_Real maxrowfac; /**< maximal row aggregation factor */
    131 SCIP_Real aggrtol; /**< tolerance for bound distance used in aggregation heuristic */
    132 int maxrounds; /**< maximal number of cmir separation rounds per node (-1: unlimited) */
    133 int maxroundsroot; /**< maximal number of cmir separation rounds in the root node (-1: unlimited) */
    134 int maxtries; /**< maximal number of rows to start aggregation with per separation round
    135 * (-1: unlimited) */
    136 int maxtriesroot; /**< maximal number of rows to start aggregation with per round in the root node
    137 * (-1: unlimited) */
    138 int maxfails; /**< maximal number of consecutive unsuccessful aggregation tries
    139 * (-1: unlimited) */
    140 int maxfailsroot; /**< maximal number of consecutive unsuccessful aggregation tries in the root
    141 * node (-1: unlimited) */
    142 int maxaggrs; /**< maximal number of aggregations for each row per separation round */
    143 int maxaggrsroot; /**< maximal number of aggregations for each row per round in the root node */
    144 int maxsepacuts; /**< maximal number of cmir cuts separated per separation round */
    145 int maxsepacutsroot; /**< maximal number of cmir cuts separated per separation round in root node */
    146 int densityoffset; /**< additional number of variables allowed in row on top of density */
    147 int maxtestdelta; /**< maximal number of different deltas to try (-1: unlimited) */
    148 SCIP_Bool trynegscaling; /**< should negative values also be tested in scaling? */
    149 SCIP_Bool fixintegralrhs; /**< should an additional variable be complemented if f0 = 0? */
    150 SCIP_Bool dynamiccuts; /**< should generated cuts be removed from the LP if they are no longer tight? */
    151 SCIP_Bool sepflowcover; /**< whether flowcover cuts should be separated in the current call */
    152 SCIP_Bool sepknapsackcover; /**< whether knapsack cover cuts should be separated in the current call */
    153 SCIP_Bool sepcmir; /**< whether cMIR cuts should be separated in the current call */
    154 SCIP_SEPA* cmir; /**< separator for adding cmir cuts */
    155 SCIP_SEPA* flowcover; /**< separator for adding flowcover cuts */
    156 SCIP_SEPA* knapsackcover; /**< separator for adding knapsack cover cuts */
    157};
    158
    159/** data used for aggregation of row */
    160typedef
    161struct AggregationData {
    162 SCIP_Real* bounddist; /**< bound distance of continuous variables */
    163 int* bounddistinds; /**< problem indices of the continUous variables corresponding to the bounddistance value */
    164 int nbounddistvars; /**< number of continuous variables that are not at their bounds */
    165 SCIP_ROW** aggrrows; /**< array of rows suitable for substitution of continuous variable */
    166 SCIP_Real* aggrrowscoef; /**< coefficient of continuous variable in row that is suitable for substitution of that variable */
    167 int aggrrowssize; /**< size of aggrrows array */
    168 int naggrrows; /**< occupied positions in aggrrows array */
    169 int* aggrrowsstart; /**< array with start positions of suitable rows for substitution for each
    170 * continuous variable with non-zero bound distance */
    171 int* ngoodaggrrows; /**< array with number of rows suitable for substitution that only contain
    172 * one continuous variable that is not at it's bound */
    173 int* nbadvarsinrow; /**< number of continuous variables that are not at their bounds for each row */
    174 SCIP_AGGRROW* aggrrow; /**< store aggregation row here so that it can be reused */
    176
    177/*
    178 * Local methods
    179 */
    180
    181/** adds given cut to LP if violated */
    182static
    184 SCIP* scip, /**< SCIP data structure */
    185 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    186 SCIP_SEPA* sepa, /**< separator */
    187 SCIP_Bool makeintegral, /**< should cut be scaled to integral coefficients if possible? */
    188 SCIP_Real* cutcoefs, /**< coefficients of active variables in cut */
    189 int* cutinds, /**< problem indices of variables in cut */
    190 int cutnnz, /**< number of non-zeros in cut */
    191 SCIP_Real cutrhs, /**< right hand side of cut */
    192 SCIP_Real cutefficacy, /**< efficacy of cut */
    193 SCIP_Bool cutislocal, /**< is the cut only locally valid? */
    194 SCIP_Bool cutremovable, /**< should the cut be removed from the LP due to aging or cleanup? */
    195 int cutrank, /**< rank of the cut */
    196 const char* cutclassname, /**< name of cut class to use for row names */
    197 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
    198 int* ncuts, /**< pointer to count the number of added cuts */
    199 SCIP_ROW** thecut /**< pointer to return cut if it was added */
    200 )
    201{
    202 assert(scip != NULL);
    203 assert(cutcoefs != NULL);
    204 assert(cutoff != NULL);
    205 assert(ncuts != NULL);
    206
    207 *cutoff = FALSE;
    208
    209 if( cutnnz > 0 && SCIPisEfficacious(scip, cutefficacy) )
    210 {
    211 SCIP_VAR** vars;
    212 int i;
    213 SCIP_ROW* cut;
    214 char cutname[SCIP_MAXSTRLEN];
    215 SCIP_Bool success;
    216
    217 /* get active problem variables */
    218 vars = SCIPgetVars(scip);
    219
    220 /* create cut name */
    221 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "%s%" SCIP_LONGINT_FORMAT "_%d", cutclassname, SCIPgetNLPs(scip), *ncuts);
    222
    223tryagain:
    224 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), cutrhs, cutislocal, FALSE, cutremovable) );
    225
    227
    228 for( i = 0; i < cutnnz; ++i )
    229 {
    230 SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[cutinds[i]], cutcoefs[i]) );
    231 }
    232
    233 /* set cut rank */
    234 SCIProwChgRank(cut, cutrank);
    235
    236 SCIPdebugMsg(scip, " -> found potential %s cut <%s>: rhs=%f, eff=%f\n", cutclassname, cutname, cutrhs, cutefficacy);
    238
    239 /* if requested, try to scale the cut to integral values but only if the scaling is small; otherwise keep the fractional cut */
    240 if( makeintegral && SCIPgetRowNumIntCols(scip, cut) == SCIProwGetNNonz(cut) )
    241 {
    243 1000LL, 1000.0, MAKECONTINTEGRAL, &success) );
    244
    246 {
    247 /* release the row */
    248 SCIP_CALL( SCIPreleaseRow(scip, &cut) );
    249
    250 /* the scaling destroyed the cut, so try to add it again, but this time do not scale it */
    251 makeintegral = FALSE;
    252 goto tryagain;
    253 }
    254 }
    255 else
    256 {
    257 success = FALSE;
    258 }
    259
    260 if( success && !SCIPisCutEfficacious(scip, sol, cut) )
    261 {
    262 SCIPdebugMsg(scip, " -> %s cut <%s> no longer efficacious: rhs=%f, eff=%f\n", cutclassname, cutname, cutrhs, cutefficacy);
    264
    265 SCIP_CALL( SCIPreleaseRow(scip, &cut) );
    266
    267 /* the cut is not efficacious anymore due to the scaling, so do not add it */
    268 return SCIP_OKAY;
    269 }
    270
    271 SCIPdebugMsg(scip, " -> found %s cut <%s>: rhs=%f, eff=%f, rank=%d, min=%f, max=%f (range=%g)\n",
    272 cutclassname, cutname, cutrhs, cutefficacy, SCIProwGetRank(cut),
    276
    278
    279 if( SCIPisCutNew(scip, cut) )
    280 {
    281 (*ncuts)++;
    282
    283 if( !cutislocal )
    284 {
    286 }
    287 else
    288 {
    289 SCIP_CALL( SCIPaddRow(scip, cut, FALSE, cutoff) );
    290 }
    291
    292 *thecut = cut;
    293 }
    294 else
    295 {
    296 /* release the row */
    297 SCIP_CALL( SCIPreleaseRow(scip, &cut) );
    298 }
    299 }
    300
    301 return SCIP_OKAY;
    302}
    303
    304/** setup data for aggregating rows */
    305static
    307 SCIP* scip, /**< SCIP data structure */
    308 SCIP_SOL* sol, /**< solution to separate, NULL for LP solution */
    309 SCIP_Bool allowlocal, /**< should local cuts be allowed */
    310 AGGREGATIONDATA* aggrdata /**< pointer to aggregation data to setup */
    311 )
    312{
    313 SCIP_VAR** vars;
    314 int nvars;
    315 int nbinvars;
    316 int nintvars;
    317 int ncontvars;
    318 int firstcontvar;
    319 int nimplvars;
    320 SCIP_ROW** rows;
    321 int nrows;
    322 int i;
    323
    324 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, &nimplvars, &ncontvars) );
    325 SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
    326
    327 SCIP_CALL( SCIPallocBufferArray(scip, &aggrdata->bounddist, ncontvars + nimplvars) );
    328 SCIP_CALL( SCIPallocBufferArray(scip, &aggrdata->bounddistinds, ncontvars + nimplvars) );
    329 SCIP_CALL( SCIPallocBufferArray(scip, &aggrdata->ngoodaggrrows, ncontvars + nimplvars) );
    330 SCIP_CALL( SCIPallocBufferArray(scip, &aggrdata->aggrrowsstart, ncontvars + nimplvars + 1) );
    331 SCIP_CALL( SCIPallocBufferArray(scip, &aggrdata->nbadvarsinrow, nrows) );
    332 SCIP_CALL( SCIPaggrRowCreate(scip, &aggrdata->aggrrow) );
    333 assert( aggrdata->aggrrow != NULL );
    334 BMSclearMemoryArray(aggrdata->nbadvarsinrow, nrows);
    335
    336 aggrdata->nbounddistvars = 0;
    337 aggrdata->aggrrows = NULL;
    338 aggrdata->aggrrowscoef = NULL;
    339 aggrdata->aggrrowssize = 0;
    340 aggrdata->naggrrows = 0;
    341
    342 firstcontvar = nvars - ncontvars;
    343
    344 for( i = nbinvars + nintvars; i < nvars; ++i )
    345 {
    346 SCIP_Real bounddist;
    347 SCIP_Real primsol;
    348 SCIP_Real distlb;
    349 SCIP_Real distub;
    350 SCIP_Real bestlb;
    351 SCIP_Real bestub;
    352 SCIP_Real bestvlb;
    353 SCIP_Real bestvub;
    354 int bestvlbidx;
    355 int bestvubidx;
    356
    357 /* compute the bound distance of the variable */
    358 if( allowlocal )
    359 {
    360 bestlb = SCIPvarGetLbLocal(vars[i]);
    361 bestub = SCIPvarGetUbLocal(vars[i]);
    362 }
    363 else
    364 {
    365 bestlb = SCIPvarGetLbGlobal(vars[i]);
    366 bestub = SCIPvarGetUbGlobal(vars[i]);
    367 }
    368
    369 SCIP_CALL( SCIPgetVarClosestVlb(scip, vars[i], sol, &bestvlb, &bestvlbidx) );
    370 SCIP_CALL( SCIPgetVarClosestVub(scip, vars[i], sol, &bestvub, &bestvubidx) );
    371 if( bestvlbidx >= 0 )
    372 bestlb = MAX(bestlb, bestvlb);
    373 if( bestvubidx >= 0 )
    374 bestub = MIN(bestub, bestvub);
    375
    376 primsol = SCIPgetSolVal(scip, sol, vars[i]);
    377 distlb = primsol - bestlb;
    378 distub = bestub - primsol;
    379
    380 bounddist = MIN(distlb, distub);
    381 bounddist = MAX(bounddist, 0.0);
    382
    383 /* prefer continuous variables over implicit integers to be aggregated out */
    384 if( i < firstcontvar )
    385 bounddist *= 0.1;
    386
    387 /* when variable is not at its bound, we want to project it out, so add it to the aggregation data */
    388 if( !SCIPisZero(scip, bounddist) )
    389 {
    390 int k = aggrdata->nbounddistvars++;
    391
    392 aggrdata->bounddist[k] = bounddist;
    393 aggrdata->bounddistinds[k] = i;
    394 aggrdata->aggrrowsstart[k] = aggrdata->naggrrows;
    395
    396 /* the current variable is a bad variable (continuous, not at its bound): increase the number of bad variable
    397 * count on each row this variables appears in; also each of these rows can be used to project the variable out
    398 * so store them.
    399 */
    400 if( SCIPvarIsInLP(vars[i]) )
    401 {
    402 SCIP_COL* col = SCIPvarGetCol(vars[i]);
    403 SCIP_ROW** colrows = SCIPcolGetRows(col);
    404 SCIP_Real* colrowvals = SCIPcolGetVals(col);
    405 int ncolnonzeros = SCIPcolGetNLPNonz(col);
    406 int aggrrowsminsize = aggrdata->naggrrows + ncolnonzeros;
    407
    408 if( aggrrowsminsize > aggrdata->aggrrowssize )
    409 {
    410 SCIP_CALL( SCIPreallocBufferArray(scip, &aggrdata->aggrrows, aggrrowsminsize) );
    411 SCIP_CALL( SCIPreallocBufferArray(scip, &aggrdata->aggrrowscoef, aggrrowsminsize) );
    412 aggrdata->aggrrowssize = aggrrowsminsize;
    413 }
    414 assert(aggrdata->aggrrows != NULL || aggrdata->aggrrowssize == 0);
    415 assert(aggrdata->aggrrowscoef != NULL || aggrdata->aggrrowssize == 0);
    416 assert(aggrdata->aggrrowssize > 0 || ncolnonzeros == 0);
    417
    418 for( k = 0; k < ncolnonzeros; ++k )
    419 {
    420 /* ignore modifiable rows and local rows if those are not permitted */
    421 if( SCIProwIsModifiable(colrows[k]) || (!allowlocal && SCIProwIsLocal(colrows[k])) )
    422 continue;
    423
    424 ++aggrdata->nbadvarsinrow[SCIProwGetLPPos(colrows[k])];
    425 assert(aggrdata->aggrrows != NULL); /* for lint */
    426 assert(aggrdata->aggrrowscoef != NULL);
    427 /* coverity[var_deref_op] */
    428 aggrdata->aggrrows[aggrdata->naggrrows] = colrows[k];
    429 aggrdata->aggrrowscoef[aggrdata->naggrrows] = colrowvals[k];
    430 ++aggrdata->naggrrows;
    431 }
    432 }
    433 }
    434 }
    435
    436 /* add sentinel entry at the end */
    437 aggrdata->aggrrowsstart[aggrdata->nbounddistvars] = aggrdata->naggrrows;
    438
    439 /* for each continous variable that is not at its bounds check if there is a
    440 * row where it is the only such variable ("good" rows). In the array with the rows that are
    441 * suitable for substituting this variable move the good rows to the beginning
    442 * and store the number of good rows for each of the variables.
    443 * If a variable has at least one good row, then it is a "better" variable and we make
    444 * the value of the bounddistance for this variable negative, to mark it.
    445 * Note that better variables are continous variables that are not at their bounds
    446 * and can be projected out without introducing bad variables (by using a good row).
    447 */
    448 {
    449 int beg;
    450
    451 beg = aggrdata->aggrrowsstart[0];
    452 for( i = 0; i < aggrdata->nbounddistvars; ++i )
    453 {
    454 int k;
    455 int ngoodrows;
    456 int end;
    457
    458 end = aggrdata->aggrrowsstart[i + 1];
    459 ngoodrows = 0;
    460 for( k = beg; k < end; ++k )
    461 {
    462 /* coverity[var_deref_op] */
    463 int lppos = SCIProwGetLPPos(aggrdata->aggrrows[k]);
    464
    465 if( aggrdata->nbadvarsinrow[lppos] == 1 &&
    466 SCIPisEQ(scip, SCIProwGetLhs(aggrdata->aggrrows[k]), SCIProwGetRhs(aggrdata->aggrrows[k])) )
    467 {
    468 int nextgoodrowpos = beg + ngoodrows;
    469 if( k > nextgoodrowpos )
    470 {
    471 SCIPswapPointers((void**) (&aggrdata->aggrrows[k]), (void**) (&aggrdata->aggrrows[nextgoodrowpos]));
    472 SCIPswapReals(&aggrdata->aggrrowscoef[k], &aggrdata->aggrrowscoef[nextgoodrowpos]);
    473 }
    474 ++ngoodrows;
    475 }
    476 }
    477 if( ngoodrows > 0 )
    478 {
    479 aggrdata->bounddist[i] = -aggrdata->bounddist[i];
    480 }
    481 aggrdata->ngoodaggrrows[i] = ngoodrows;
    482 beg = end;
    483 }
    484 }
    485
    486 return SCIP_OKAY;
    487}
    488
    489/** free resources held in aggregation data */
    490static
    492 SCIP* scip, /**< SCIP datastructure */
    493 AGGREGATIONDATA* aggrdata /**< pointer to ggregation data */
    494 )
    495{
    496 SCIPaggrRowFree(scip, &aggrdata->aggrrow);
    504}
    505
    506/** retrieves the candidate rows for canceling out the given variable, also returns the number of "good" rows which are the
    507 * rows stored at the first ngoodrows positions. A row is good if its continuous variables are all at their bounds, except
    508 * maybe the given continuous variable (in probvaridx)
    509 */
    510static
    512 AGGREGATIONDATA* aggrdata, /**< pointer to ggregation data */
    513 int probvaridx, /**< problem index of variables to retrieve candidates for */
    514 SCIP_ROW*** rows, /**< pointer to store array to candidate rows */
    515 SCIP_Real** rowvarcoefs, /**< pointer to store array of coefficients of given variable in the corresponding rows */
    516 int* nrows, /**< pointer to return number of rows in returned arrays */
    517 int* ngoodrows /**< pointer to return number of "good" rows in the returned arrays */
    518 )
    519{
    520 int aggrdataidx;
    521
    522 if( !SCIPsortedvecFindInt(aggrdata->bounddistinds, probvaridx, aggrdata->nbounddistvars, &aggrdataidx) )
    523 return FALSE;
    524
    525 *rows = aggrdata->aggrrows + aggrdata->aggrrowsstart[aggrdataidx];
    526 *nrows = aggrdata->aggrrowsstart[aggrdataidx + 1] - aggrdata->aggrrowsstart[aggrdataidx];
    527 *rowvarcoefs = aggrdata->aggrrowscoef + aggrdata->aggrrowsstart[aggrdataidx];
    528 *ngoodrows = aggrdata->ngoodaggrrows[aggrdataidx];
    529
    530 return TRUE;
    531}
    532
    533/** find the bound distance value in the aggregation data struct for the given variable problem index */
    534static
    536 AGGREGATIONDATA* aggrdata, /**< SCIP datastructure */
    537 int probvaridx /**< problem index of variables to retrieve candidates for */
    538 )
    539{
    540 int aggrdataidx;
    541
    542 if( !SCIPsortedvecFindInt(aggrdata->bounddistinds, probvaridx, aggrdata->nbounddistvars, &aggrdataidx) )
    543 return 0.0;
    544
    545 return aggrdata->bounddist[aggrdataidx];
    546}
    547
    548/** Aggregates the next row suitable for cancelling out an active continuous variable.
    549 *
    550 * Equality rows that contain no other active continuous variables are preffered and apart from that
    551 * the scores for the rows are used to determine which row is aggregated next
    552 */
    553static
    555 SCIP* scip, /**< SCIP data structure */
    556 SCIP_SEPADATA* sepadata, /**< separator data */
    557 SCIP_Real* rowlhsscores, /**< aggregation scores for left hand sides of row */
    558 SCIP_Real* rowrhsscores, /**< aggregation scores for right hand sides of row */
    559 AGGREGATIONDATA* aggrdata, /**< aggregation data */
    560 SCIP_AGGRROW* aggrrow, /**< current aggregation row */
    561 int* naggrs, /**< pointer to increase counter if real aggregation took place */
    562 SCIP_Bool* success /**< pointer to return whether another row was added to the aggregation row */
    563 )
    564{
    565 int i;
    566 int firstcontvar;
    567 int* badvarinds;
    568 SCIP_Real* badvarbddist;
    569 int nbadvars;
    570 SCIP_Real minbddist;
    571 SCIP_ROW* bestrow;
    572 SCIP_Real bestrowscore;
    573 SCIP_Real aggrfac;
    574 int bestrowside;
    575 int ncontvars;
    576 int nnz = SCIPaggrRowGetNNz(aggrrow);
    577 int* inds = SCIPaggrRowGetInds(aggrrow);
    578
    579 assert( success != NULL );
    580 *success = FALSE;
    581
    582 firstcontvar = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
    584 assert( firstcontvar + ncontvars == SCIPgetNVars(scip) );
    585
    586 SCIP_CALL( SCIPallocBufferArray(scip, &badvarinds, MIN(ncontvars, nnz)) );
    587 SCIP_CALL( SCIPallocBufferArray(scip, &badvarbddist, MIN(ncontvars, nnz)) );
    588
    589 nbadvars = 0;
    590
    591 for( i = 0; i < nnz; ++i )
    592 {
    593 SCIP_Real bounddist;
    594
    595 /* only consider continuous variables */
    596 if( inds[i] < firstcontvar )
    597 continue;
    598
    599 bounddist = aggrdataGetBoundDist(aggrdata, inds[i]);
    600
    601 if( bounddist == 0.0 )
    602 continue;
    603
    604 badvarinds[nbadvars] = inds[i];
    605 badvarbddist[nbadvars] = bounddist;
    606 ++nbadvars;
    607 }
    608
    609 if( nbadvars == 0 )
    610 goto TERMINATE;
    611
    612 SCIPsortDownRealInt(badvarbddist, badvarinds, nbadvars);
    613
    614 aggrfac = 0.0;
    615 bestrowscore = 0.0;
    616 bestrowside = 0;
    617 minbddist = 0.0;
    618 bestrow = NULL;
    619
    620 /* because the "good" bad variables have a negative bound distance, they are at the end */
    621 for( i = nbadvars - 1; i >= 0; --i )
    622 {
    623 int probvaridx;
    624 SCIP_ROW** candrows;
    625 SCIP_Real* candrowcoefs;
    626 int nrows;
    627 int ngoodrows;
    628 int k;
    629
    630 /* if the bound distance is not negative, there are no more good variables so stop */
    631 if( badvarbddist[i] > 0.0 )
    632 break;
    633
    634 /* if no best row was found yet, this variable has the currently best bound distance */
    635 if( aggrfac == 0.0 )
    636 minbddist = -badvarbddist[i] * (1.0 - sepadata->aggrtol);
    637
    638 /* if the bound distance of the current variable is smaller than the minimum bound distance stop looping */
    639 if( -badvarbddist[i] < minbddist )
    640 break;
    641
    642 probvaridx = badvarinds[i];
    643
    644 if( !getRowAggregationCandidates(aggrdata, probvaridx, &candrows, &candrowcoefs, &nrows, &ngoodrows) )
    645 return SCIP_ERROR;
    646
    647 assert(ngoodrows > 0); /* bounddistance was negative for this variable, so it should have good rows */
    648 assert(ngoodrows <= nrows);
    649
    650 for( k = 0; k < ngoodrows; ++k )
    651 {
    652 SCIP_Real rowaggrfac;
    653 SCIP_Real rowscore;
    654 int lppos;
    655
    656 /* do not add rows twice */
    657 if( SCIPaggrRowHasRowBeenAdded(aggrrow, candrows[k]) )
    658 continue;
    659
    660 rowaggrfac = - SCIPaggrRowGetProbvarValue(aggrrow, probvaridx) / candrowcoefs[k];
    661
    662 /* if factor is too extreme skip this row */
    663 if( SCIPisFeasZero(scip, rowaggrfac) || REALABS(rowaggrfac) > sepadata->maxrowfac )
    664 continue;
    665
    666 lppos = SCIProwGetLPPos(candrows[k]);
    667
    668 /* row could be used and good rows are equalities, so ignore sidetype */
    669 rowscore = MAX(rowlhsscores[lppos], rowrhsscores[lppos]);
    670
    671 /* if this rows score is better than the currently best score, remember it */
    672 if( aggrfac == 0.0 || rowscore > bestrowscore )
    673 {
    674 bestrow = candrows[k];
    675 aggrfac = rowaggrfac;
    676 bestrowscore = rowscore;
    677 bestrowside = 0;
    678 }
    679 }
    680 }
    681
    682 /* found a row among the good rows, so aggregate it and stop */
    683 if( aggrfac != 0.0 )
    684 {
    685 ++(*naggrs);
    686 SCIP_CALL( SCIPaggrRowAddRow(scip, aggrrow, bestrow, aggrfac, bestrowside) );
    687 SCIPaggrRowRemoveZeros(scip, aggrrow, FALSE, success);
    688 goto TERMINATE;
    689 }
    690
    691 for( i = 0; i < nbadvars; ++i )
    692 {
    693 int probvaridx;
    694 SCIP_ROW** candrows;
    695 SCIP_Real* candrowcoefs;
    696 int nrows;
    697 int ngoodrows;
    698 int k;
    699
    700 /* if the bound distance is negative, there are no more variables to be tested, so stop */
    701 if( badvarbddist[i] < 0.0 )
    702 break;
    703
    704 /* if no best row was found yet, this variable has the currently best bound distance */
    705 if( aggrfac == 0.0 )
    706 minbddist = badvarbddist[i] * (1.0 - sepadata->aggrtol);
    707
    708 /* if the bound distance of the current variable is smaller than the minimum bound distance stop looping */
    709 if( badvarbddist[i] < minbddist )
    710 break;
    711
    712 probvaridx = badvarinds[i];
    713
    714 if( !getRowAggregationCandidates(aggrdata, probvaridx, &candrows, &candrowcoefs, &nrows, &ngoodrows) )
    715 return SCIP_ERROR;
    716
    717 /* bounddistance was positive for this variable, so it should not have good rows */
    718 assert(ngoodrows == 0);
    719
    720 for( k = 0; k < nrows; ++k )
    721 {
    722 SCIP_Real rowaggrfac;
    723 SCIP_Real rowscore;
    724 int rowside;
    725 int lppos;
    726
    727 /* do not add rows twice */
    728 if( SCIPaggrRowHasRowBeenAdded(aggrrow, candrows[k]) )
    729 continue;
    730
    731 rowaggrfac = - SCIPaggrRowGetProbvarValue(aggrrow, probvaridx) / candrowcoefs[k];
    732
    733 /* if factor is too extreme skip this row */
    734 if( SCIPisFeasZero(scip, rowaggrfac) || REALABS(rowaggrfac) > sepadata->maxrowfac )
    735 continue;
    736
    737 /* row could be used, decide which side */
    738 lppos = SCIProwGetLPPos(candrows[k]);
    739
    740 /* either both or none of the rowscores are 0.0 so use the one which gives a positive slack */
    741 if( (rowaggrfac < 0.0 && !SCIPisInfinity(scip, -SCIProwGetLhs(candrows[k]))) || SCIPisInfinity(scip, SCIProwGetRhs(candrows[k])) )
    742 {
    743 rowscore = rowlhsscores[lppos];
    744 rowside = -1;
    745 }
    746 else
    747 {
    748 rowscore = rowrhsscores[lppos];
    749 rowside = 1;
    750 }
    751
    752 /* if this rows score is better than the currently best score, remember it */
    753 if( aggrfac == 0.0 || SCIPisGT(scip, rowscore, bestrowscore) ||
    754 (SCIPisEQ(scip, rowscore, bestrowscore) && aggrdata->nbadvarsinrow[lppos] < aggrdata->nbadvarsinrow[SCIProwGetLPPos(bestrow)]) )
    755 {
    756 bestrow = candrows[k];
    757 aggrfac = rowaggrfac;
    758 bestrowscore = rowscore;
    759 bestrowside = rowside;
    760 }
    761 }
    762 }
    763
    764 /* found a row so aggregate it */
    765 if( aggrfac != 0.0 )
    766 {
    767 ++(*naggrs);
    768 SCIP_CALL( SCIPaggrRowAddRow(scip, aggrrow, bestrow, aggrfac, bestrowside) );
    769 SCIPaggrRowRemoveZeros(scip, aggrrow, FALSE, success);
    770 }
    771
    772TERMINATE:
    773 SCIPfreeBufferArray(scip, &badvarbddist);
    774 SCIPfreeBufferArray(scip, &badvarinds);
    775
    776 return SCIP_OKAY;
    777}
    778
    779/** aggregates different single mixed integer constraints by taking linear combinations of the rows of the LP */
    780static
    782 SCIP* scip, /**< SCIP data structure */
    783 AGGREGATIONDATA* aggrdata, /**< pointer to aggregation data */
    784 SCIP_SEPA* sepa, /**< separator */
    785 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    786 SCIP_Bool allowlocal, /**< should local cuts be allowed */
    787 SCIP_Real* rowlhsscores, /**< aggregation scores for left hand sides of row */
    788 SCIP_Real* rowrhsscores, /**< aggregation scores for right hand sides of row */
    789 int startrow, /**< index of row to start aggregation; -1 for using the objective cutoff constraint */
    790 int maxaggrs, /**< maximal number of aggregations */
    791 SCIP_Bool* wastried, /**< pointer to store whether the given startrow was actually tried */
    792 SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
    793 SCIP_CUTGENRESULT* cutresult, /**< result structure with pre-allocated cutcoefs and cutinds arrays */
    794 SCIP_Bool negate, /**< should the start row be multiplied by -1 */
    795 int* ncuts /**< pointer to count the number of generated cuts */
    796 )
    797{
    798 SCIP_SEPADATA* sepadata;
    799 SCIP_ROW** rows;
    800
    801 SCIP_Real startweight;
    802 SCIP_Real startrowact;
    803 int maxaggrnonzs;
    804 int naggrs;
    805 int nrows;
    806 int maxtestdelta;
    807
    808 assert(scip != NULL);
    809 assert(aggrdata != NULL);
    810 assert(aggrdata->aggrrow != NULL);
    811 assert(sepa != NULL);
    812 assert(rowlhsscores != NULL);
    813 assert(rowrhsscores != NULL);
    814 assert(wastried != NULL);
    815 assert(cutoff != NULL);
    816 assert(ncuts != NULL);
    817
    818 sepadata = SCIPsepaGetData(sepa);
    819 assert(sepadata != NULL);
    820
    821 *cutoff = FALSE;
    822 *wastried = FALSE;
    823
    824 SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
    825 assert(nrows == 0 || rows != NULL);
    826
    827 maxtestdelta = sepadata->maxtestdelta == -1 ? INT_MAX : sepadata->maxtestdelta;
    828
    829 /* calculate maximal number of non-zeros in aggregated row */
    830 maxaggrnonzs = (int)(sepadata->maxaggdensity * SCIPgetNLPCols(scip)) + sepadata->densityoffset;
    831
    832 /* add start row to the initially empty aggregation row (aggrrow) */
    833 if( startrow < 0 )
    834 {
    836
    837 /* if the objective is integral we round the right hand side of the cutoff constraint.
    838 * Therefore the constraint may not be valid for the problem but it is valid for the set
    839 * of all improving solutions. We refrain from adding an epsilon cutoff for the case
    840 * of a non-integral objective function to avoid cutting of any improving solution even
    841 * if the improvement is below some epsilon value.
    842 */
    844 rhs = floor(rhs);
    845
    846 SCIP_CALL( SCIPaggrRowAddObjectiveFunction(scip, aggrdata->aggrrow, rhs, 1.0) );
    847
    848 if( SCIPaggrRowGetNNz(aggrdata->aggrrow) == 0 )
    849 {
    850 SCIPaggrRowClear(aggrdata->aggrrow);
    851 return SCIP_OKAY;
    852 }
    853 }
    854 else
    855 {
    856 assert(0 <= startrow && startrow < nrows);
    857
    858 SCIPdebugMsg(scip, "start c-MIR aggregation with row <%s> (%d/%d)\n", SCIProwGetName(rows[startrow]), startrow, nrows);
    859
    860 startrowact = SCIPgetRowSolActivity(scip, rows[startrow], sol);
    861
    862 if( startrowact <= 0.5 * SCIProwGetLhs(rows[startrow]) + 0.5 * SCIProwGetRhs(rows[startrow]) )
    863 startweight = -1.0;
    864 else
    865 startweight = 1.0;
    866
    867 SCIP_CALL( SCIPaggrRowAddRow(scip, aggrdata->aggrrow, rows[startrow], negate ? -startweight : startweight, 0) ); /*lint !e644*/
    868 }
    869
    870 /* try to generate cut from the current aggregated row; add cut if found, otherwise add another row to aggrrow
    871 * in order to get rid of a continuous variable
    872 */
    873 naggrs = 0;
    874 while( naggrs <= maxaggrs )
    875 {
    876 SCIP_CUTGENPARAMS params;
    877 SCIP_CUTGENMETHOD methods;
    878 SCIP_ROW* cut = NULL;
    879 SCIP_Bool aggrsuccess;
    880
    881 *wastried = TRUE;
    882
    883 /* initialize cut generation parameters */
    884 SCIPinitCutGenParams(&params);
    885 params.allowlocal = allowlocal;
    886 params.maxtestdelta = maxtestdelta;
    887
    888 /* set enabled methods */
    889 methods = SCIP_CUTGENMETHOD_NONE;
    890 if( sepadata->sepflowcover )
    892 if( sepadata->sepknapsackcover )
    894 if( sepadata->sepcmir )
    895 methods |= SCIP_CUTGENMETHOD_CMIR;
    896
    897 /* try all enabled cut generation methods and get the best cut */
    898 SCIP_CALL( SCIPcalcBestCut(scip, sol, aggrdata->aggrrow, methods, &params, cutresult) );
    899
    900 if( cutresult->success )
    901 {
    902 SCIP_SEPA* cutsepa;
    903 const char* cutname;
    904
    905 switch( cutresult->winningmethod )
    906 {
    908 cutsepa = sepadata->flowcover;
    909 cutname = startrow < 0 ? "objflowcover" : "flowcover";
    910 break;
    912 cutsepa = sepadata->knapsackcover;
    913 cutname = startrow < 0 ? "objlci" : "lci";
    914 break;
    916 cutsepa = sepadata->cmir;
    917 cutname = startrow < 0 ? "objcmir" : "cmir";
    918 break;
    919 default:
    920 SCIPABORT();
    921 cutsepa = NULL;
    922 cutname = NULL;
    923 }
    924
    925 SCIP_CALL( addCut(scip, sol, cutsepa, FALSE, cutresult->cutcoefs, cutresult->cutinds, cutresult->cutnnz,
    926 cutresult->cutrhs, cutresult->cutefficacy, cutresult->cutislocal, sepadata->dynamiccuts,
    927 cutresult->cutrank, cutname, cutoff, ncuts, &cut) );
    928 }
    929
    930 if ( *cutoff )
    931 {
    932 if( cut != NULL )
    933 {
    934 SCIP_CALL( SCIPreleaseRow(scip, &cut) );
    935 }
    936 break;
    937 }
    938
    939 /* if the cut was successfully added, decrease the score of the rows used in the aggregation and clean the aggregation
    940 * row (and call this function again with a different start row for aggregation)
    941 */
    942 if( cut != NULL )
    943 {
    944 int* rowinds;
    945 int i;
    946
    947 rowinds = SCIPaggrRowGetRowInds(aggrdata->aggrrow);
    948 nrows = SCIPaggrRowGetNRows(aggrdata->aggrrow);
    949
    950 /* decrease row score of used rows slightly */
    951 for( i = 0; i < nrows; ++i )
    952 {
    953 SCIP_Real fac = 1.0 - 0.999 * SCIProwGetParallelism(rows[rowinds[i]], cut, 'e');
    954
    955 rowlhsscores[rowinds[i]] *= fac;
    956 rowrhsscores[rowinds[i]] *= fac;
    957 }
    958
    959 SCIP_CALL( SCIPreleaseRow(scip, &cut) );
    960
    961 SCIPdebugMsg(scip, " -> abort aggregation: cut found\n");
    962 break;
    963 }
    964
    965 /* Step 2:
    966 * aggregate an additional row in order to remove a continuous variable
    967 */
    968
    969 /* abort, if we reached the maximal number of aggregations */
    970 if( naggrs == maxaggrs )
    971 {
    972 SCIPdebugMsg(scip, " -> abort aggregation: maximal number of aggregations reached\n");
    973 break;
    974 }
    975
    976 SCIP_CALL( aggregateNextRow(scip, sepadata, rowlhsscores, rowrhsscores, aggrdata, aggrdata->aggrrow,
    977 &naggrs, &aggrsuccess) );
    978
    979 /* no suitable aggregation was found or number of non-zeros is now too large so abort */
    980 if( ! aggrsuccess || SCIPaggrRowGetNNz(aggrdata->aggrrow) > maxaggrnonzs || SCIPaggrRowGetNNz(aggrdata->aggrrow) == 0 )
    981 {
    982 break;
    983 }
    984
    985 SCIPdebugMsg(scip, " -> current aggregation has %d/%d nonzeros and consists of %d/%d rows\n",
    986 SCIPaggrRowGetNNz(aggrdata->aggrrow), maxaggrnonzs, naggrs, maxaggrs);
    987 }
    988
    989 SCIPaggrRowClear(aggrdata->aggrrow);
    990
    991 return SCIP_OKAY;
    992}
    993
    994/** gives an estimate of how much the activity of this row is affected by fractionality in the current solution */
    995static
    997 SCIP_ROW* row, /**< the LP row */
    998 SCIP_Real* fractionalities /**< array of fractionalities for each variable */
    999 )
    1000{
    1001 int nlpnonz;
    1002 int i;
    1003 SCIP_COL** cols;
    1004 SCIP_Real* vals;
    1005 SCIP_Real fracsum = 0.0;
    1006
    1007 cols = SCIProwGetCols(row);
    1008 vals = SCIProwGetVals(row);
    1009 nlpnonz = SCIProwGetNLPNonz(row);
    1010
    1011 for( i = 0; i < nlpnonz; ++i )
    1012 {
    1013 SCIP_VAR* var = SCIPcolGetVar(cols[i]);
    1014 fracsum += REALABS(vals[i] * fractionalities[SCIPvarGetProbindex(var)]);
    1015 }
    1016
    1017 return fracsum;
    1018}
    1019
    1020/** searches for and adds c-MIR cuts that separate the given primal solution */
    1021static
    1023 SCIP* scip, /**< SCIP data structure */
    1024 SCIP_SEPA* sepa, /**< the c-MIR separator */
    1025 SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
    1026 SCIP_Bool allowlocal, /**< should local cuts be allowed */
    1027 int depth, /**< current depth */
    1028 SCIP_RESULT* result /**< pointer to store the result */
    1029 )
    1030{
    1031 AGGREGATIONDATA aggrdata;
    1032 SCIP_SEPADATA* sepadata;
    1033 SCIP_VAR** vars;
    1034 SCIP_Real* varsolvals;
    1035 SCIP_Real* bestcontlbs;
    1036 SCIP_Real* bestcontubs;
    1037 SCIP_Real* fractionalities;
    1038 SCIP_ROW** rows;
    1039 SCIP_Real* rowlhsscores;
    1040 SCIP_Real* rowrhsscores;
    1041 SCIP_Real* rowscores;
    1042 int* roworder;
    1043 SCIP_Real maxslack;
    1044 SCIP_Bool cutoff = FALSE;
    1045 SCIP_Bool wastried;
    1046 int nvars;
    1047 int nintvars;
    1048 int ncontvars;
    1049 int nrows;
    1050 int nnonzrows;
    1051 int ntries;
    1052 int nfails;
    1053 int ncalls;
    1054 int maxtries;
    1055 int maxfails;
    1056 int maxaggrs;
    1057 int maxsepacuts;
    1058 int ncuts;
    1059 int r;
    1060 int v;
    1061 int oldncuts;
    1062
    1063 SCIP_CUTGENRESULT* cutresult;
    1064
    1065 assert(result != NULL);
    1066 assert(*result == SCIP_DIDNOTRUN);
    1067
    1068 sepadata = SCIPsepaGetData(sepa);
    1069 assert(sepadata != NULL);
    1070
    1071 ncalls = SCIPsepaGetNCallsAtNode(sepa);
    1072
    1073 /* only call the cmir cut separator a given number of times at each node */
    1074 if( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot)
    1075 || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) )
    1076 return SCIP_OKAY;
    1077
    1078 /* check which cuts should be separated */
    1079 {
    1080 int cmirfreq;
    1081 int flowcoverfreq;
    1082 int knapsackcoverfreq;
    1083
    1084 cmirfreq = SCIPsepaGetFreq(sepadata->cmir);
    1085 flowcoverfreq = SCIPsepaGetFreq(sepadata->flowcover);
    1086 knapsackcoverfreq = SCIPsepaGetFreq(sepadata->knapsackcover);
    1087
    1088 sepadata->sepcmir = cmirfreq > 0 ? (depth % cmirfreq) == 0 : cmirfreq == depth;
    1089 sepadata->sepflowcover = flowcoverfreq > 0 ? (depth % flowcoverfreq) == 0 : flowcoverfreq == depth;
    1090 sepadata->sepknapsackcover = knapsackcoverfreq > 0 ? (depth % knapsackcoverfreq) == 0 : knapsackcoverfreq == depth;
    1091 }
    1092
    1093 if( ! sepadata->sepcmir && ! sepadata->sepflowcover && ! sepadata->sepknapsackcover )
    1094 return SCIP_OKAY;
    1095
    1096 /* get all rows and number of columns */
    1097 SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
    1098 assert(nrows == 0 || rows != NULL);
    1099
    1100 /* nothing to do, if LP is empty */
    1101 if( nrows == 0 )
    1102 return SCIP_OKAY;
    1103
    1104 /* check whether SCIP was stopped in the meantime */
    1105 if( SCIPisStopped(scip) )
    1106 return SCIP_OKAY;
    1107
    1108 /* get active problem variables */
    1109 vars = SCIPgetVars(scip);
    1110 nvars = SCIPgetNVars(scip);
    1111 ncontvars = SCIPgetNContVars(scip);
    1112#ifdef IMPLINTSARECONT
    1113 ncontvars += SCIPgetNContImplVars(scip); /* also aggregate out implicit integers */
    1114#endif
    1115 nintvars = nvars - ncontvars;
    1116 assert(nvars == 0 || vars != NULL);
    1117
    1118 /* nothing to do, if problem has no variables */
    1119 if( nvars == 0 )
    1120 return SCIP_OKAY;
    1121
    1122 SCIPdebugMsg(scip, "separating c-MIR cuts\n");
    1123
    1124 *result = SCIP_DIDNOTFIND;
    1125
    1126 /* get data structure */
    1127 SCIP_CALL( SCIPallocBufferArray(scip, &rowlhsscores, nrows) );
    1128 SCIP_CALL( SCIPallocBufferArray(scip, &rowrhsscores, nrows) );
    1129 SCIP_CALL( SCIPallocBufferArray(scip, &roworder, nrows) );
    1130 SCIP_CALL( SCIPallocBufferArray(scip, &varsolvals, nvars) );
    1131 SCIP_CALL( SCIPallocBufferArray(scip, &bestcontlbs, ncontvars) );
    1132 SCIP_CALL( SCIPallocBufferArray(scip, &bestcontubs, ncontvars) );
    1133 SCIP_CALL( SCIPallocBufferArray(scip, &fractionalities, nvars) );
    1134 SCIP_CALL( SCIPcreateCutGenResult(scip, &cutresult) );
    1135 SCIP_CALL( SCIPallocBufferArray(scip, &rowscores, nrows) );
    1136
    1137 /* get the solution values for all active variables */
    1138 SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, varsolvals) );
    1139
    1140 /* calculate the fractionality of the integer variables in the current solution */
    1141 for( v = 0; v < nintvars; ++v )
    1142 {
    1143 fractionalities[v] = SCIPfeasFrac(scip, varsolvals[v]);
    1144 fractionalities[v] = MIN(fractionalities[v], 1.0 - fractionalities[v]);
    1145 }
    1146
    1147 /* calculate the fractionality of the continuous variables in the current solution;
    1148 * The fractionality of a continuous variable x is defined to be a * f_y,
    1149 * if there is a variable bound x <= a * y + c where f_y is the fractionality of y
    1150 * and in the current solution the variable bound has no slack.
    1151 */
    1152 for( ; v < nvars; ++v )
    1153 {
    1154 SCIP_VAR** vlbvars;
    1155 SCIP_VAR** vubvars;
    1156 SCIP_Real* vlbcoefs;
    1157 SCIP_Real* vubcoefs;
    1158 SCIP_Real closestvlb;
    1159 SCIP_Real closestvub;
    1160 int closestvlbidx;
    1161 int closestvubidx;
    1162
    1163 SCIP_CALL( SCIPgetVarClosestVlb(scip, vars[v], sol, &closestvlb, &closestvlbidx) );
    1164 SCIP_CALL( SCIPgetVarClosestVub(scip, vars[v], sol, &closestvub, &closestvubidx) );
    1165
    1166 vlbvars = SCIPvarGetVlbVars(vars[v]);
    1167 vubvars = SCIPvarGetVubVars(vars[v]);
    1168 vlbcoefs = SCIPvarGetVlbCoefs(vars[v]);
    1169 vubcoefs = SCIPvarGetVubCoefs(vars[v]);
    1170
    1171 fractionalities[v] = 0.0;
    1172 if( closestvlbidx != -1 && SCIPisEQ(scip, varsolvals[v], closestvlb) )
    1173 {
    1174 int vlbvarprobidx = SCIPvarGetProbindex(vlbvars[closestvlbidx]);
    1175 SCIP_Real frac = SCIPfeasFrac(scip, varsolvals[vlbvarprobidx]);
    1176
    1177 if( frac < 0.0 )
    1178 frac = 0.0;
    1179 assert(frac >= 0.0 && frac < 1.0);
    1180 frac = MIN(frac, 1.0 - frac) * vlbcoefs[closestvlbidx];
    1181 fractionalities[v] += frac;
    1182 }
    1183
    1184 if( closestvubidx != -1 && SCIPisEQ(scip, varsolvals[v], closestvub) )
    1185 {
    1186 int vubvarprobidx = SCIPvarGetProbindex(vubvars[closestvubidx]);
    1187 SCIP_Real frac = SCIPfeasFrac(scip, varsolvals[vubvarprobidx]);
    1188
    1189 if( frac < 0.0 )
    1190 frac = 0.0;
    1191 assert(frac >= 0.0 && frac < 1.0);
    1192 frac = MIN(frac, 1.0 - frac) * vubcoefs[closestvubidx];
    1193 fractionalities[v] += frac;
    1194 }
    1195 }
    1196
    1197 /* get the maximal number of cuts allowed in a separation round */
    1198 if( depth == 0 )
    1199 {
    1200 maxtries = sepadata->maxtriesroot;
    1201 maxfails = sepadata->maxfailsroot;
    1202 maxaggrs = sepadata->maxaggrsroot;
    1203 maxsepacuts = sepadata->maxsepacutsroot;
    1204 maxslack = sepadata->maxslackroot;
    1205 }
    1206 else
    1207 {
    1208 maxtries = sepadata->maxtries;
    1209 maxfails = sepadata->maxfails;
    1210 maxaggrs = sepadata->maxaggrs;
    1211 maxsepacuts = sepadata->maxsepacuts;
    1212 maxslack = sepadata->maxslack;
    1213 }
    1214
    1215 /* calculate aggregation scores for both sides of all rows, and sort rows by decreasing maximal score
    1216 * TODO: document score definition */
    1217
    1218 /* count the number of non-zero rows and zero rows. these values are used for the sorting of the rowscores.
    1219 * only the non-zero rows need to be sorted. */
    1220 nnonzrows = 0;
    1221 for( r = 0; r < nrows; r++ )
    1222 {
    1223 int nnonz;
    1224
    1225 assert(SCIProwGetLPPos(rows[r]) == r);
    1226
    1227 nnonz = SCIProwGetNLPNonz(rows[r]);
    1228 if( nnonz == 0 || SCIProwIsModifiable(rows[r]) || (!allowlocal && SCIProwIsLocal(rows[r])) )
    1229 {
    1230 /* ignore empty rows, modifiable rows, and local rows if they are not allowed */
    1231 rowlhsscores[r] = 0.0;
    1232 rowrhsscores[r] = 0.0;
    1233 }
    1234 else
    1235 {
    1236 SCIP_Real activity;
    1237 SCIP_Real lhs;
    1238 SCIP_Real rhs;
    1239 SCIP_Real dualsol;
    1240 SCIP_Real dualscore;
    1241 SCIP_Real rowdensity;
    1242 SCIP_Real rownorm;
    1243 SCIP_Real slack;
    1244 SCIP_Real fracact;
    1245 SCIP_Real fracscore;
    1246 SCIP_Real objnorm;
    1247
    1248 objnorm = SCIPgetObjNorm(scip);
    1249 objnorm = MAX(objnorm, 1.0);
    1250
    1251 fracact = getRowFracActivity(rows[r], fractionalities);
    1252 dualsol = (sol == NULL ? SCIProwGetDualsol(rows[r]) : 1.0);
    1253 activity = SCIPgetRowSolActivity(scip, rows[r], sol);
    1254 lhs = SCIProwGetLhs(rows[r]);
    1255 rhs = SCIProwGetRhs(rows[r]);
    1256 rownorm = SCIProwGetNorm(rows[r]);
    1257 rownorm = MAX(rownorm, 0.1);
    1258 rowdensity = (SCIP_Real)(nnonz - sepadata->densityoffset)/(SCIP_Real)nvars;
    1259 assert(SCIPisPositive(scip, rownorm));
    1260 fracscore = fracact / rownorm;
    1261
    1262 slack = (activity - lhs)/rownorm;
    1263 dualscore = MAX(fracscore * dualsol/objnorm, 0.0001);
    1264 if( !SCIPisInfinity(scip, -lhs) && SCIPisLE(scip, slack, maxslack)
    1265 && rowdensity <= sepadata->maxrowdensity
    1266 && rowdensity <= sepadata->maxaggdensity ) /*lint !e774*/
    1267 {
    1268 rowlhsscores[r] = dualscore + sepadata->densityscore * (1.0-rowdensity) + sepadata->slackscore * MAX(1.0 - slack, 0.0);
    1269 assert(rowlhsscores[r] > 0.0);
    1270 }
    1271 else
    1272 rowlhsscores[r] = 0.0;
    1273
    1274 slack = (rhs - activity)/rownorm;
    1275 dualscore = MAX(-fracscore * dualsol/objnorm, 0.0001);
    1276 if( !SCIPisInfinity(scip, rhs) && SCIPisLE(scip, slack, maxslack)
    1277 && rowdensity <= sepadata->maxrowdensity
    1278 && rowdensity <= sepadata->maxaggdensity ) /*lint !e774*/
    1279 {
    1280 rowrhsscores[r] = dualscore + sepadata->densityscore * (1.0-rowdensity) + sepadata->slackscore * MAX(1.0 - slack, 0.0);
    1281 assert(rowrhsscores[r] > 0.0);
    1282 }
    1283 else
    1284 rowrhsscores[r] = 0.0;
    1285
    1286 /* for the row order only use the fractionality score since it best indicates how likely it is to find a cut */
    1287 if( fracscore != 0.0 )
    1288 {
    1289 roworder[nnonzrows] = r;
    1290 rowscores[nnonzrows] = fracscore;
    1291 ++nnonzrows;
    1292 }
    1293 }
    1294
    1295 SCIPdebugMsg(scip, " -> row %d <%s>: lhsscore=%g rhsscore=%g\n", r, SCIProwGetName(rows[r]),
    1296 rowlhsscores[r], rowrhsscores[r]);
    1297 }
    1298 assert(nnonzrows <= nrows);
    1299
    1300 SCIPsortDownRealInt(rowscores, roworder, nnonzrows);
    1301 SCIPfreeBufferArray(scip, &rowscores);
    1302
    1303 /* calculate the data required for performing the row aggregation */
    1304 SCIP_CALL( setupAggregationData(scip, sol, allowlocal, &aggrdata) );
    1305
    1306 ncuts = 0;
    1307 if( maxtries < 0 )
    1308 maxtries = INT_MAX;
    1309 if( maxfails < 0 )
    1310 maxfails = INT_MAX;
    1311 else if( depth == 0 && 2 * SCIPgetNSepaRounds(scip) < maxfails )
    1312 maxfails += maxfails - 2 * SCIPgetNSepaRounds(scip); /* allow up to double as many fails in early separounds of root node */
    1313
    1314 /* start aggregation heuristic for each row in the LP and generate resulting cuts */
    1315 ntries = 0;
    1316 nfails = 0;
    1317
    1319 {
    1320 /* try separating the objective function with the cutoff bound */
    1321 SCIP_CALL( aggregation(scip, &aggrdata, sepa, sol, allowlocal, rowlhsscores, rowrhsscores,
    1322 -1, 2 * maxaggrs, &wastried, &cutoff, cutresult, FALSE, &ncuts) );
    1323
    1324 if( cutoff )
    1325 goto TERMINATE;
    1326 }
    1327
    1328 for( r = 0; r < nnonzrows && ntries < maxtries && ncuts < maxsepacuts && !SCIPisStopped(scip); r++ )
    1329 {
    1330 oldncuts = ncuts;
    1331 SCIP_CALL( aggregation(scip, &aggrdata, sepa, sol, allowlocal, rowlhsscores, rowrhsscores,
    1332 roworder[r], maxaggrs, &wastried, &cutoff, cutresult, FALSE, &ncuts) );
    1333
    1334 /* if trynegscaling is true we start the aggregation heuristic again for this row, but multiply it by -1 first.
    1335 * This is done by calling the aggregation function with the parameter negate equal to TRUE
    1336 */
    1337 if( sepadata->trynegscaling && !cutoff )
    1338 {
    1339 SCIP_CALL( aggregation(scip, &aggrdata, sepa, sol, allowlocal, rowlhsscores, rowrhsscores,
    1340 roworder[r], maxaggrs, &wastried, &cutoff, cutresult, TRUE, &ncuts) );
    1341 }
    1342
    1343 if ( cutoff )
    1344 break;
    1345
    1346 if( !wastried )
    1347 {
    1348 continue;
    1349 }
    1350 ntries++;
    1351
    1352 if( ncuts == oldncuts )
    1353 {
    1354 nfails++;
    1355 if( nfails >= maxfails )
    1356 {
    1357 break;
    1358 }
    1359 }
    1360 else
    1361 {
    1362 nfails = 0;
    1363 }
    1364 }
    1365 TERMINATE:
    1366 /* free data structure */
    1367 destroyAggregationData(scip, &aggrdata);
    1368 SCIPfreeCutGenResult(scip, &cutresult);
    1369 SCIPfreeBufferArray(scip, &fractionalities);
    1370 SCIPfreeBufferArray(scip, &bestcontubs);
    1371 SCIPfreeBufferArray(scip, &bestcontlbs);
    1372 SCIPfreeBufferArray(scip, &varsolvals);
    1373 SCIPfreeBufferArray(scip, &roworder);
    1374 SCIPfreeBufferArray(scip, &rowrhsscores);
    1375 SCIPfreeBufferArray(scip, &rowlhsscores);
    1376
    1377 if ( cutoff )
    1378 *result = SCIP_CUTOFF;
    1379 else if ( ncuts > 0 )
    1380 *result = SCIP_SEPARATED;
    1381
    1382 return SCIP_OKAY;
    1383}
    1384
    1385/*
    1386 * Callback methods of separator
    1387 */
    1388
    1389/** copy method for separator plugins (called when SCIP copies plugins) */
    1390static
    1391SCIP_DECL_SEPACOPY(sepaCopyAggregation)
    1392{ /*lint --e{715}*/
    1393 assert(scip != NULL);
    1394 assert(sepa != NULL);
    1395
    1397
    1398 /* call inclusion method of constraint handler */
    1400
    1401 return SCIP_OKAY;
    1402}
    1403
    1404/** destructor of separator to free user data (called when SCIP is exiting) */
    1405static
    1406SCIP_DECL_SEPAFREE(sepaFreeAggregation)
    1407{ /*lint --e{715}*/
    1408 SCIP_SEPADATA* sepadata;
    1409
    1410 /* free separator data */
    1411 sepadata = SCIPsepaGetData(sepa);
    1412 assert(sepadata != NULL);
    1413
    1414 SCIPfreeBlockMemory(scip, &sepadata);
    1415
    1416 SCIPsepaSetData(sepa, NULL);
    1417
    1418 return SCIP_OKAY;
    1419}
    1420
    1421/** LP solution separation method of separator */
    1422static
    1423SCIP_DECL_SEPAEXECLP(sepaExeclpAggregation)
    1424{ /*lint --e{715}*/
    1425 assert( result != NULL );
    1426
    1427 *result = SCIP_DIDNOTRUN;
    1428
    1429 /* only call separator, if we are not close to terminating */
    1430 if( SCIPisStopped(scip) )
    1431 return SCIP_OKAY;
    1432
    1433 /* only call separator, if an optimal LP solution is at hand */
    1435 return SCIP_OKAY;
    1436
    1437 /* only call separator, if there are fractional variables */
    1438 if( SCIPgetNLPBranchCands(scip) == 0 )
    1439 return SCIP_OKAY;
    1440
    1441 SCIP_CALL( separateCuts(scip, sepa, NULL, allowlocal, depth, result) );
    1442
    1443 return SCIP_OKAY;
    1444}
    1445
    1446/** arbitrary primal solution separation method of separator */
    1447static
    1448SCIP_DECL_SEPAEXECSOL(sepaExecsolAggregation)
    1449{ /*lint --e{715}*/
    1450 assert( result != NULL );
    1451
    1452 *result = SCIP_DIDNOTRUN;
    1453
    1454 SCIP_CALL( separateCuts(scip, sepa, sol, allowlocal, depth, result) );
    1455
    1456 return SCIP_OKAY;
    1457}
    1458
    1459/** LP solution separation method of dummy separator */
    1460static
    1461SCIP_DECL_SEPAEXECLP(sepaExeclpDummy)
    1462{ /*lint --e{715}*/
    1463 assert( result != NULL );
    1464
    1465 *result = SCIP_DIDNOTRUN;
    1466
    1467 return SCIP_OKAY;
    1468}
    1469
    1470/** arbitrary primal solution separation method of dummy separator */
    1471static
    1472SCIP_DECL_SEPAEXECSOL(sepaExecsolDummy)
    1473{ /*lint --e{715}*/
    1474 assert( result != NULL );
    1475
    1476 *result = SCIP_DIDNOTRUN;
    1477
    1478 return SCIP_OKAY;
    1479}
    1480
    1481/*
    1482 * separator specific interface methods
    1483 */
    1484
    1485/** creates the cmir separator and includes it in SCIP */
    1487 SCIP* scip /**< SCIP data structure */
    1488 )
    1489{
    1490 SCIP_SEPADATA* sepadata;
    1491 SCIP_SEPA* sepa;
    1492
    1493 /* create cmir separator data */
    1494 SCIP_CALL( SCIPallocBlockMemory(scip, &sepadata) );
    1495
    1496 /* include dummy separators */
    1497 SCIP_CALL( SCIPincludeSepaBasic(scip, &sepadata->flowcover, "flowcover", "separator for flowcover cuts", -100000, SEPA_FREQ, 0.0,
    1498 SEPA_USESSUBSCIP, FALSE, sepaExeclpDummy, sepaExecsolDummy, NULL) );
    1499
    1500 assert(sepadata->flowcover != NULL);
    1501
    1502 SCIP_CALL( SCIPincludeSepaBasic(scip, &sepadata->cmir, "cmir", "separator for cmir cuts", -100000, SEPA_FREQ, 0.0,
    1503 SEPA_USESSUBSCIP, FALSE, sepaExeclpDummy, sepaExecsolDummy, NULL) );
    1504
    1505 assert(sepadata->cmir != NULL);
    1506
    1507 SCIP_CALL( SCIPincludeSepaBasic(scip, &sepadata->knapsackcover, "knapsackcover", "separator for knapsack cover cuts", -100000, SEPA_FREQ, 0.0,
    1508 SEPA_USESSUBSCIP, FALSE, sepaExeclpDummy, sepaExecsolDummy, NULL) );
    1509
    1510 assert(sepadata->knapsackcover != NULL);
    1511
    1512 /* include separator */
    1515 sepaExeclpAggregation, sepaExecsolAggregation,
    1516 sepadata) );
    1517
    1518 assert(sepa != NULL);
    1519
    1520 /* set non-NULL pointers to callback methods */
    1521 SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyAggregation) );
    1522 SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeAggregation) );
    1523
    1524 /* mark main separator as a parent */
    1526
    1527 /* set pointer from child separators to main separator */
    1528 SCIPsetSepaParentsepa(scip, sepadata->flowcover, sepa);
    1529 SCIPsetSepaParentsepa(scip, sepadata->cmir, sepa);
    1530 SCIPsetSepaParentsepa(scip, sepadata->knapsackcover, sepa);
    1531
    1532 /* add cmir separator parameters */
    1534 "separating/" SEPA_NAME "/maxrounds",
    1535 "maximal number of cmir separation rounds per node (-1: unlimited)",
    1536 &sepadata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
    1538 "separating/" SEPA_NAME "/maxroundsroot",
    1539 "maximal number of cmir separation rounds in the root node (-1: unlimited)",
    1540 &sepadata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
    1542 "separating/" SEPA_NAME "/maxtries",
    1543 "maximal number of rows to start aggregation with per separation round (-1: unlimited)",
    1544 &sepadata->maxtries, TRUE, DEFAULT_MAXTRIES, -1, INT_MAX, NULL, NULL) );
    1546 "separating/" SEPA_NAME "/maxtriesroot",
    1547 "maximal number of rows to start aggregation with per separation round in the root node (-1: unlimited)",
    1548 &sepadata->maxtriesroot, TRUE, DEFAULT_MAXTRIESROOT, -1, INT_MAX, NULL, NULL) );
    1550 "separating/" SEPA_NAME "/maxfails",
    1551 "maximal number of consecutive unsuccessful aggregation tries (-1: unlimited)",
    1552 &sepadata->maxfails, TRUE, DEFAULT_MAXFAILS, -1, INT_MAX, NULL, NULL) );
    1554 "separating/" SEPA_NAME "/maxfailsroot",
    1555 "maximal number of consecutive unsuccessful aggregation tries in the root node (-1: unlimited)",
    1556 &sepadata->maxfailsroot, TRUE, DEFAULT_MAXFAILSROOT, -1, INT_MAX, NULL, NULL) );
    1558 "separating/" SEPA_NAME "/maxaggrs",
    1559 "maximal number of aggregations for each row per separation round",
    1560 &sepadata->maxaggrs, TRUE, DEFAULT_MAXAGGRS, 0, INT_MAX, NULL, NULL) );
    1562 "separating/" SEPA_NAME "/maxaggrsroot",
    1563 "maximal number of aggregations for each row per separation round in the root node",
    1564 &sepadata->maxaggrsroot, TRUE, DEFAULT_MAXAGGRSROOT, 0, INT_MAX, NULL, NULL) );
    1566 "separating/" SEPA_NAME "/maxsepacuts",
    1567 "maximal number of cmir cuts separated per separation round",
    1568 &sepadata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
    1570 "separating/" SEPA_NAME "/maxsepacutsroot",
    1571 "maximal number of cmir cuts separated per separation round in the root node",
    1572 &sepadata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
    1574 "separating/" SEPA_NAME "/maxslack",
    1575 "maximal slack of rows to be used in aggregation",
    1576 &sepadata->maxslack, TRUE, DEFAULT_MAXSLACK, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    1578 "separating/" SEPA_NAME "/maxslackroot",
    1579 "maximal slack of rows to be used in aggregation in the root node",
    1580 &sepadata->maxslackroot, TRUE, DEFAULT_MAXSLACKROOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    1582 "separating/" SEPA_NAME "/densityscore",
    1583 "weight of row density in the aggregation scoring of the rows",
    1584 &sepadata->densityscore, TRUE, DEFAULT_DENSITYSCORE, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    1586 "separating/" SEPA_NAME "/slackscore",
    1587 "weight of slack in the aggregation scoring of the rows",
    1588 &sepadata->slackscore, TRUE, DEFAULT_SLACKSCORE, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    1590 "separating/" SEPA_NAME "/maxaggdensity",
    1591 "maximal density of aggregated row",
    1592 &sepadata->maxaggdensity, TRUE, DEFAULT_MAXAGGDENSITY, 0.0, 1.0, NULL, NULL) );
    1594 "separating/" SEPA_NAME "/maxrowdensity",
    1595 "maximal density of row to be used in aggregation",
    1596 &sepadata->maxrowdensity, TRUE, DEFAULT_MAXROWDENSITY, 0.0, 1.0, NULL, NULL) );
    1598 "separating/" SEPA_NAME "/densityoffset",
    1599 "additional number of variables allowed in row on top of density",
    1600 &sepadata->densityoffset, TRUE, DEFAULT_DENSITYOFFSET, 0, INT_MAX, NULL, NULL) );
    1602 "separating/" SEPA_NAME "/maxrowfac",
    1603 "maximal row aggregation factor",
    1604 &sepadata->maxrowfac, TRUE, DEFAULT_MAXROWFAC, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    1606 "separating/" SEPA_NAME "/maxtestdelta",
    1607 "maximal number of different deltas to try (-1: unlimited)",
    1608 &sepadata->maxtestdelta, TRUE, DEFAULT_MAXTESTDELTA, -1, INT_MAX, NULL, NULL) );
    1610 "separating/" SEPA_NAME "/aggrtol",
    1611 "tolerance for bound distances used to select continuous variable in current aggregated constraint to be eliminated",
    1612 &sepadata->aggrtol, TRUE, DEFAULT_AGGRTOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    1614 "separating/" SEPA_NAME "/trynegscaling",
    1615 "should negative values also be tested in scaling?",
    1616 &sepadata->trynegscaling, TRUE, DEFAULT_TRYNEGSCALING, NULL, NULL) );
    1618 "separating/" SEPA_NAME "/fixintegralrhs",
    1619 "should an additional variable be complemented if f0 = 0?",
    1620 &sepadata->fixintegralrhs, TRUE, DEFAULT_FIXINTEGRALRHS, NULL, NULL) );
    1622 "separating/" SEPA_NAME "/dynamiccuts",
    1623 "should generated cuts be removed from the LP if they are no longer tight?",
    1624 &sepadata->dynamiccuts, FALSE, DEFAULT_DYNAMICCUTS, NULL, NULL) );
    1625
    1626 return SCIP_OKAY;
    1627}
    SCIP_Real * r
    Definition: circlepacking.c:59
    methods for the aggregation rows
    #define NULL
    Definition: def.h:257
    #define SCIP_MAXSTRLEN
    Definition: def.h:278
    #define SCIP_REAL_MAX
    Definition: def.h:167
    #define SCIP_Bool
    Definition: def.h:100
    #define MIN(x, y)
    Definition: def.h:233
    #define SCIP_STRINGEQ(name, reference, retcode)
    Definition: def.h:454
    #define SCIP_Real
    Definition: def.h:165
    #define TRUE
    Definition: def.h:102
    #define FALSE
    Definition: def.h:103
    #define MAX(x, y)
    Definition: def.h:229
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:157
    #define SCIPABORT()
    Definition: def.h:336
    #define REALABS(x)
    Definition: def.h:191
    #define SCIP_CALL(x)
    Definition: def.h:364
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:767
    int SCIPgetNIntVars(SCIP *scip)
    Definition: scip_prob.c:2340
    int SCIPgetNImplVars(SCIP *scip)
    Definition: scip_prob.c:2387
    int SCIPgetNContVars(SCIP *scip)
    Definition: scip_prob.c:2569
    SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
    Definition: scip_prob.c:2115
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    SCIP_VAR ** SCIPgetVars(SCIP *scip)
    Definition: scip_prob.c:2201
    SCIP_Real SCIPgetObjNorm(SCIP *scip)
    Definition: scip_prob.c:1880
    int SCIPgetNContImplVars(SCIP *scip)
    Definition: scip_prob.c:2522
    int SCIPgetNBinVars(SCIP *scip)
    Definition: scip_prob.c:2293
    SCIP_Bool SCIPisObjIntegral(SCIP *scip)
    Definition: scip_prob.c:1801
    #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
    void SCIPswapPointers(void **pointer1, void **pointer2)
    Definition: misc.c:10511
    void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
    Definition: misc.c:10498
    int SCIPgetNLPBranchCands(SCIP *scip)
    Definition: scip_branch.c:436
    SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
    Definition: lp.c:17425
    SCIP_Real * SCIPcolGetVals(SCIP_COL *col)
    Definition: lp.c:17555
    SCIP_ROW ** SCIPcolGetRows(SCIP_COL *col)
    Definition: lp.c:17545
    int SCIPcolGetNLPNonz(SCIP_COL *col)
    Definition: lp.c:17534
    SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
    Definition: scip_cut.c:336
    SCIP_Bool SCIPaggrRowHasRowBeenAdded(SCIP_AGGRROW *aggrrow, SCIP_ROW *row)
    Definition: cuts.c:4016
    SCIP_RETCODE SCIPaggrRowCreate(SCIP *scip, SCIP_AGGRROW **aggrrow)
    Definition: cuts.c:2679
    SCIP_RETCODE SCIPcreateCutGenResult(SCIP *scip, SCIP_CUTGENRESULT **result)
    Definition: cuts.c:13665
    void SCIPaggrRowClear(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:3229
    SCIP_Bool SCIPisCutNew(SCIP *scip, SCIP_ROW *row)
    Definition: scip_cut.c:318
    SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
    Definition: scip_cut.c:117
    SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
    Definition: scip_cut.c:135
    int SCIPaggrRowGetNRows(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:3984
    void SCIPfreeCutGenResult(SCIP *scip, SCIP_CUTGENRESULT **result)
    Definition: cuts.c:13685
    void SCIPaggrRowFree(SCIP *scip, SCIP_AGGRROW **aggrrow)
    Definition: cuts.c:2711
    void SCIPinitCutGenParams(SCIP_CUTGENPARAMS *params)
    Definition: cuts.c:13643
    SCIP_RETCODE SCIPcalcBestCut(SCIP *scip, SCIP_SOL *sol, SCIP_AGGRROW *aggrrow, SCIP_CUTGENMETHOD methods, SCIP_CUTGENPARAMS *params, SCIP_CUTGENRESULT *result)
    Definition: cuts.c:13716
    int * SCIPaggrRowGetInds(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:4039
    SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
    Definition: scip_cut.c:225
    void SCIPaggrRowRemoveZeros(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Bool useglbbounds, SCIP_Bool *valid)
    Definition: cuts.c:3960
    int SCIPaggrRowGetNNz(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:4049
    SCIP_RETCODE SCIPaggrRowAddRow(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, int sidetype)
    Definition: cuts.c:2815
    static INLINE SCIP_Real SCIPaggrRowGetProbvarValue(SCIP_AGGRROW *aggrrow, int probindex)
    Definition: cuts.h:297
    int * SCIPaggrRowGetRowInds(SCIP_AGGRROW *aggrrow)
    Definition: cuts.c:3994
    SCIP_RETCODE SCIPaggrRowAddObjectiveFunction(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Real rhs, SCIP_Real scale)
    Definition: cuts.c:3078
    SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
    Definition: scip_lp.c:576
    SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
    Definition: scip_lp.c:174
    int SCIPgetNLPCols(SCIP *scip)
    Definition: scip_lp.c:533
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPreallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:128
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPfreeBufferArrayNull(scip, ptr)
    Definition: scip_mem.h:137
    #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_Bool SCIProwIsModifiable(SCIP_ROW *row)
    Definition: lp.c:17805
    SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1581
    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
    int SCIProwGetNLPNonz(SCIP_ROW *row)
    Definition: lp.c:17621
    SCIP_Real SCIProwGetNorm(SCIP_ROW *row)
    Definition: lp.c:17662
    int SCIProwGetLPPos(SCIP_ROW *row)
    Definition: lp.c:17895
    SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1604
    SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
    Definition: lp.c:17795
    SCIP_RETCODE SCIPmakeRowIntegral(SCIP *scip, SCIP_ROW *row, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Bool usecontvars, SCIP_Bool *success)
    Definition: scip_lp.c:1790
    SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_lp.c:1646
    SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
    Definition: scip_lp.c:2176
    const char * SCIProwGetName(SCIP_ROW *row)
    Definition: lp.c:17745
    SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
    Definition: scip_lp.c:1508
    SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
    Definition: scip_lp.c:1429
    int SCIProwGetRank(SCIP_ROW *row)
    Definition: lp.c:17775
    void SCIProwChgRank(SCIP_ROW *row, int rank)
    Definition: lp.c:17928
    SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
    Definition: lp.c:17706
    int SCIPgetRowNumIntCols(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1832
    SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
    Definition: lp.c:17642
    SCIP_Real SCIPgetRowSolActivity(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
    Definition: scip_lp.c:2108
    SCIP_RETCODE SCIPincludeSepaBasic(SCIP *scip, SCIP_SEPA **sepa, const char *name, const char *desc, int priority, int freq, SCIP_Real maxbounddist, SCIP_Bool usessubscip, SCIP_Bool delay, SCIP_DECL_SEPAEXECLP((*sepaexeclp)), SCIP_DECL_SEPAEXECSOL((*sepaexecsol)), SCIP_SEPADATA *sepadata)
    Definition: scip_sepa.c:115
    int SCIPsepaGetFreq(SCIP_SEPA *sepa)
    Definition: sepa.c:790
    const char * SCIPsepaGetName(SCIP_SEPA *sepa)
    Definition: sepa.c:746
    int SCIPsepaGetNCallsAtNode(SCIP_SEPA *sepa)
    Definition: sepa.c:893
    SCIP_RETCODE SCIPsetSepaFree(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAFREE((*sepafree)))
    Definition: scip_sepa.c:173
    SCIP_SEPADATA * SCIPsepaGetData(SCIP_SEPA *sepa)
    Definition: sepa.c:636
    void SCIPsepaSetData(SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata)
    Definition: sepa.c:646
    void SCIPsetSepaIsParentsepa(SCIP *scip, SCIP_SEPA *sepa)
    Definition: scip_sepa.c:309
    SCIP_RETCODE SCIPsetSepaCopy(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPACOPY((*sepacopy)))
    Definition: scip_sepa.c:157
    void SCIPsetSepaParentsepa(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPA *parentsepa)
    Definition: scip_sepa.c:324
    SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
    Definition: scip_sol.c:1844
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1763
    int SCIPgetNSepaRounds(SCIP *scip)
    SCIP_Longint SCIPgetNLPs(SCIP *scip)
    SCIP_Real SCIPgetCutoffbound(SCIP *scip)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Real SCIPfeasFrac(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPepsilon(SCIP *scip)
    SCIP_Real SCIPsumepsilon(SCIP *scip)
    SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
    Definition: var.c:23715
    SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
    Definition: var.c:24536
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24300
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24174
    SCIP_RETCODE SCIPgetVarClosestVub(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *closestvub, int *closestvubidx)
    Definition: scip_var.c:8592
    int SCIPvarGetProbindex(SCIP_VAR *var)
    Definition: var.c:23694
    SCIP_RETCODE SCIPgetVarClosestVlb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *closestvlb, int *closestvlbidx)
    Definition: scip_var.c:8569
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24266
    SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
    Definition: var.c:24526
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24152
    SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
    Definition: var.c:24568
    SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
    Definition: var.c:24578
    SCIP_Bool SCIPvarIsInLP(SCIP_VAR *var)
    Definition: var.c:23738
    SCIP_RETCODE SCIPincludeSepaAggregation(SCIP *scip)
    SCIP_Bool SCIPsortedvecFindInt(int *intarray, int val, int len, int *pos)
    void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    static SCIP_Real negate(SCIP_Real x)
    memory allocation routines
    #define BMSclearMemoryArray(ptr, num)
    Definition: memory.h:130
    public methods for LP management
    public methods for message output
    #define SCIPdebug(x)
    Definition: pub_message.h:93
    public data structures and miscellaneous methods
    methods for sorting joint arrays of various types
    public methods for separators
    public methods for problem variables
    public methods for branching rule plugins and branching
    public methods for cuts and aggregation rows
    general public methods
    public methods for the LP relaxation, rows and columns
    public methods for memory management
    public methods for message handling
    public methods for numerical tolerances
    public methods for SCIP parameter handling
    public methods for global and local (sub)problems
    public methods for separator plugins
    public methods for solutions
    public methods for querying solving statistics
    public methods for the branch-and-bound tree
    public methods for SCIP variables
    #define SEPA_PRIORITY
    #define DEFAULT_MAXTRIES
    struct AggregationData AGGREGATIONDATA
    #define SEPA_DELAY
    #define DEFAULT_SLACKSCORE
    #define DEFAULT_MAXAGGRS
    #define DEFAULT_MAXFAILS
    static SCIP_RETCODE addCut(SCIP *scip, SCIP_SOL *sol, SCIP_SEPA *sepa, SCIP_Bool makeintegral, SCIP_Real *cutcoefs, int *cutinds, int cutnnz, SCIP_Real cutrhs, SCIP_Real cutefficacy, SCIP_Bool cutislocal, SCIP_Bool cutremovable, int cutrank, const char *cutclassname, SCIP_Bool *cutoff, int *ncuts, SCIP_ROW **thecut)
    #define DEFAULT_AGGRTOL
    #define DEFAULT_DYNAMICCUTS
    static SCIP_DECL_SEPACOPY(sepaCopyAggregation)
    static SCIP_Bool getRowAggregationCandidates(AGGREGATIONDATA *aggrdata, int probvaridx, SCIP_ROW ***rows, SCIP_Real **rowvarcoefs, int *nrows, int *ngoodrows)
    #define SEPA_DESC
    static SCIP_DECL_SEPAFREE(sepaFreeAggregation)
    static SCIP_Real aggrdataGetBoundDist(AGGREGATIONDATA *aggrdata, int probvaridx)
    #define DEFAULT_MAXSLACKROOT
    #define MAKECONTINTEGRAL
    static SCIP_RETCODE aggregation(SCIP *scip, AGGREGATIONDATA *aggrdata, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_Bool allowlocal, SCIP_Real *rowlhsscores, SCIP_Real *rowrhsscores, int startrow, int maxaggrs, SCIP_Bool *wastried, SCIP_Bool *cutoff, SCIP_CUTGENRESULT *cutresult, SCIP_Bool negate, int *ncuts)
    #define DEFAULT_MAXFAILSROOT
    #define DEFAULT_MAXAGGRSROOT
    #define DEFAULT_MAXROUNDSROOT
    #define SEPA_USESSUBSCIP
    #define DEFAULT_MAXSLACK
    static SCIP_RETCODE aggregateNextRow(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_Real *rowlhsscores, SCIP_Real *rowrhsscores, AGGREGATIONDATA *aggrdata, SCIP_AGGRROW *aggrrow, int *naggrs, SCIP_Bool *success)
    #define DEFAULT_TRYNEGSCALING
    #define DEFAULT_MAXTRIESROOT
    #define DEFAULT_MAXROWFAC
    static SCIP_DECL_SEPAEXECLP(sepaExeclpAggregation)
    #define DEFAULT_MAXSEPACUTSROOT
    #define DEFAULT_DENSITYSCORE
    #define DEFAULT_DENSITYOFFSET
    static SCIP_DECL_SEPAEXECSOL(sepaExecsolAggregation)
    #define DEFAULT_FIXINTEGRALRHS
    static SCIP_RETCODE setupAggregationData(SCIP *scip, SCIP_SOL *sol, SCIP_Bool allowlocal, AGGREGATIONDATA *aggrdata)
    #define DEFAULT_MAXTESTDELTA
    #define SEPA_MAXBOUNDDIST
    #define SEPA_FREQ
    #define DEFAULT_MAXSEPACUTS
    #define DEFAULT_MAXAGGDENSITY
    #define SEPA_NAME
    static SCIP_Real getRowFracActivity(SCIP_ROW *row, SCIP_Real *fractionalities)
    #define DEFAULT_MAXROUNDS
    static void destroyAggregationData(SCIP *scip, AGGREGATIONDATA *aggrdata)
    #define DEFAULT_MAXROWDENSITY
    static SCIP_RETCODE separateCuts(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_Bool allowlocal, int depth, SCIP_RESULT *result)
    flow cover and complemented mixed integer rounding cuts separator (Marchand's version)
    SCIP_AGGRROW * aggrrow
    SCIP_Real * bounddist
    SCIP_ROW ** aggrrows
    SCIP_Real * aggrrowscoef
    SCIP_Bool allowlocal
    Definition: struct_cuts.h:69
    SCIP_Bool cutislocal
    Definition: struct_cuts.h:82
    SCIP_Real cutrhs
    Definition: struct_cuts.h:79
    SCIP_Real cutefficacy
    Definition: struct_cuts.h:78
    SCIP_CUTGENMETHOD winningmethod
    Definition: struct_cuts.h:77
    SCIP_Bool success
    Definition: struct_cuts.h:83
    SCIP_Real * cutcoefs
    Definition: struct_cuts.h:75
    #define SCIP_CUTGENMETHOD_KNAPSACKCOVER
    Definition: type_cuts.h:44
    #define SCIP_CUTGENMETHOD_NONE
    Definition: type_cuts.h:42
    #define SCIP_CUTGENMETHOD_CMIR
    Definition: type_cuts.h:45
    uint32_t SCIP_CUTGENMETHOD
    Definition: type_cuts.h:39
    #define SCIP_CUTGENMETHOD_FLOWCOVER
    Definition: type_cuts.h:43
    @ SCIP_LPSOLSTAT_OPTIMAL
    Definition: type_lp.h:44
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_CUTOFF
    Definition: type_result.h:48
    @ SCIP_DIDNOTFIND
    Definition: type_result.h:44
    @ SCIP_SEPARATED
    Definition: type_result.h:49
    enum SCIP_Result SCIP_RESULT
    Definition: type_result.h:61
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    @ SCIP_ERROR
    Definition: type_retcode.h:43
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    struct SCIP_SepaData SCIP_SEPADATA
    Definition: type_sepa.h:52