Scippy

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