Scippy

    SCIP

    Solving Constraint Integer Programs

    sepa_eccuts.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_eccuts.c
    26 * @ingroup DEFPLUGINS_SEPA
    27 * @brief edge concave cut separator
    28 * @author Benjamin Mueller
    29 */
    30
    31/**@todo only count number of fixed variables in the edge concave terms */
    32/**@todo only add nonlinear row aggregations where at least ...% of the variables (bilinear terms?) are in edge concave
    33 * terms */
    34/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    35
    36#include <assert.h>
    37#include <string.h>
    38
    39#include "scip/scipdefplugins.h"
    40#include "scip/sepa_eccuts.h"
    41#include "scip/cons_xor.h"
    42#include "scip/nlp.h"
    43#include "tclique/tclique.h"
    44
    45#define SEPA_NAME "eccuts"
    46#define SEPA_DESC "separator for edge-concave functions"
    47#define SEPA_PRIORITY -13000
    48#define SEPA_FREQ -1
    49#define SEPA_MAXBOUNDDIST 1.0
    50#define SEPA_USESSUBSCIP FALSE /**< does the separator use a secondary SCIP instance? */
    51#define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
    52
    53#define CLIQUE_MAXFIRSTNODEWEIGHT 1000 /**< maximum weight of branching nodes in level 0; 0 if not used for cliques
    54 * with at least one fractional node) */
    55#define CLIQUE_MINWEIGHT 0 /**< lower bound for weight of generated cliques */
    56#define CLIQUE_MAXNTREENODES 10000 /**< maximal number of nodes of b&b tree */
    57#define CLIQUE_BACKTRACKFREQ 10000 /**< frequency to backtrack to first level of tree (0: no premature backtracking) */
    58
    59#define DEFAULT_DYNAMICCUTS TRUE /**< should generated cuts be removed from the LP if they are no longer tight? */
    60#define DEFAULT_MAXROUNDS 10 /**< maximal number of separation rounds per node (-1: unlimited) */
    61#define DEFAULT_MAXROUNDSROOT 250 /**< maximal number of separation rounds in the root node (-1: unlimited) */
    62#define DEFAULT_MAXDEPTH -1 /**< maximal depth at which the separator is applied */
    63#define DEFAULT_MAXSEPACUTS 10 /**< maximal number of e.c. cuts separated per separation round */
    64#define DEFAULT_MAXSEPACUTSROOT 50 /**< maximal number of e.c. cuts separated per separation round in root node */
    65#define DEFAULT_CUTMAXRANGE 1e+7 /**< maximal coefficient range of a cut (maximal coefficient divided by minimal
    66 * coefficient) in order to be added to LP relaxation */
    67#define DEFAULT_MINVIOLATION 0.3 /**< minimal violation of an e.c. cut to be separated */
    68#define DEFAULT_MINAGGRSIZE 3 /**< search for e.c. aggregation of at least this size (has to be >= 3) */
    69#define DEFAULT_MAXAGGRSIZE 4 /**< search for e.c. aggregation of at most this size (has to be >= minaggrsize) */
    70#define DEFAULT_MAXBILINTERMS 500 /**< maximum number of bilinear terms allowed to be in a quadratic constraint */
    71#define DEFAULT_MAXSTALLROUNDS 5 /**< maximum number of unsuccessful rounds in the e.c. aggregation search */
    72
    73#define SUBSCIP_NODELIMIT 100LL /**< node limit to solve the sub-SCIP */
    74
    75#define ADJUSTFACETTOL 1e-6 /**< adjust resulting facets in checkRikun() up to a violation of this value */
    76#define USEDUALSIMPLEX TRUE /**< use dual or primal simplex algorithm? */
    77
    78/** first values for \f$2^n\f$ */
    79static const int poweroftwo[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 };
    80
    81/*
    82 * Data structures
    83 */
    84
    85/** data to store a single edge-concave aggregations; an edge-concave aggregation of a quadratic constraint is a subset
    86 * of nonconvex bilinear terms
    87 */
    88struct EcAggr
    89{
    90 SCIP_VAR** vars; /**< variables */
    91 int nvars; /**< number of variables */
    92 int varsize; /**< size of vars array */
    93
    94 SCIP_Real* termcoefs; /**< coefficients of bilinear terms */
    95 int* termvars1; /**< index of the first variable of each bilinear term */
    96 int* termvars2; /**< index of the second variable of each bilinear term*/
    97 int nterms; /**< number of bilinear terms in the aggregation */
    98 int termsize; /**< size of term{coefs,vars1,vars2} arrays */
    99};
    100typedef struct EcAggr SCIP_ECAGGR;
    101
    102/** data to store all edge-concave aggregations and the remaining part of a nonlinear row of the form g(x) <= rhs */
    104{
    105 SCIP_NLROW* nlrow; /**< nonlinear row aggregation */
    106 SCIP_Bool rhsaggr; /**< consider nonlinear row aggregation for g(x) <= rhs (TRUE) or
    107 * g(x) >= lhs (FALSE) */
    108
    109 SCIP_ECAGGR** ecaggr; /**< array with all edge-concave aggregations */
    110 int necaggr; /**< number of edge-concave aggregation */
    111
    112 SCIP_VAR** linvars; /**< linear variables */
    113 SCIP_Real* lincoefs; /**< linear coefficients */
    114 int nlinvars; /**< number of linear variables */
    115 int linvarssize; /**< size of linvars array */
    116
    117 SCIP_VAR** quadvars; /**< quadratic variables */
    118 int* quadvar2aggr; /**< stores in which edge-concave aggregation the i-th quadratic variable
    119 * is contained (< 0: in no edge-concave aggregation) */
    120 int nquadvars; /**< number of quadratic variables */
    121 int quadvarssize; /**< size of quadvars array */
    122
    123 SCIP_VAR** remtermvars1; /**< first quadratic variable of remaining bilinear terms */
    124 SCIP_VAR** remtermvars2; /**< second quadratic variable of remaining bilinear terms */
    125 SCIP_Real* remtermcoefs; /**< coefficients for each remaining bilinear term */
    126 int nremterms; /**< number of remaining bilinear terms */
    127 int remtermsize; /**< size of remterm* arrays */
    128
    129 SCIP_Real rhs; /**< rhs of the nonlinear row */
    130 SCIP_Real constant; /**< constant part of the nonlinear row */
    131};
    133
    134/** separator data */
    135struct SCIP_SepaData
    136{
    137 SCIP_NLROWAGGR** nlrowaggrs; /**< array containing all nonlinear row aggregations */
    138 int nnlrowaggrs; /**< number of nonlinear row aggregations */
    139 int nlrowaggrssize; /**< size of nlrowaggrs array */
    140 SCIP_Bool searchedforaggr; /**< flag if we already searched for nlrow aggregation candidates */
    141 int minaggrsize; /**< only search for e.c. aggregations of at least this size (has to be >= 3) */
    142 int maxaggrsize; /**< only search for e.c. aggregations of at most this size (has to be >= minaggrsize) */
    143 int maxecsize; /**< largest edge concave aggregation size */
    144 int maxbilinterms; /**< maximum number of bilinear terms allowed to be in a quadratic constraint */
    145 int maxstallrounds; /**< maximum number of unsuccessful rounds in the e.c. aggregation search */
    146
    147 SCIP_LPI* lpi; /**< LP interface to solve the LPs to compute the facets of the convex envelopes */
    148 int lpisize; /**< maximum size of e.c. aggregations which can be handled by the LP interface */
    149
    150 SCIP_Real cutmaxrange; /**< maximal coef range of a cut (maximal coefficient divided by minimal
    151 * coefficient) in order to be added to LP relaxation */
    152 SCIP_Bool dynamiccuts; /**< should generated cuts be removed from the LP if they are no longer tight? */
    153 SCIP_Real minviolation; /**< minimal violation of an e.c. cut to be separated */
    154
    155 int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
    156 int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
    157 int maxdepth; /**< maximal depth at which the separator is applied */
    158 int maxsepacuts; /**< maximal number of e.c. cuts separated per separation round */
    159 int maxsepacutsroot; /**< maximal number of e.c. cuts separated per separation round in root node */
    160
    161#ifdef SCIP_STATISTIC
    162 SCIP_Real aggrsearchtime; /**< total time spent for searching edge concave aggregations */
    163 int nlhsnlrowaggrs; /**< number of found nonlinear row aggregations for SCIP_NLROWs of the form g(x) <= rhs */
    164 int nrhsnlrowaggrs; /**< number of found nonlinear row aggregations for SCIP_NLROWs of the form g(x) >= lhs */
    165#endif
    166};
    167
    168
    169/*
    170 * Local methods
    171 */
    172
    173/** creates an empty edge-concave aggregation (without bilinear terms) */
    174static
    176 SCIP* scip, /**< SCIP data structure */
    177 SCIP_ECAGGR** ecaggr, /**< pointer to store the edge-concave aggregation */
    178 int nquadvars, /**< number of quadratic variables */
    179 int nquadterms /**< number of bilinear terms */
    180 )
    181{
    182 assert(scip != NULL);
    183 assert(ecaggr != NULL);
    184 assert(nquadvars > 0);
    185 assert(nquadterms >= nquadvars);
    186
    188
    189 (*ecaggr)->nvars = 0;
    190 (*ecaggr)->nterms = 0;
    191 (*ecaggr)->varsize = nquadvars;
    192 (*ecaggr)->termsize = nquadterms;
    193
    194 /* allocate enough memory for the quadratic variables and bilinear terms */
    195 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*ecaggr)->vars, nquadvars) );
    196 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*ecaggr)->termcoefs, nquadterms) );
    197 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*ecaggr)->termvars1, nquadterms) );
    198 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*ecaggr)->termvars2, nquadterms) );
    199
    200 return SCIP_OKAY;
    201}
    202
    203/** frees an edge-concave aggregation */
    204static
    206 SCIP* scip, /**< SCIP data structure */
    207 SCIP_ECAGGR** ecaggr /**< pointer to store the edge-concave aggregation */
    208 )
    209{
    210 assert(scip != NULL);
    211 assert(ecaggr != NULL);
    212
    213 SCIPfreeBlockMemoryArray(scip, &((*ecaggr)->termcoefs), (*ecaggr)->termsize);
    214 SCIPfreeBlockMemoryArray(scip, &((*ecaggr)->termvars1), (*ecaggr)->termsize);
    215 SCIPfreeBlockMemoryArray(scip, &((*ecaggr)->termvars2), (*ecaggr)->termsize);
    216 SCIPfreeBlockMemoryArray(scip, &((*ecaggr)->vars), (*ecaggr)->varsize);
    217
    218 SCIPfreeBlockMemory(scip, ecaggr);
    219 *ecaggr = NULL;
    220
    221 return SCIP_OKAY;
    222}
    223
    224/** adds a quadratic variable to an edge-concave aggregation */
    225static
    227 SCIP_ECAGGR* ecaggr, /**< pointer to store the edge-concave aggregation */
    228 SCIP_VAR* x /**< first variable */
    229 )
    230{
    231 ecaggr->vars[ ecaggr->nvars++ ] = x;
    232 return SCIP_OKAY;
    233}
    234
    235/** adds a bilinear term to an edge-concave aggregation */
    236static
    238 SCIP* scip, /**< SCIP data structure */
    239 SCIP_ECAGGR* ecaggr, /**< pointer to store the edge-concave aggregation */
    240 SCIP_VAR* x, /**< first variable */
    241 SCIP_VAR* y, /**< second variable */
    242 SCIP_Real coef /**< bilinear coefficient */
    243 )
    244{
    245 int idx1;
    246 int idx2;
    247 int i;
    248
    249 assert(x != NULL);
    250 assert(y != NULL);
    251 assert(ecaggr->nterms + 1 <= ((ecaggr->nvars + 1) * ecaggr->nvars) / 2);
    252 assert(!SCIPisZero(scip, coef));
    253
    254 idx1 = -1;
    255 idx2 = -1;
    256
    257 /* search for the quadratic variables in the e.c. aggregation */
    258 for( i = 0; i < ecaggr->nvars && (idx1 == -1 || idx2 == -1); ++i )
    259 {
    260 if( ecaggr->vars[i] == x )
    261 idx1 = i;
    262 if( ecaggr->vars[i] == y )
    263 idx2 = i;
    264 }
    265
    266 assert(idx1 != -1 && idx2 != -1);
    267
    268 ecaggr->termcoefs[ ecaggr->nterms ] = coef;
    269 ecaggr->termvars1[ ecaggr->nterms ] = idx1;
    270 ecaggr->termvars2[ ecaggr->nterms ] = idx2;
    271 ++(ecaggr->nterms);
    272
    273 return SCIP_OKAY;
    274}
    275
    276#ifdef SCIP_DEBUG
    277/** prints an edge-concave aggregation */
    278static
    279void ecaggrPrint(
    280 SCIP* scip, /**< SCIP data structure */
    281 SCIP_ECAGGR* ecaggr /**< pointer to store the edge-concave aggregation */
    282 )
    283{
    284 int i;
    285
    286 assert(scip != NULL);
    287 assert(ecaggr != NULL);
    288
    289 SCIPdebugMsg(scip, " nvars = %d nterms = %d\n", ecaggr->nvars, ecaggr->nterms);
    290 SCIPdebugMsg(scip, " vars: ");
    291 for( i = 0; i < ecaggr->nvars; ++i )
    292 SCIPdebugMsgPrint(scip, "%s ", SCIPvarGetName(ecaggr->vars[i]));
    293 SCIPdebugMsgPrint(scip, "\n");
    294
    295 SCIPdebugMsg(scip, " terms: ");
    296 for( i = 0; i < ecaggr->nterms; ++i )
    297 {
    298 SCIP_VAR* x;
    299 SCIP_VAR* y;
    300
    301 x = ecaggr->vars[ ecaggr->termvars1[i] ];
    302 y = ecaggr->vars[ ecaggr->termvars2[i] ];
    303 SCIPdebugMsgPrint(scip, "%e %s * %s ", ecaggr->termcoefs[i], SCIPvarGetName(x), SCIPvarGetName(y) );
    304 }
    305 SCIPdebugMsgPrint(scip, "\n");
    306}
    307#endif
    308
    309/** stores linear terms in a given nonlinear row aggregation */
    310static
    312 SCIP* scip, /**< SCIP data structure */
    313 SCIP_NLROWAGGR* nlrowaggr, /**< nonlinear row aggregation */
    314 SCIP_VAR** linvars, /**< linear variables */
    315 SCIP_Real* lincoefs, /**< linear coefficients */
    316 int nlinvars /**< number of linear variables */
    317 )
    318{
    319 assert(scip != NULL);
    320 assert(nlrowaggr != NULL);
    321 assert(linvars != NULL || nlinvars == 0);
    322 assert(lincoefs != NULL || nlinvars == 0);
    323 assert(nlinvars >= 0);
    324
    325 nlrowaggr->nlinvars = 0;
    326 nlrowaggr->linvarssize = 0;
    327 nlrowaggr->linvars = NULL;
    328 nlrowaggr->lincoefs = NULL;
    329
    330 if( nlinvars == 0 )
    331 return SCIP_OKAY;
    332
    333 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &nlrowaggr->linvars, linvars, nlinvars) );
    334 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &nlrowaggr->lincoefs, lincoefs, nlinvars) );
    335 nlrowaggr->nlinvars = nlinvars;
    336 nlrowaggr->linvarssize = nlinvars;
    337
    338 /* if we have a nlrow of the form g(x) >= lhs, multiply every coefficient by -1 */
    339 if( !nlrowaggr->rhsaggr )
    340 {
    341 int i;
    342
    343 for( i = 0; i < nlrowaggr->nlinvars; ++i )
    344 nlrowaggr->lincoefs[i] *= -1.0;
    345 }
    346
    347 return SCIP_OKAY;
    348}
    349
    350/** adds linear term to a given nonlinear row aggregation */
    351static
    353 SCIP* scip, /**< SCIP data structure */
    354 SCIP_NLROWAGGR* nlrowaggr, /**< nonlinear row aggregation */
    355 SCIP_VAR* linvar, /**< linear variable */
    356 SCIP_Real lincoef /**< coefficient */
    357 )
    358{
    359 assert(scip != NULL);
    360 assert(nlrowaggr != NULL);
    361 assert(linvar != NULL);
    362
    363 if( nlrowaggr->nlinvars == nlrowaggr->linvarssize )
    364 {
    365 int newsize = SCIPcalcMemGrowSize(scip, nlrowaggr->linvarssize+1);
    366 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &nlrowaggr->linvars, nlrowaggr->linvarssize, newsize) );
    367 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &nlrowaggr->lincoefs, nlrowaggr->linvarssize, newsize) );
    368 nlrowaggr->linvarssize = newsize;
    369 }
    370 assert(nlrowaggr->linvarssize > nlrowaggr->nlinvars);
    371
    372 /* if we have a nlrow of the form g(x) >= lhs, multiply coefficient by -1 */
    373 if( !nlrowaggr->rhsaggr )
    374 lincoef = -lincoef;
    375
    376 nlrowaggr->linvars[nlrowaggr->nlinvars] = linvar;
    377 nlrowaggr->lincoefs[nlrowaggr->nlinvars] = lincoef;
    378 ++nlrowaggr->nlinvars;
    379
    380 return SCIP_OKAY;
    381}
    382
    383/** adds quadratic variable to a given nonlinear row aggregation */
    384static
    386 SCIP* scip, /**< SCIP data structure */
    387 SCIP_NLROWAGGR* nlrowaggr, /**< nonlinear row aggregation */
    388 SCIP_VAR* quadvar /**< quadratic variable */
    389 )
    390{
    391 assert(scip != NULL);
    392 assert(nlrowaggr != NULL);
    393 assert(quadvar != NULL);
    394
    395 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &nlrowaggr->quadvars, &nlrowaggr->quadvarssize, nlrowaggr->nquadvars+1) );
    396 assert(nlrowaggr->quadvarssize > nlrowaggr->nquadvars);
    397 nlrowaggr->quadvars[nlrowaggr->nquadvars] = quadvar;
    398 ++nlrowaggr->nquadvars;
    399
    400 return SCIP_OKAY;
    401}
    402
    403/** adds a remaining bilinear term to a given nonlinear row aggregation */
    404static
    406 SCIP_NLROWAGGR* nlrowaggr, /**< nonlinear row aggregation */
    407 SCIP_VAR* x, /**< first variable */
    408 SCIP_VAR* y, /**< second variable */
    409 SCIP_Real coef /**< bilinear coefficient */
    410 )
    411{
    412 assert(nlrowaggr != NULL);
    413 assert(x != NULL);
    414 assert(y != NULL);
    415 assert(coef != 0.0);
    416 assert(nlrowaggr->remtermcoefs != NULL);
    417 assert(nlrowaggr->remtermvars1 != NULL);
    418 assert(nlrowaggr->remtermvars2 != NULL);
    419
    420 nlrowaggr->remtermcoefs[ nlrowaggr->nremterms ] = coef;
    421 nlrowaggr->remtermvars1[ nlrowaggr->nremterms ] = x;
    422 nlrowaggr->remtermvars2[ nlrowaggr->nremterms ] = y;
    423 ++(nlrowaggr->nremterms);
    424
    425 return SCIP_OKAY;
    426}
    427
    428/** creates a nonlinear row aggregation */
    429static
    431 SCIP* scip, /**< SCIP data structure */
    432 SCIP_NLROW* nlrow, /**< nonlinear row */
    433 SCIP_NLROWAGGR** nlrowaggr, /**< pointer to store the nonlinear row aggregation */
    434 int* quadvar2aggr, /**< mapping between quadratic variables and edge-concave aggregation
    435 * stores a negative value if the quadratic variables does not belong
    436 * to any aggregation */
    437 int nfound, /**< number of edge-concave aggregations */
    438 SCIP_Bool rhsaggr /**< consider nonlinear row aggregation for g(x) <= rhs (TRUE) or
    439 * lhs <= g(x) (FALSE) */
    440 )
    441{
    442 SCIP_EXPR* expr;
    443 int* aggrnvars; /* count the number of variables in each e.c. aggregations */
    444 int* aggrnterms; /* count the number of bilinear terms in each e.c. aggregations */
    445 int nquadvars;
    446 int nremterms;
    447 int i;
    448
    449 assert(scip != NULL);
    450 assert(nlrow != NULL);
    451 assert(nlrowaggr != NULL);
    452 assert(quadvar2aggr != NULL);
    453 assert(nfound > 0);
    454
    455 expr = SCIPnlrowGetExpr(nlrow);
    456 SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, &nquadvars, NULL, NULL, NULL);
    457 nremterms = 0;
    458
    459 SCIP_CALL( SCIPallocClearBufferArray(scip, &aggrnvars, nfound) );
    460 SCIP_CALL( SCIPallocClearBufferArray(scip, &aggrnterms, nfound) );
    461
    462 /* create an empty nonlinear row aggregation */
    463 SCIP_CALL( SCIPallocBlockMemory(scip, nlrowaggr) );
    464 (*nlrowaggr)->nlrow = nlrow;
    465 (*nlrowaggr)->rhsaggr = rhsaggr;
    466 (*nlrowaggr)->rhs = rhsaggr ? SCIPnlrowGetRhs(nlrow) : -SCIPnlrowGetLhs(nlrow);
    467 (*nlrowaggr)->constant = rhsaggr ? SCIPnlrowGetConstant(nlrow) : -SCIPnlrowGetConstant(nlrow);
    468
    469 (*nlrowaggr)->quadvars = NULL;
    470 (*nlrowaggr)->nquadvars = 0;
    471 (*nlrowaggr)->quadvarssize = 0;
    472 (*nlrowaggr)->quadvar2aggr = NULL;
    473 (*nlrowaggr)->remtermcoefs = NULL;
    474 (*nlrowaggr)->remtermvars1 = NULL;
    475 (*nlrowaggr)->remtermvars2 = NULL;
    476 (*nlrowaggr)->nremterms = 0;
    477
    478 /* copy quadvar2aggr array */
    479 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*nlrowaggr)->quadvar2aggr, quadvar2aggr, nquadvars) );
    480
    481 /* store all linear terms */
    483 SCIPnlrowGetNLinearVars(nlrow)) );
    484
    485 /* store all quadratic variables and additional linear terms */
    486 /* count the number of variables in each e.c. aggregation */
    487 /* count the number of square and bilinear terms in each e.c. aggregation */
    488 for( i = 0; i < nquadvars; ++i )
    489 {
    490 SCIP_EXPR* qterm;
    491 SCIP_Real lincoef;
    492 SCIP_Real sqrcoef;
    493 int idx1;
    494 int nadjbilin;
    495 int* adjbilin;
    496 int j;
    497
    498 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, &lincoef, &sqrcoef, &nadjbilin, &adjbilin, NULL);
    499 assert(SCIPisExprVar(scip, qterm));
    500
    502
    503 if( lincoef != 0.0 )
    504 {
    505 SCIP_CALL( nlrowaggrAddLinearTerm(scip, *nlrowaggr, SCIPgetVarExprVar(qterm), lincoef) );
    506 }
    507
    508 if( quadvar2aggr[i] >= 0)
    509 ++aggrnvars[ quadvar2aggr[i] ];
    510
    511 idx1 = quadvar2aggr[i];
    512 if( rhsaggr )
    513 sqrcoef = -sqrcoef;
    514
    515 /* variable has to belong to an e.c. aggregation; square term has to be concave */
    516 if( idx1 >= 0 && SCIPisNegative(scip, sqrcoef) )
    517 ++aggrnterms[idx1];
    518 else
    519 ++nremterms;
    520
    521 for( j = 0; j < nadjbilin; ++j )
    522 {
    523 SCIP_EXPR* qterm1;
    524 int pos2;
    525 int idx2;
    526
    527 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &qterm1, NULL, NULL, &pos2, NULL);
    528
    529 /* only handle qterm1 == qterm here; the other case will be handled when its turn for qterm2 to be qterm */
    530 if( qterm1 != qterm )
    531 continue;
    532
    533 idx2 = quadvar2aggr[pos2];
    534
    535 /* variables have to belong to the same e.c. aggregation; bilinear term has to be concave */
    536 if( idx1 >= 0 && idx2 >= 0 && idx1 == idx2 )
    537 ++aggrnterms[idx1];
    538 else
    539 ++nremterms;
    540 }
    541 }
    542 assert((*nlrowaggr)->nquadvars == nquadvars);
    543
    544 /* create all edge-concave aggregations (empty) and remaining terms */
    545 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*nlrowaggr)->ecaggr, nfound) );
    546 if( nremterms > 0 )
    547 {
    548 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*nlrowaggr)->remtermcoefs, nremterms) );
    549 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*nlrowaggr)->remtermvars1, nremterms) );
    550 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*nlrowaggr)->remtermvars2, nremterms) );
    551 (*nlrowaggr)->remtermsize = nremterms;
    552 }
    553 (*nlrowaggr)->necaggr = nfound;
    554
    555 for( i = 0; i < nfound; ++i )
    556 {
    557 SCIP_CALL( ecaggrCreateEmpty(scip, &(*nlrowaggr)->ecaggr[i], aggrnvars[i], aggrnterms[i]) );
    558 }
    559
    560 /* add quadratic variables to the edge-concave aggregations */
    561 for( i = 0; i < nquadvars; ++i )
    562 {
    563 int idx;
    564
    565 idx = quadvar2aggr[i];
    566
    567 if( idx >= 0)
    568 {
    569 SCIP_EXPR* qterm;
    570
    571 SCIPdebugMsg(scip, "add quadvar %d to aggr. %d\n", i, idx);
    572
    573 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, NULL, NULL, NULL, NULL);
    574 assert(SCIPisExprVar(scip, qterm));
    575
    576 SCIP_CALL( ecaggrAddQuadvar((*nlrowaggr)->ecaggr[idx], SCIPgetVarExprVar(qterm)) );
    577 }
    578 }
    579
    580 /* add the bilinear/square terms to the edge-concave aggregations or in the remaining part */
    581 for( i = 0; i < nquadvars; ++i )
    582 {
    583 SCIP_EXPR* qterm;
    584 SCIP_VAR* x;
    585 SCIP_Real coef;
    586 int idx1;
    587 int nadjbilin;
    588 int* adjbilin;
    589 int j;
    590
    591 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, &coef, &nadjbilin, &adjbilin, NULL);
    592
    593 x = SCIPgetVarExprVar(qterm);
    594
    595 idx1 = quadvar2aggr[i];
    596 if( rhsaggr )
    597 coef = -coef;
    598
    599 if( idx1 >= 0 && SCIPisNegative(scip, coef) )
    600 {
    601 SCIP_CALL( ecaggrAddBilinTerm(scip, (*nlrowaggr)->ecaggr[idx1], x, x, coef) );
    602 SCIPdebugMsg(scip, "add term %e *%d^2 to aggr. %d\n", coef, i, idx1);
    603 }
    604 else
    605 {
    606 SCIP_CALL( nlrowaggrAddRemBilinTerm(*nlrowaggr, x, x, coef) );
    607 SCIPdebugMsg(scip, "add term %e *%d^2 to the remaining part\n", coef, idx1);
    608 }
    609
    610 for( j = 0; j < nadjbilin; ++j )
    611 {
    612 SCIP_EXPR* qterm1;
    613 SCIP_EXPR* qterm2;
    614 int pos2;
    615 int idx2;
    616 SCIP_VAR* y;
    617
    618 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &qterm1, &qterm2, &coef, &pos2, NULL);
    619
    620 /* only handle qterm1 == qterm here; the other case will be handled when its turn for qterm2 to be qterm */
    621 if( qterm1 != qterm )
    622 continue;
    623
    624 y = SCIPgetVarExprVar(qterm2);
    625
    626 idx2 = quadvar2aggr[pos2];
    627 if( rhsaggr )
    628 coef = -coef;
    629
    630 if( idx1 >= 0 && idx2 >= 0 && idx1 == idx2 )
    631 {
    632 SCIP_CALL( ecaggrAddBilinTerm(scip, (*nlrowaggr)->ecaggr[idx1], x, y, coef) );
    633 SCIPdebugMsg(scip, "add term %e *%d*%d to aggr. %d\n", coef, i, pos2, idx1);
    634 }
    635 else
    636 {
    637 SCIP_CALL( nlrowaggrAddRemBilinTerm(*nlrowaggr, x, y, coef) );
    638 SCIPdebugMsg(scip, "add term %e *%d*%d to the remaining part\n", coef, i, pos2);
    639 }
    640 }
    641 }
    642
    643 /* free allocated memory */
    644 SCIPfreeBufferArray(scip, &aggrnterms);
    645 SCIPfreeBufferArray(scip, &aggrnvars);
    646
    647 return SCIP_OKAY;
    648}
    649
    650/** frees a nonlinear row aggregation */
    651static
    653 SCIP* scip, /**< SCIP data structure */
    654 SCIP_NLROWAGGR** nlrowaggr /**< pointer to free the nonlinear row aggregation */
    655 )
    656{
    657 int i;
    658
    659 assert(scip != NULL);
    660 assert(nlrowaggr != NULL);
    661 assert(*nlrowaggr != NULL);
    662 (*nlrowaggr)->nlrow = NULL;
    663 assert((*nlrowaggr)->quadvars != NULL);
    664 assert((*nlrowaggr)->nquadvars > 0);
    665 assert((*nlrowaggr)->nremterms >= 0);
    666
    667 /* free remaining part */
    668 SCIPfreeBlockMemoryArrayNull(scip, &(*nlrowaggr)->remtermcoefs, (*nlrowaggr)->remtermsize);
    669 SCIPfreeBlockMemoryArrayNull(scip, &(*nlrowaggr)->remtermvars1, (*nlrowaggr)->remtermsize);
    670 SCIPfreeBlockMemoryArrayNull(scip, &(*nlrowaggr)->remtermvars2, (*nlrowaggr)->remtermsize);
    671
    672 /* free quadratic variables */
    673 SCIPfreeBlockMemoryArray(scip, &(*nlrowaggr)->quadvars, (*nlrowaggr)->quadvarssize);
    674 SCIPfreeBlockMemoryArray(scip, &(*nlrowaggr)->quadvar2aggr, (*nlrowaggr)->nquadvars);
    675
    676 /* free linear part */
    677 if( (*nlrowaggr)->nlinvars > 0 )
    678 {
    679 SCIPfreeBlockMemoryArray(scip, &(*nlrowaggr)->linvars, (*nlrowaggr)->linvarssize);
    680 SCIPfreeBlockMemoryArray(scip, &(*nlrowaggr)->lincoefs, (*nlrowaggr)->linvarssize);
    681 }
    682
    683 /* free edge-concave aggregations */
    684 for( i = 0; i < (*nlrowaggr)->necaggr; ++i )
    685 {
    686 SCIP_CALL( ecaggrFree(scip, &(*nlrowaggr)->ecaggr[i]) );
    687 }
    688 SCIPfreeBlockMemoryArray(scip, &(*nlrowaggr)->ecaggr, (*nlrowaggr)->necaggr);
    689
    690 /* free nlrow aggregation */
    691 SCIPfreeBlockMemory(scip, nlrowaggr);
    692
    693 return SCIP_OKAY;
    694}
    695
    696#ifdef SCIP_DEBUG
    697/** prints a nonlinear row aggregation */
    698static
    699void nlrowaggrPrint(
    700 SCIP* scip, /**< SCIP data structure */
    701 SCIP_NLROWAGGR* nlrowaggr /**< nonlinear row aggregation */
    702 )
    703{
    704 int i;
    705
    706 SCIPdebugMsg(scip, " nlrowaggr rhs = %e\n", nlrowaggr->rhs);
    707 SCIPdebugMsg(scip, " #remaining terms = %d\n", nlrowaggr->nremterms);
    708
    709 SCIPdebugMsg(scip, "remaining terms: ");
    710 for( i = 0; i < nlrowaggr->nremterms; ++i )
    711 SCIPdebugMsgPrint(scip, "%e %s * %s + ", nlrowaggr->remtermcoefs[i], SCIPvarGetName(nlrowaggr->remtermvars1[i]),
    712 SCIPvarGetName(nlrowaggr->remtermvars2[i]) );
    713 for( i = 0; i < nlrowaggr->nlinvars; ++i )
    714 SCIPdebugMsgPrint(scip, "%e %s + ", nlrowaggr->lincoefs[i], SCIPvarGetName(nlrowaggr->linvars[i]) );
    715 SCIPdebugMsgPrint(scip, "\n");
    716
    717 for( i = 0; i < nlrowaggr->necaggr; ++i )
    718 {
    719 SCIPdebugMsg(scip, "print e.c. aggr %d\n", i);
    720 ecaggrPrint(scip, nlrowaggr->ecaggr[i]);
    721 }
    722 return;
    723}
    724#endif
    725
    726/** creates separator data */
    727static
    729 SCIP* scip, /**< SCIP data structure */
    730 SCIP_SEPADATA** sepadata /**< pointer to store separator data */
    731 )
    732{
    733 assert(scip != NULL);
    734 assert(sepadata != NULL);
    735
    736 SCIP_CALL( SCIPallocBlockMemory(scip, sepadata) );
    737 BMSclearMemory(*sepadata);
    738
    739 return SCIP_OKAY;
    740}
    741
    742/** frees all nonlinear row aggregations */
    743static
    745 SCIP* scip, /**< SCIP data structure */
    746 SCIP_SEPADATA* sepadata /**< pointer to store separator data */
    747 )
    748{
    749 assert(scip != NULL);
    750 assert(sepadata != NULL);
    751
    752 /* free nonlinear row aggregations */
    753 if( sepadata->nlrowaggrs != NULL )
    754 {
    755 int i;
    756
    757 for( i = sepadata->nnlrowaggrs - 1; i >= 0; --i )
    758 {
    759 SCIP_CALL( nlrowaggrFree(scip, &sepadata->nlrowaggrs[i]) );
    760 }
    761
    762 SCIPfreeBlockMemoryArray(scip, &sepadata->nlrowaggrs, sepadata->nlrowaggrssize);
    763
    764 sepadata->nlrowaggrs = NULL;
    765 sepadata->nnlrowaggrs = 0;
    766 sepadata->nlrowaggrssize = 0;
    767 }
    768
    769 return SCIP_OKAY;
    770}
    771
    772/** frees separator data */
    773static
    775 SCIP* scip, /**< SCIP data structure */
    776 SCIP_SEPADATA** sepadata /**< pointer to store separator data */
    777 )
    778{
    779 assert(scip != NULL);
    780 assert(sepadata != NULL);
    781 assert(*sepadata != NULL);
    782
    783 /* free nonlinear row aggregations */
    784 SCIP_CALL( sepadataFreeNlrows(scip, *sepadata) );
    785
    786 /* free LP interface */
    787 if( (*sepadata)->lpi != NULL )
    788 {
    789 SCIP_CALL( SCIPlpiFree(&((*sepadata)->lpi)) );
    790 (*sepadata)->lpisize = 0;
    791 }
    792
    793 SCIPfreeBlockMemory(scip, sepadata);
    794
    795 return SCIP_OKAY;
    796}
    797
    798/** adds a nonlinear row aggregation to the separator data */
    799static
    801 SCIP* scip, /**< SCIP data structure */
    802 SCIP_SEPADATA* sepadata, /**< separator data */
    803 SCIP_NLROWAGGR* nlrowaggr /**< non-linear row aggregation */
    804 )
    805{
    806 int i;
    807
    808 assert(scip != NULL);
    809 assert(sepadata != NULL);
    810 assert(nlrowaggr != NULL);
    811
    812 if( sepadata->nlrowaggrssize == 0 )
    813 {
    814 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &sepadata->nlrowaggrs, 2) ); /*lint !e506*/
    815 sepadata->nlrowaggrssize = 2;
    816 }
    817 else if( sepadata->nlrowaggrssize < sepadata->nnlrowaggrs + 1 )
    818 {
    819 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &sepadata->nlrowaggrs, sepadata->nlrowaggrssize, 2 * sepadata->nlrowaggrssize) ); /*lint !e506 !e647*/
    820 sepadata->nlrowaggrssize *= 2;
    821 assert(sepadata->nlrowaggrssize >= sepadata->nnlrowaggrs + 1);
    822 }
    823
    824 sepadata->nlrowaggrs[ sepadata->nnlrowaggrs ] = nlrowaggr;
    825 ++(sepadata->nnlrowaggrs);
    826
    827 /* update maximum e.c. aggregation size */
    828 for( i = 0; i < nlrowaggr->necaggr; ++i )
    829 sepadata->maxecsize = MAX(sepadata->maxecsize, nlrowaggr->ecaggr[i]->nvars);
    830
    831#ifdef SCIP_STATISTIC
    832 /* update statistics */
    833 if( nlrowaggr->rhsaggr )
    834 ++(sepadata->nrhsnlrowaggrs);
    835 else
    836 ++(sepadata->nlhsnlrowaggrs);
    837#endif
    838
    839 return SCIP_OKAY;
    840}
    841
    842/** returns min{val-lb,ub-val} / (ub-lb) */
    843static
    845 SCIP* scip, /**< SCIP data structure */
    846 SCIP_Real val, /**< solution value */
    847 SCIP_Real lb, /**< lower bound */
    848 SCIP_Real ub /**< upper bound */
    849 )
    850{
    851 if( SCIPisFeasEQ(scip, lb, ub) )
    852 return 0.0;
    853
    854 /* adjust */
    855 val = MAX(val, lb);
    856 val = MIN(val, ub);
    857
    858 return MIN(ub - val, val - lb) / (ub - lb);
    859}
    860
    861/** creates an MIP to search for cycles with an odd number of positive edges in the graph representation of a nonlinear row
    862 *
    863 * The model uses directed binary arc flow variables.
    864 * We introduce for all quadratic elements a forward and backward edge.
    865 * If the term is quadratic (e.g., loop in the graph) we fix the corresponding variables to zero.
    866 * This leads to an easy mapping between quadratic elements and the variables of the MIP.
    867 */
    868static
    870 SCIP* scip, /**< SCIP data structure */
    871 SCIP* subscip, /**< auxiliary SCIP to search aggregations */
    872 SCIP_SEPADATA* sepadata, /**< separator data */
    873 SCIP_NLROW* nlrow, /**< nonlinear row */
    874 SCIP_Bool rhsaggr, /**< consider nonlinear row aggregation for g(x) <= rhs (TRUE) or
    875 * lhs <= g(x) (FALSE) */
    876 SCIP_VAR** forwardarcs, /**< array to store all forward arc variables */
    877 SCIP_VAR** backwardarcs, /**< array to store all backward arc variables */
    878 SCIP_Real* nodeweights, /**< weights for each node of the graph */
    879 int* nedges, /**< pointer to store the number of nonexcluded edges in the graph */
    880 int* narcs /**< pointer to store the number of created arc variables (number of square and bilinear terms) */
    881 )
    882{
    883 SCIP_VAR** oddcyclearcs;
    884 SCIP_CONS** flowcons;
    885 SCIP_CONS* cyclelengthcons;
    886 SCIP_CONS* oddcyclecons;
    887 char name[SCIP_MAXSTRLEN];
    888 SCIP_EXPR* expr;
    889 int noddcyclearcs;
    890 int nnodes;
    891 int nquadexprs;
    892 int nbilinexprs;
    893 int i;
    894 int arcidx;
    895
    896 assert(subscip != NULL);
    897 assert(forwardarcs != NULL);
    898 assert(backwardarcs != NULL);
    899 assert(nedges != NULL);
    900 assert(sepadata->minaggrsize <= sepadata->maxaggrsize);
    901
    902 expr = SCIPnlrowGetExpr(nlrow);
    903 SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, &nquadexprs, &nbilinexprs, NULL, NULL);
    904
    905 nnodes = nquadexprs;
    906 *nedges = 0;
    907 *narcs = 0;
    908
    909 assert(nnodes > 0);
    910
    911 noddcyclearcs = 0;
    912 SCIP_CALL( SCIPallocBufferArray(subscip, &oddcyclearcs, 2*nbilinexprs) );
    913
    914 /* create problem with default plug-ins */
    915 SCIP_CALL( SCIPcreateProbBasic(subscip, "E.C. aggregation MIP") );
    918
    919 /* create forward and backward arc variables */
    920 for( i = 0; i < nquadexprs; ++i )
    921 {
    922 SCIP_EXPR* qterm;
    923 SCIP_Real coef;
    924 int nadjbilin;
    925 int* adjbilin;
    926 int j;
    927
    928 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, &coef, &nadjbilin, &adjbilin, NULL);
    929
    930 if( !SCIPisZero(scip, coef) )
    931 {
    932 /* squares (loops) are fixed to zero */
    933 SCIPdebugMsg(scip, "edge {%d,%d} = {%s,%s} coeff=%e edgeweight=0\n", i, i,
    935 coef);
    936
    937 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "x#%d#%d", i, i);
    938 SCIP_CALL( SCIPcreateVarBasic(subscip, &forwardarcs[*narcs], name, 0.0, 0.0, 0.01, SCIP_VARTYPE_BINARY) );
    939 SCIP_CALL( SCIPaddVar(subscip, forwardarcs[*narcs]) );
    940
    941 SCIP_CALL( SCIPcreateVarBasic(subscip, &backwardarcs[*narcs], name, 0.0, 0.0, 0.01, SCIP_VARTYPE_BINARY) );
    942 SCIP_CALL( SCIPaddVar(subscip, backwardarcs[*narcs]) );
    943
    944 ++*narcs;
    945 }
    946
    947 for( j = 0 ; j < nadjbilin; ++j )
    948 {
    949 SCIP_EXPR* qterm1;
    950 SCIP_EXPR* qterm2;
    951 int pos2;
    952 SCIP_Real edgeweight;
    953 SCIP_CONS* noparallelcons;
    954
    955 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &qterm1, &qterm2, &coef, &pos2, NULL);
    956
    957 /* handle qterm == qterm2 later */
    958 if( qterm1 != qterm )
    959 continue;
    960
    961 edgeweight = nodeweights[i] + nodeweights[pos2];
    962 SCIPdebugMsg(scip, "edge {%d,%d} = {%s,%s} coeff=%e edgeweight=%e\n", i, pos2,
    964 coef, edgeweight);
    965
    966 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "x#%d#%d", i, pos2);
    967 SCIP_CALL( SCIPcreateVarBasic(subscip, &forwardarcs[*narcs], name, 0.0, 1.0, 0.01 + edgeweight, SCIP_VARTYPE_BINARY) );
    968 SCIP_CALL( SCIPaddVar(subscip, forwardarcs[*narcs]) );
    969
    970 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "x#%d#%d", i, pos2);
    971 SCIP_CALL( SCIPcreateVarBasic(subscip, &backwardarcs[*narcs], name, 0.0, 1.0, 0.01 + edgeweight, SCIP_VARTYPE_BINARY) );
    972 SCIP_CALL( SCIPaddVar(subscip, backwardarcs[*narcs]) );
    973
    974 ++(*nedges);
    975
    976 /* store all arcs which are important for the odd cycle property (no loops) */
    977 if( rhsaggr && SCIPisPositive(scip, coef) )
    978 {
    979 assert(noddcyclearcs < 2*nbilinexprs-1);
    980 oddcyclearcs[noddcyclearcs++] = forwardarcs[i];
    981 oddcyclearcs[noddcyclearcs++] = backwardarcs[i];
    982 }
    983
    984 if( !rhsaggr && SCIPisNegative(scip, coef) )
    985 {
    986 assert(noddcyclearcs < 2*nbilinexprs-1);
    987 oddcyclearcs[noddcyclearcs++] = forwardarcs[i];
    988 oddcyclearcs[noddcyclearcs++] = backwardarcs[i];
    989 }
    990
    991 /* add constraints to ensure no parallel edges */
    992 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "cons_noparalleledges");
    993 SCIP_CALL( SCIPcreateConsBasicLinear(subscip, &noparallelcons, name, 0, NULL, NULL, 0.0, 1.0) );
    994 SCIP_CALL( SCIPaddCoefLinear(subscip, noparallelcons, forwardarcs[*narcs], 1.0) );
    995 SCIP_CALL( SCIPaddCoefLinear(subscip, noparallelcons, backwardarcs[*narcs], 1.0) );
    996 SCIP_CALL( SCIPaddCons(subscip, noparallelcons) );
    997 SCIP_CALL( SCIPreleaseCons(subscip, &noparallelcons) );
    998
    999 ++*narcs;
    1000 }
    1001 }
    1002 assert(*narcs > 0);
    1003
    1004 /* odd cycle property constraint */
    1005 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "cons_oddcycle");
    1006 SCIP_CALL( SCIPcreateConsBasicXor(subscip, &oddcyclecons, name, TRUE, noddcyclearcs, oddcyclearcs) );
    1007 SCIP_CALL( SCIPaddCons(subscip, oddcyclecons) );
    1008 SCIP_CALL( SCIPreleaseCons(subscip, &oddcyclecons) );
    1009 SCIPfreeBufferArray(subscip, &oddcyclearcs);
    1010
    1011 /* cycle length constraint */
    1012 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "cons_cyclelength");
    1013 SCIP_CALL( SCIPcreateConsBasicLinear(subscip, &cyclelengthcons, name, 0, NULL, NULL,
    1014 (SCIP_Real) sepadata->minaggrsize, (SCIP_Real) sepadata->maxaggrsize) );
    1015
    1016 for( i = 0; i < *narcs; ++i )
    1017 {
    1018 SCIP_CALL( SCIPaddCoefLinear(subscip, cyclelengthcons, forwardarcs[i], 1.0) );
    1019 SCIP_CALL( SCIPaddCoefLinear(subscip, cyclelengthcons, backwardarcs[i], 1.0) );
    1020 }
    1021
    1022 SCIP_CALL( SCIPaddCons(subscip, cyclelengthcons) );
    1023 SCIP_CALL( SCIPreleaseCons(subscip, &cyclelengthcons) );
    1024
    1025 /* create flow conservation constraints */
    1026 SCIP_CALL( SCIPallocBufferArray(subscip, &flowcons, nnodes) );
    1027
    1028 for( i = 0; i < nnodes; ++i )
    1029 {
    1030 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "cons_flowconservation#%d", i);
    1031 SCIP_CALL( SCIPcreateConsBasicLinear(subscip, &flowcons[i], name, 0, NULL, NULL, 0.0, 0.0) );
    1032 }
    1033
    1034 arcidx = 0;
    1035 for( i = 0; i < nquadexprs; ++i )
    1036 {
    1037 SCIP_EXPR* qterm;
    1038 SCIP_Real coef;
    1039 int nadjbilin;
    1040 int* adjbilin;
    1041 int j;
    1042
    1043 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, &coef, &nadjbilin, &adjbilin, NULL);
    1044
    1045 if( !SCIPisZero(scip, coef) )
    1046 ++arcidx;
    1047
    1048 for( j = 0 ; j < nadjbilin; ++j )
    1049 {
    1050 SCIP_EXPR* qterm1;
    1051 int pos2;
    1052
    1053 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &qterm1, NULL, NULL, &pos2, NULL);
    1054
    1055 /* handle qterm == qterm2 later */
    1056 if( qterm1 != qterm )
    1057 continue;
    1058
    1059 SCIP_CALL( SCIPaddCoefLinear(subscip, flowcons[i], forwardarcs[arcidx], 1.0) );
    1060 SCIP_CALL( SCIPaddCoefLinear(subscip, flowcons[i], backwardarcs[arcidx], -1.0) );
    1061
    1062 SCIP_CALL( SCIPaddCoefLinear(subscip, flowcons[pos2], forwardarcs[arcidx], -1.0) );
    1063 SCIP_CALL( SCIPaddCoefLinear(subscip, flowcons[pos2], backwardarcs[arcidx], 1.0) );
    1064
    1065 ++arcidx;
    1066 }
    1067 }
    1068 assert(arcidx == *narcs);
    1069
    1070 for( i = 0; i < nnodes; ++i )
    1071 {
    1072 SCIP_CALL( SCIPaddCons(subscip, flowcons[i]) );
    1073 SCIP_CALL( SCIPreleaseCons(subscip, &flowcons[i]) );
    1074 }
    1075
    1076 SCIPfreeBufferArray(subscip, &flowcons);
    1077
    1078 return SCIP_OKAY;
    1079}
    1080
    1081/** fixed all arc variables (u,v) for which u or v is already in an edge-concave aggregation */
    1082static
    1084 SCIP* subscip, /**< auxiliary SCIP to search aggregations */
    1085 SCIP_NLROW* nlrow, /**< nonlinear row */
    1086 SCIP_VAR** forwardarcs, /**< forward arc variables */
    1087 SCIP_VAR** backwardarcs, /**< backward arc variables */
    1088 int* quadvar2aggr, /**< mapping of quadvars to e.c. aggr. index (< 0: in no aggr.) */
    1089 int* nedges /**< pointer to store the number of nonexcluded edges */
    1090 )
    1091{
    1092 SCIP_EXPR* expr;
    1093 int nquadexprs;
    1094 int arcidx;
    1095 int i;
    1096
    1097 assert(subscip != NULL);
    1098 assert(nlrow != NULL);
    1099 assert(forwardarcs != NULL);
    1100 assert(backwardarcs != NULL);
    1101 assert(quadvar2aggr != NULL);
    1102 assert(nedges != NULL);
    1103
    1104 SCIP_CALL( SCIPfreeTransform(subscip) );
    1105
    1106 /* recompute the number of edges */
    1107 *nedges = 0;
    1108
    1109 expr = SCIPnlrowGetExpr(nlrow);
    1110 SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, NULL, NULL);
    1111
    1112 /* fix each arc to 0 if at least one of its nodes is contained in an e.c. aggregation */
    1113 arcidx = 0;
    1114 for( i = 0; i < nquadexprs; ++i )
    1115 {
    1116 SCIP_EXPR* qterm;
    1117 SCIP_Real coef;
    1118 int nadjbilin;
    1119 int* adjbilin;
    1120 int j;
    1121
    1122 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, &coef, &nadjbilin, &adjbilin, NULL);
    1123
    1124 if( !SCIPisZero(subscip, coef) )
    1125 {
    1126 if( quadvar2aggr[i] != -1 )
    1127 {
    1128 SCIP_CALL( SCIPchgVarUb(subscip, forwardarcs[arcidx], 0.0) );
    1129 SCIP_CALL( SCIPchgVarUb(subscip, backwardarcs[arcidx], 0.0) );
    1130 }
    1131 ++arcidx;
    1132 }
    1133
    1134 for( j = 0 ; j < nadjbilin; ++j )
    1135 {
    1136 SCIP_EXPR* qterm1;
    1137 int pos2;
    1138
    1139 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &qterm1, NULL, NULL, &pos2, NULL);
    1140
    1141 /* handle qterm == qterm2 later */
    1142 if( qterm1 != qterm )
    1143 continue;
    1144
    1145 if( quadvar2aggr[i] != -1 || quadvar2aggr[pos2] != -1 )
    1146 {
    1147 SCIP_CALL( SCIPchgVarUb(subscip, forwardarcs[arcidx], 0.0) );
    1148 SCIP_CALL( SCIPchgVarUb(subscip, backwardarcs[arcidx], 0.0) );
    1149 }
    1150 else
    1151 ++*nedges;
    1152
    1153 ++arcidx;
    1154 }
    1155 }
    1156
    1157 return SCIP_OKAY;
    1158}
    1159
    1160/** stores the best edge-concave aggregation found by the MIP model */
    1161static
    1163 SCIP* subscip, /**< auxiliary SCIP to search aggregations */
    1164 SCIP_NLROW* nlrow, /**< nonlinear row */
    1165 SCIP_VAR** forwardarcs, /**< forward arc variables */
    1166 SCIP_VAR** backwardarcs, /**< backward arc variables */
    1167 int* quadvar2aggr, /**< mapping of quadvars to e.c. aggr. index (< 0: in no aggr.) */
    1168 int nfoundsofar /**< number of e.c. aggregation found so far */
    1169 )
    1170{
    1171 SCIP_SOL* sol;
    1172 SCIP_EXPR* expr;
    1173 int nquadexprs;
    1174 int arcidx;
    1175 int i;
    1176
    1177 assert(subscip != NULL);
    1178 assert(nlrow != NULL);
    1179 assert(forwardarcs != NULL);
    1180 assert(backwardarcs != NULL);
    1181 assert(quadvar2aggr != NULL);
    1182 assert(nfoundsofar >= 0);
    1183 assert(SCIPgetStatus(subscip) != SCIP_STATUS_INFEASIBLE);
    1184 assert(SCIPgetStatus(subscip) != SCIP_STATUS_UNBOUNDED);
    1185 assert(SCIPgetStatus(subscip) != SCIP_STATUS_INFORUNBD);
    1186 assert(SCIPgetNSols(subscip) > 0);
    1187
    1188 sol = SCIPgetBestSol(subscip);
    1189 assert(sol != NULL);
    1190
    1191 expr = SCIPnlrowGetExpr(nlrow);
    1192 SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, NULL, NULL);
    1193
    1194 /* fix each arc to 0 if at least one of its nodes is contained in an e.c. aggregation */
    1195 arcidx = 0;
    1196 for( i = 0; i < nquadexprs; ++i )
    1197 {
    1198 SCIP_EXPR* qterm;
    1199 SCIP_Real coef;
    1200 int nadjbilin;
    1201 int* adjbilin;
    1202 int j;
    1203
    1204 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, &coef, &nadjbilin, &adjbilin, NULL);
    1205
    1206 if( !SCIPisZero(subscip, coef) )
    1207 {
    1208 if( SCIPisGT(subscip, SCIPgetSolVal(subscip, sol, forwardarcs[arcidx]), 0.5) ||
    1209 SCIPisGT(subscip, SCIPgetSolVal(subscip, sol, backwardarcs[arcidx]), 0.5) )
    1210 {
    1211 assert(quadvar2aggr[i] == -1 || quadvar2aggr[i] == nfoundsofar);
    1212 quadvar2aggr[i] = nfoundsofar;
    1213 }
    1214
    1215 ++arcidx;
    1216 }
    1217
    1218 for( j = 0; j < nadjbilin; ++j )
    1219 {
    1220 SCIP_EXPR* qterm1;
    1221 int pos2;
    1222
    1223 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &qterm1, NULL, NULL, &pos2, NULL);
    1224
    1225 /* handle qterm == qterm2 later */
    1226 if( qterm1 != qterm )
    1227 continue;
    1228
    1229 if( SCIPisGT(subscip, SCIPgetSolVal(subscip, sol, forwardarcs[arcidx]), 0.5) ||
    1230 SCIPisGT(subscip, SCIPgetSolVal(subscip, sol, backwardarcs[arcidx]), 0.5) )
    1231 {
    1232 assert(quadvar2aggr[i] == -1 || quadvar2aggr[i] == nfoundsofar);
    1233 assert(quadvar2aggr[pos2] == -1 || quadvar2aggr[pos2] == nfoundsofar);
    1234
    1235 quadvar2aggr[i] = nfoundsofar;
    1236 quadvar2aggr[pos2] = nfoundsofar;
    1237 }
    1238
    1239 ++arcidx;
    1240 }
    1241 }
    1242
    1243 return SCIP_OKAY;
    1244}
    1245
    1246/** searches for edge-concave aggregations with a MIP model based on binary flow variables */
    1247static
    1249 SCIP* subscip, /**< SCIP data structure */
    1250 SCIP_Real timelimit, /**< time limit to solve the MIP */
    1251 int nedges, /**< number of nonexcluded undirected edges */
    1252 SCIP_Bool* aggrleft, /**< pointer to store if there might be a left aggregation */
    1253 SCIP_Bool* found /**< pointer to store if we have found an aggregation */
    1254 )
    1255{
    1256 assert(subscip != NULL);
    1257 assert(aggrleft != NULL);
    1258 assert(found != NULL);
    1259 assert(nedges >= 0);
    1260
    1261 *aggrleft = TRUE;
    1262 *found = FALSE;
    1263
    1264 if( SCIPisLE(subscip, timelimit, 0.0) )
    1265 return SCIP_OKAY;
    1266
    1267 /* set working limits */
    1268 SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
    1269 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/totalnodes", SUBSCIP_NODELIMIT) );
    1270
    1271 /* set heuristics to aggressive */
    1273
    1274 /* disable output to console in optimized mode, enable in SCIP's debug mode */
    1275#ifdef SCIP_DEBUG
    1276 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 5) );
    1277 SCIP_CALL( SCIPsetIntParam(subscip, "display/freq", 1) );
    1278#else
    1279 SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
    1280#endif
    1281
    1282 SCIP_CALL( SCIPsolve(subscip) );
    1283
    1284 /* no more aggregation left if the MIP is infeasible */
    1285 if( SCIPgetStatus(subscip) == SCIP_STATUS_INFEASIBLE )
    1286 {
    1287 *found = FALSE;
    1288 *aggrleft = FALSE;
    1289 return SCIP_OKAY;
    1290 }
    1291
    1292 if( SCIPgetNSols(subscip) > 0 )
    1293 {
    1294 *found = TRUE;
    1295 *aggrleft = TRUE;
    1296
    1297#ifdef SCIP_DEBUG
    1298 if( SCIPgetNSols(subscip) > 0 )
    1299 {
    1300 SCIP_CALL( SCIPprintSol(subscip, SCIPgetBestSol(subscip), NULL , FALSE) );
    1301 }
    1302#endif
    1303 }
    1304
    1305 return SCIP_OKAY;
    1306}
    1307
    1308/** creates a tclique graph from a given nonlinear row
    1309 *
    1310 * SCIP's clique code can only handle integer node weights; all node weights are scaled by a factor of 100; since the
    1311 * clique code ignores nodes with weight of zero, we add an offset of 100 to each weight
    1312 */
    1313static
    1315 SCIP_NLROW* nlrow, /**< nonlinear row */
    1316 TCLIQUE_GRAPH** graph, /**< TCLIQUE graph structure */
    1317 SCIP_Real* nodeweights /**< weights for each quadratic variable (nodes in the graph) */
    1318 )
    1319{
    1320 SCIP_EXPR* expr;
    1321 int nquadexprs;
    1322 int i;
    1323
    1324 assert(graph != NULL);
    1325 assert(nlrow != NULL);
    1326
    1327 /* create the tclique graph */
    1328 if( !tcliqueCreate(graph) )
    1329 {
    1330 SCIPerrorMessage("could not create clique graph\n");
    1331 return SCIP_ERROR;
    1332 }
    1333
    1334 expr = SCIPnlrowGetExpr(nlrow);
    1335 SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, NULL, NULL);
    1336
    1337 /* add all nodes to the tclique graph */
    1338 for( i = 0; i < nquadexprs; ++i )
    1339 {
    1340 int nodeweight;
    1341
    1342 /* note: clique code can only handle integer weights */
    1343 nodeweight = 100 + (int)(100 * nodeweights[i]);
    1344 /* SCIPdebugMsg(scip, "%d (%s): nodeweight %d \n", i, SCIPvarGetName(SCIPnlrowGetQuadVars(nlrow)[i]), nodeweight); */
    1345
    1346 if( !tcliqueAddNode(*graph, i, nodeweight) )
    1347 {
    1348 SCIPerrorMessage("could not add node to clique graph\n");
    1349 return SCIP_ERROR;
    1350 }
    1351 }
    1352
    1353 /* add all edges */
    1354 for( i = 0; i < nquadexprs; ++i )
    1355 {
    1356 SCIP_EXPR* qterm;
    1357 int nadjbilin;
    1358 int* adjbilin;
    1359 int j;
    1360
    1361 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, NULL, &nadjbilin, &adjbilin, NULL);
    1362
    1363 for( j = 0; j < nadjbilin; ++j )
    1364 {
    1365 SCIP_EXPR* qterm1;
    1366 SCIP_EXPR* qterm2;
    1367 int pos2;
    1368
    1369 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &qterm1, &qterm2, NULL, &pos2, NULL);
    1370
    1371 /* handle qterm == qterm2 later */
    1372 if( qterm1 != qterm )
    1373 continue;
    1374
    1375#ifdef SCIP_DEBUG_DETAILED
    1376 SCIPdebugMessage(" add edge (%d, %d) = (%s,%s) to tclique graph\n",
    1379#endif
    1380
    1381 if( !tcliqueAddEdge(*graph, i, pos2) )
    1382 {
    1383 SCIPerrorMessage("could not add edge to clique graph\n");
    1384 return SCIP_ERROR;
    1385 }
    1386 }
    1387 }
    1388
    1389 /* flush the clique graph */
    1390 if( !tcliqueFlush(*graph) )
    1391 {
    1392 SCIPerrorMessage("could not flush the clique graph\n");
    1393 return SCIP_ERROR;
    1394 }
    1395
    1396 return SCIP_OKAY;
    1397}
    1398
    1399/** searches for edge-concave aggregations by computing cliques in the graph representation of a given nonlinear row
    1400 *
    1401 * update graph, compute clique, store clique; after computing a clique we heuristically check if the clique contains
    1402 * at least one good cycle
    1403 */
    1404static
    1406 SCIP* scip, /**< SCIP data structure */
    1407 TCLIQUE_GRAPH* graph, /**< TCLIQUE graph structure */
    1408 SCIP_SEPADATA* sepadata, /**< separator data */
    1409 SCIP_NLROW* nlrow, /**< nonlinear row */
    1410 int* quadvar2aggr, /**< mapping of quadvars to e.c. aggr. index (< 0: in no aggr.) */
    1411 int nfoundsofar, /**< number of e.c. aggregation found so far */
    1412 SCIP_Bool rhsaggr, /**< consider nonlinear row aggregation for g(x) <= rhs (TRUE) or
    1413 * lhs <= g(x) (FALSE) */
    1414 SCIP_Bool* foundaggr, /**< pointer to store if we have found an aggregation */
    1415 SCIP_Bool* foundclique /**< pointer to store if we have found a clique */
    1416 )
    1417{
    1418 SCIP_HASHMAP* cliquemap;
    1419 TCLIQUE_STATUS status;
    1420 SCIP_EXPR* expr;
    1421 int nquadexprs;
    1422 int* maxcliquenodes;
    1423 int* degrees;
    1424 int nmaxcliquenodes;
    1425 int maxcliqueweight;
    1426 int noddcycleedges;
    1427 int ntwodegrees;
    1428 int aggrsize;
    1429 int i;
    1430
    1431 assert(graph != NULL);
    1432 assert(nfoundsofar >= 0);
    1433 assert(foundaggr != NULL);
    1434 assert(foundclique != NULL);
    1435
    1436 cliquemap = NULL;
    1437 *foundaggr = FALSE;
    1438 *foundclique = FALSE;
    1439
    1440 expr = SCIPnlrowGetExpr(nlrow);
    1441 SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, NULL, NULL);
    1442 assert(nquadexprs == tcliqueGetNNodes(graph));
    1443
    1444 /* exclude all nodes which are already in an edge-concave aggregation (no flush is needed) */
    1445 for( i = 0; i < nquadexprs; ++i )
    1446 {
    1447 if( quadvar2aggr[i] != -1 )
    1448 {
    1449 SCIPdebugMsg(scip, "exclude node %d from clique graph\n", i);
    1450 tcliqueChangeWeight(graph, i, 0);
    1451 }
    1452 }
    1453
    1454 SCIP_CALL( SCIPallocBufferArray(scip, &maxcliquenodes, nquadexprs) );
    1455
    1456 /* solve clique problem */
    1457 tcliqueMaxClique(tcliqueGetNNodes, tcliqueGetWeights, tcliqueIsEdge, tcliqueSelectAdjnodes, graph, NULL, NULL,
    1458 maxcliquenodes, &nmaxcliquenodes, &maxcliqueweight, CLIQUE_MAXFIRSTNODEWEIGHT, CLIQUE_MINWEIGHT,
    1460
    1461 if( status != TCLIQUE_OPTIMAL || nmaxcliquenodes < sepadata->minaggrsize )
    1462 goto TERMINATE;
    1463
    1464 *foundclique = TRUE;
    1465 aggrsize = MIN(sepadata->maxaggrsize, nmaxcliquenodes);
    1466 SCIP_CALL( SCIPhashmapCreate(&cliquemap, SCIPblkmem(scip), aggrsize) );
    1467
    1468 for( i = 0; i < aggrsize; ++i )
    1469 {
    1470 SCIP_CALL( SCIPhashmapInsertInt(cliquemap, (void*) (size_t) maxcliquenodes[i], 0) ); /*lint !e571*/
    1471 }
    1472
    1473 /* count the degree of good cycle edges for each node in the clique */
    1474 SCIP_CALL( SCIPallocBufferArray(scip, &degrees, aggrsize) );
    1475 BMSclearMemoryArray(degrees, aggrsize);
    1476 ntwodegrees = 0;
    1477
    1478 /* count the number of positive or negative edges (depending on <= rhs or >= lhs) */
    1479 noddcycleedges = 0;
    1480 for( i = 0; i < nquadexprs; ++i )
    1481 {
    1482 SCIP_Bool isoddcycleedge;
    1483 SCIP_EXPR* qterm;
    1484 SCIP_Real coef;
    1485 int nadjbilin;
    1486 int* adjbilin;
    1487 int j;
    1488
    1489 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, &coef, &nadjbilin, &adjbilin, NULL);
    1490
    1491 isoddcycleedge = (rhsaggr && SCIPisPositive(scip, coef)) || (!rhsaggr && SCIPisNegative(scip, coef));
    1492
    1493 if( isoddcycleedge && SCIPhashmapExists(cliquemap, (void*) (size_t) i) )
    1494 {
    1495 ++noddcycleedges;
    1496 ++degrees[i];
    1497 }
    1498
    1499 for( j = 0; j < nadjbilin; ++j )
    1500 {
    1501 SCIP_EXPR* qterm1;
    1502 SCIP_EXPR* qterm2;
    1503 int pos2;
    1504
    1505 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &qterm1, &qterm2, &coef, &pos2, NULL);
    1506
    1507 /* handle qterm == qterm2 later */
    1508 if( qterm1 != qterm )
    1509 continue;
    1510
    1511 isoddcycleedge = (rhsaggr && SCIPisPositive(scip, coef)) || (!rhsaggr && SCIPisNegative(scip, coef));
    1512
    1513 if( isoddcycleedge
    1514 && SCIPhashmapExists(cliquemap, (void*) (size_t) i)
    1515 && SCIPhashmapExists(cliquemap, (void*) (size_t) pos2) )
    1516 {
    1517 ++noddcycleedges;
    1518 ++degrees[i];
    1519 ++degrees[pos2];
    1520 }
    1521 }
    1522 }
    1523
    1524 /* count the number of nodes with exactly two incident odd cycle edges */
    1525 for( i = 0; i < aggrsize; ++i )
    1526 if( degrees[i] == 2 )
    1527 ++ntwodegrees;
    1528
    1529 /* check cases for which we are sure that there are no good cycles in the clique */
    1530 if( noddcycleedges == 0 || (aggrsize == 3 && noddcycleedges == 2) || (aggrsize == 4 && ntwodegrees == 4) )
    1531 *foundaggr = FALSE;
    1532 else
    1533 *foundaggr = TRUE;
    1534
    1535 /* add the found clique as an edge-concave aggregation or exclude the nodes from the remaining search */
    1536 for( i = 0; i < aggrsize; ++i )
    1537 {
    1538 quadvar2aggr[ maxcliquenodes[i] ] = *foundaggr ? nfoundsofar : -2;
    1539 SCIPdebugMsg(scip, "%s %d\n", *foundaggr ? "aggregate node: " : "exclude node: ", maxcliquenodes[i]);
    1540 }
    1541
    1542 SCIPfreeBufferArray(scip, &degrees);
    1543
    1544TERMINATE:
    1545 if( cliquemap != NULL )
    1546 SCIPhashmapFree(&cliquemap);
    1547 SCIPfreeBufferArray(scip, &maxcliquenodes);
    1548
    1549 return SCIP_OKAY;
    1550}
    1551
    1552/** helper function for searchEcAggr() */
    1553static
    1555 SCIP* scip, /**< SCIP data structure */
    1556 SCIP* subscip, /**< sub-SCIP data structure */
    1557 SCIP_SEPADATA* sepadata, /**< separator data */
    1558 SCIP_NLROW* nlrow, /**< nonlinear row */
    1559 SCIP_SOL* sol, /**< current solution (might be NULL) */
    1560 SCIP_Bool rhsaggr, /**< consider nonlinear row aggregation for g(x) <= rhs (TRUE) or g(x) >= lhs (FALSE) */
    1561 int* quadvar2aggr, /**< array to store for each quadratic variable in which edge-concave
    1562 * aggregation it is stored (< 0: in no aggregation); size has to be at
    1563 * least SCIPnlrowGetNQuadVars(nlrow) */
    1564 int* nfound /**< pointer to store the number of found e.c. aggregations */
    1565 )
    1566{
    1567 TCLIQUE_GRAPH* graph = NULL;
    1568 SCIP_EXPR* expr;
    1569 SCIP_VAR** forwardarcs;
    1570 SCIP_VAR** backwardarcs;
    1571 SCIP_Real* nodeweights;
    1572 SCIP_Real timelimit;
    1573 SCIP_RETCODE retcode;
    1574 int nunsucces = 0;
    1575 int nedges = 0;
    1576 int narcs;
    1577 int nquadvars;
    1578 int nbilinexprs;
    1579 int i;
    1580
    1581 assert(subscip != NULL);
    1582 assert(quadvar2aggr != NULL);
    1583 assert(nfound != NULL);
    1584
    1585 expr = SCIPnlrowGetExpr(nlrow);
    1586 SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, &nquadvars, &nbilinexprs, NULL, NULL);
    1587
    1588 retcode = SCIP_OKAY;
    1589 *nfound = 0;
    1590
    1591 /* arrays to store all arc variables of the MIP model; note that we introduce variables even for loops in the graph
    1592 * to have an easy mapping from the edges of the graph to the quadratic elements
    1593 * nquadvars + nbilinexprs is an upper bound on the actual number of square and bilinear terms
    1594 */
    1595 SCIP_CALL( SCIPallocBufferArray(scip, &nodeweights, nquadvars) );
    1596 SCIP_CALL( SCIPallocBufferArray(scip, &forwardarcs, nquadvars + nbilinexprs) );
    1597 SCIP_CALL( SCIPallocBufferArray(scip, &backwardarcs, nquadvars + nbilinexprs) );
    1598
    1599 /* initialize mapping from quadvars to e.c. aggregation index (-1: quadvar is in no aggregation); compute node
    1600 * weights
    1601 */
    1602 for( i = 0; i < nquadvars; ++i )
    1603 {
    1604 SCIP_EXPR* qterm;
    1605 SCIP_VAR* var;
    1606
    1607 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, NULL, NULL, NULL, NULL);
    1608 assert(SCIPisExprVar(scip, qterm));
    1609 var = SCIPgetVarExprVar(qterm);
    1610
    1611 quadvar2aggr[i] = -1;
    1612 nodeweights[i] = phi(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
    1613 SCIPdebugMsg(scip, "%s = %e (%e in [%e, %e])\n", SCIPvarGetName(var), nodeweights[i], SCIPgetSolVal(scip, sol, var),
    1615 }
    1616
    1617 SCIP_CALL( createMIP(scip, subscip, sepadata, nlrow, rhsaggr, forwardarcs, backwardarcs, nodeweights, &nedges, &narcs) );
    1618 assert(nedges >= 0);
    1619 assert(narcs > 0);
    1620 SCIPdebugMsg(scip, "nedges (without loops) = %d\n", nedges);
    1621 SCIPdebugMsg(scip, "narcs (number of quadratic terms) = %d\n", narcs);
    1622
    1623 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
    1624
    1625 /* main loop to search for edge-concave aggregations */
    1626 while( !SCIPisStopped(scip) )
    1627 {
    1628 SCIP_Bool aggrleft;
    1629 SCIP_Bool found;
    1630
    1631 SCIPdebugMsg(scip, "#remaining edges = %d\n", nedges);
    1632
    1633 /* not enough edges left */
    1634 if( nedges < sepadata->minaggrsize )
    1635 break;
    1636
    1637 /* check whether there is enough time left; update the remaining time */
    1638 if( !SCIPisInfinity(scip, timelimit) )
    1639 {
    1640 timelimit -= SCIPgetSolvingTime(scip);
    1641 if( timelimit <= 0.0 )
    1642 {
    1643 SCIPdebugMsg(scip, "skip aggregation search since no time left\n");
    1644 goto TERMINATE;
    1645 }
    1646 }
    1647
    1648 /* 1.a - search for edge-concave aggregation with the help of the MIP model */
    1649 SCIP_CALL( searchEcAggrWithMIP(subscip, timelimit, nedges, &aggrleft, &found) );
    1650
    1651 /* 1.b - there are no more edge-concave aggregations left */
    1652 if( !aggrleft )
    1653 {
    1654 SCIPdebugMsg(scip, "no more aggregation left\n");
    1655 break;
    1656 }
    1657
    1658 if( found )
    1659 {
    1660 SCIP_CALL( storeAggrFromMIP(subscip, nlrow, forwardarcs, backwardarcs, quadvar2aggr, *nfound) );
    1661 ++(*nfound);
    1662 nunsucces = 0;
    1663 }
    1664 /* try to find an edge-concave aggregation by computing cliques */
    1665 else
    1666 {
    1667 SCIP_Bool foundaggr;
    1668 SCIP_Bool foundclique;
    1669
    1670 ++nunsucces;
    1671
    1672 /* create graph if necessary */
    1673 if( graph == NULL )
    1674 {
    1675 SCIP_CALL_TERMINATE( retcode, createTcliqueGraph(nlrow, &graph, nodeweights), TERMINATE );
    1676 }
    1677
    1678 /* 2.a - search and store a single edge-concave aggregation by computing a clique with a good cycle */
    1679 SCIP_CALL_FINALLY( searchEcAggrWithCliques(scip, graph, sepadata, nlrow, quadvar2aggr, *nfound, rhsaggr,
    1680 &foundaggr, &foundclique), tcliqueFree(&graph) );
    1681
    1682 if( foundaggr )
    1683 {
    1684 assert(foundclique);
    1685 ++(*nfound);
    1686 nunsucces = 0;
    1687 }
    1688 else
    1689 ++nunsucces;
    1690
    1691 /* 2.b - no clique of at least minaggrsize size found */
    1692 if( !foundclique )
    1693 {
    1694 assert(!foundaggr);
    1695 SCIPdebugMsg(scip, "did not find a clique to exclude -> leave aggregation search\n");
    1696 break;
    1697 }
    1698 }
    1699
    1700 /* leave the algorithm if we did not find something for maxstallrounds many iterations */
    1701 if( nunsucces >= sepadata->maxstallrounds && *nfound == 0 )
    1702 {
    1703 SCIPdebugMsg(scip, "did not find an e.c. aggregation for %d iterations\n", nunsucces);
    1704 break;
    1705 }
    1706
    1707 /* exclude all edges used in the last aggregation and nodes found in the clique solution */
    1708 SCIP_CALL_FINALLY( updateMIP(subscip, nlrow, forwardarcs, backwardarcs, quadvar2aggr, &nedges), tcliqueFree(&graph) );
    1709 }
    1710
    1711TERMINATE:
    1712
    1713#ifdef SCIP_DEBUG
    1714 SCIPdebugMsg(scip, "aggregations found:\n");
    1715 for( i = 0; i < nquadvars; ++i )
    1716 {
    1717 SCIPdebugMsg(scip, " %d in %d\n", i, quadvar2aggr[i]);
    1718 }
    1719#endif
    1720
    1721 /* free clique graph */
    1722 if( graph != NULL )
    1723 tcliqueFree(&graph);
    1724
    1725 /* free sub-SCIP */
    1726 for( i = 0; i < narcs; ++i )
    1727 {
    1728 SCIP_CALL( SCIPreleaseVar(subscip, &forwardarcs[i]) );
    1729 SCIP_CALL( SCIPreleaseVar(subscip, &backwardarcs[i]) );
    1730 }
    1731
    1732 SCIPfreeBufferArray(scip, &backwardarcs);
    1733 SCIPfreeBufferArray(scip, &forwardarcs);
    1734 SCIPfreeBufferArray(scip, &nodeweights);
    1735
    1736 return retcode;
    1737}
    1738
    1739/** computes a partitioning into edge-concave aggregations for a given (quadratic) nonlinear row
    1740 *
    1741 * Each aggregation has to contain a cycle with an odd number of positive weighted edges (good cycles) in the corresponding graph representation.
    1742 * For this we use the following algorithm:
    1743 * -# use a MIP model based on binary flow variables to compute good cycles and store the implied subgraphs as an e.c. aggr.
    1744 * -# if we find a good cycle, store the implied subgraph, delete it from the graph representation and go to 1)
    1745 * -# if the MIP model is infeasible (there are no good cycles), STOP
    1746 * -# we compute a large clique C if the MIP model fails (because of working limits, etc)
    1747 * -# if we find a good cycle in C, store the implied subgraph of C, delete it from the graph representation and go to 1)
    1748 * -# if C is not large enough, STOP
    1749 */
    1750static
    1752 SCIP* scip, /**< SCIP data structure */
    1753 SCIP_SEPADATA* sepadata, /**< separator data */
    1754 SCIP_NLROW* nlrow, /**< nonlinear row */
    1755 SCIP_SOL* sol, /**< current solution (might be NULL) */
    1756 SCIP_Bool rhsaggr, /**< consider nonlinear row aggregation for g(x) <= rhs (TRUE) or g(x) >= lhs (FALSE) */
    1757 int* quadvar2aggr, /**< array to store for each quadratic variable in which edge-concave
    1758 * aggregation it is stored (< 0: in no aggregation); size has to be at
    1759 * least SCIPnlrowGetNQuadVars(nlrow) */
    1760 int* nfound /**< pointer to store the number of found e.c. aggregations */
    1761 )
    1762{
    1763 SCIP* subscip;
    1764 SCIP_RETCODE retcode;
    1765
    1766 /* create and set up a sub-SCIP */
    1767 SCIP_CALL_FINALLY( SCIPcreate(&subscip), (void)SCIPfree(&subscip) );
    1768
    1769 retcode = doSeachEcAggr(scip, subscip, sepadata, nlrow, sol, rhsaggr, quadvar2aggr, nfound);
    1770
    1771 SCIP_CALL( SCIPfree(&subscip) );
    1772 SCIP_CALL( retcode );
    1773
    1774 return SCIP_OKAY;
    1775}
    1776
    1777/** returns whether a given nonlinear row can be used to compute edge-concave aggregations for which their convex
    1778 * envelope could dominate the termwise bilinear relaxation
    1779 *
    1780 * This is the case if there exists at least one cycle with
    1781 * an odd number of positive edges in the corresponding graph representation of the nonlinear row.
    1782 */
    1783static
    1785 SCIP* scip, /**< SCIP data structure */
    1786 SCIP_SEPADATA* sepadata, /**< separator data */
    1787 SCIP_NLROW* nlrow, /**< nonlinear row representation of a nonlinear constraint */
    1788 SCIP_Bool* rhscandidate, /**< pointer to store if we should compute edge-concave aggregations for
    1789 * the <= rhs case */
    1790 SCIP_Bool* lhscandidate /**< pointer to store if we should compute edge-concave aggregations for
    1791 * the >= lhs case */
    1792 )
    1793{
    1794 SCIP_EXPR* expr = NULL;
    1795 SCIP_Bool takerow = FALSE;
    1796 int nquadvars = 0;
    1797 int* degrees;
    1798 int ninterestingnodes;
    1799 int nposedges;
    1800 int nnegedges;
    1801 int i;
    1802
    1803 assert(rhscandidate != NULL);
    1804 assert(lhscandidate != NULL);
    1805
    1806 *rhscandidate = TRUE;
    1807 *lhscandidate = TRUE;
    1808
    1809 /* check whether nlrow is in the NLP, is quadratic in variables, and there are enough quadratic variables */
    1810 if( SCIPnlrowIsInNLP(nlrow) && SCIPnlrowGetExpr(nlrow) != NULL )
    1811 {
    1812 expr = SCIPnlrowGetExpr(nlrow);
    1813 SCIP_CALL( SCIPcheckExprQuadratic(scip, expr, &takerow) );
    1814 }
    1815 if( takerow )
    1816 takerow = SCIPexprAreQuadraticExprsVariables(expr);
    1817 if( takerow )
    1818 {
    1819 SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, &nquadvars, NULL, NULL, NULL);
    1820 takerow = nquadvars >= sepadata->minaggrsize;
    1821 }
    1822 if( !takerow )
    1823 {
    1824 *rhscandidate = FALSE;
    1825 *lhscandidate = FALSE;
    1826 return SCIP_OKAY;
    1827 }
    1828
    1829 /* check for infinite rhs or lhs */
    1831 *rhscandidate = FALSE;
    1833 *lhscandidate = FALSE;
    1834
    1835 SCIP_CALL( SCIPallocClearBufferArray(scip, &degrees, nquadvars) );
    1836
    1837 ninterestingnodes = 0;
    1838 nposedges = 0;
    1839 nnegedges = 0;
    1840
    1841 for( i = 0; i < nquadvars; ++i )
    1842 {
    1843 SCIP_EXPR* qterm;
    1844 SCIP_VAR* var1;
    1845 int nadjbilin;
    1846 int* adjbilin;
    1847 int j;
    1848
    1849 SCIPexprGetQuadraticQuadTerm(expr, i, &qterm, NULL, NULL, &nadjbilin, &adjbilin, NULL);
    1850 assert(SCIPisExprVar(scip, qterm));
    1851
    1852 var1 = SCIPgetVarExprVar(qterm);
    1853
    1854 /* do not consider global fixed variables */
    1856 continue;
    1857
    1858 for( j = 0; j < nadjbilin; ++j )
    1859 {
    1860 SCIP_EXPR* qterm1;
    1861 SCIP_EXPR* qterm2;
    1862 SCIP_VAR* var2;
    1863 SCIP_Real coef;
    1864 int pos2;
    1865
    1866 SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &qterm1, &qterm2, &coef, &pos2, NULL);
    1867
    1868 if( qterm1 != qterm )
    1869 continue;
    1870
    1871 var2 = SCIPgetVarExprVar(qterm2);
    1872
    1873 /* do not consider loops or global fixed variables */
    1875 continue;
    1876
    1877 ++degrees[i];
    1878 ++degrees[pos2];
    1879
    1880 /* count the number of nodes with a degree of at least 2 */
    1881 if( degrees[i] == 2 )
    1882 ++ninterestingnodes;
    1883 if( degrees[pos2] == 2 )
    1884 ++ninterestingnodes;
    1885
    1886 nposedges += SCIPisPositive(scip, coef) ? 1 : 0;
    1887 nnegedges += SCIPisNegative(scip, coef) ? 1 : 0;
    1888 }
    1889 }
    1890
    1891 SCIPfreeBufferArray(scip, &degrees);
    1892
    1893 SCIPdebugMsg(scip, "nlrow contains: %d edges\n", nposedges + nnegedges);
    1894
    1895 /* too many edges, too few edges, or to few nodes with degree at least 2 in the graph */
    1896 if( nposedges + nnegedges > sepadata->maxbilinterms || nposedges + nnegedges < sepadata->minaggrsize
    1897 || ninterestingnodes < sepadata->minaggrsize )
    1898 {
    1899 *rhscandidate = FALSE;
    1900 *lhscandidate = FALSE;
    1901 return SCIP_OKAY;
    1902 }
    1903
    1904 /* check if there are enough positive/negative edges; for a 3-clique there has to be an odd number of those edges */
    1905 if( nposedges == 0 || (nposedges + nnegedges == 3 && (nposedges % 2) == 0) )
    1906 *rhscandidate = FALSE;
    1907 if( nnegedges == 0 || (nposedges + nnegedges == 3 && (nnegedges % 2) == 0) )
    1908 *lhscandidate = FALSE;
    1909
    1910 return SCIP_OKAY;
    1911}
    1912
    1913/** finds and stores edge-concave aggregations for a given nonlinear row */
    1914static
    1916 SCIP* scip, /**< SCIP data structure */
    1917 SCIP_SEPADATA* sepadata, /**< separator data */
    1918 SCIP_NLROW* nlrow, /**< nonlinear row */
    1919 SCIP_SOL* sol /**< current solution (might be NULL) */
    1920 )
    1921{
    1922 int nquadvars;
    1923 int* quadvar2aggr;
    1924 SCIP_Bool rhscandidate;
    1925 SCIP_Bool lhscandidate;
    1926
    1927 assert(scip != NULL);
    1928 assert(nlrow != NULL);
    1929 assert(sepadata != NULL);
    1930
    1931#ifdef SCIP_DEBUG
    1932 SCIPdebugMsg(scip, "search for edge-concave aggregation for the nonlinear row: \n");
    1933 SCIP_CALL( SCIPprintNlRow(scip, nlrow, NULL) );
    1934#endif
    1935
    1936 /* check obvious conditions for existing cycles with an odd number of positive/negative edges */
    1937 SCIP_CALL( isCandidate(scip, sepadata, nlrow, &rhscandidate, &lhscandidate) );
    1938 SCIPdebugMsg(scip, "rhs candidate = %u lhs candidate = %u\n", rhscandidate, lhscandidate);
    1939
    1940 if( !rhscandidate && !lhscandidate )
    1941 return SCIP_OKAY;
    1942
    1944 SCIP_CALL( SCIPallocBufferArray(scip, &quadvar2aggr, nquadvars) ); /*lint !e705*/
    1945
    1946 /* search for edge-concave aggregations (consider <= rhs) */
    1947 if( rhscandidate )
    1948 {
    1949 SCIP_NLROWAGGR* nlrowaggr;
    1950 int nfound;
    1951
    1952 assert(!SCIPisInfinity(scip, REALABS(SCIPnlrowGetRhs(nlrow))));
    1953
    1954 SCIPdebugMsg(scip, "consider <= rhs\n");
    1955 SCIP_CALL( searchEcAggr(scip, sepadata, nlrow, sol, TRUE, quadvar2aggr, &nfound) );
    1956
    1957 if( nfound > 0 )
    1958 {
    1959 SCIP_CALL( nlrowaggrCreate(scip, nlrow, &nlrowaggr, quadvar2aggr, nfound, TRUE) );
    1960 assert(nlrow != NULL);
    1961 SCIPdebug(nlrowaggrPrint(scip, nlrowaggr));
    1962 SCIP_CALL( sepadataAddNlrowaggr(scip, sepadata, nlrowaggr) );
    1963 }
    1964 }
    1965
    1966 /* search for edge-concave aggregations (consider <= lhs) */
    1967 if( lhscandidate )
    1968 {
    1969 SCIP_NLROWAGGR* nlrowaggr;
    1970 int nfound;
    1971
    1972 assert(!SCIPisInfinity(scip, REALABS(SCIPnlrowGetLhs(nlrow))));
    1973
    1974 SCIPdebugMsg(scip, "consider >= lhs\n");
    1975 SCIP_CALL( searchEcAggr(scip, sepadata, nlrow, sol, FALSE, quadvar2aggr, &nfound) );
    1976
    1977 if( nfound > 0 )
    1978 {
    1979 SCIP_CALL( nlrowaggrCreate(scip, nlrow, &nlrowaggr, quadvar2aggr, nfound, FALSE) );
    1980 assert(nlrow != NULL);
    1981 SCIPdebug(nlrowaggrPrint(scip, nlrowaggr));
    1982 SCIP_CALL( sepadataAddNlrowaggr(scip, sepadata, nlrowaggr) );
    1983 }
    1984 }
    1985
    1986 SCIPfreeBufferArray(scip, &quadvar2aggr);
    1987 return SCIP_OKAY;
    1988}
    1989
    1990/*
    1991 * methods to compute edge-concave cuts
    1992 */
    1993
    1994#ifdef SCIP_DEBUG
    1995/** prints a given facet (candidate) */
    1996static
    1997void printFacet(
    1998 SCIP* scip, /**< SCIP data structure */
    1999 SCIP_VAR** vars, /**< variables contained in the edge-concave aggregation */
    2000 int nvars, /**< number of variables contained in the edge-concave aggregation */
    2001 SCIP_Real* facet, /**< current facet candidate */
    2002 SCIP_Real facetval /**< facet evaluated at the current solution */
    2003 )
    2004{
    2005 int i;
    2006
    2007 SCIPdebugMsg(scip, "print facet (val=%e): ", facetval);
    2008 for( i = 0; i < nvars; ++i )
    2009 SCIPdebugMsgPrint(scip, "%e %s + ", facet[i], SCIPvarGetName(vars[i]));
    2010 SCIPdebugMsgPrint(scip, "%e\n", facet[nvars]);
    2011}
    2012#endif
    2013
    2014/** checks if a facet is really an underestimate for all corners of the domain [l,u]
    2015 *
    2016 * Because of numerics it can happen that a facet violates a corner of the domain.
    2017 * To make the facet valid we subtract the maximum violation from the constant part of the facet.
    2018 */
    2019static
    2021 SCIP* scip, /**< SCIP data structure */
    2022 SCIP_ECAGGR* ecaggr, /**< edge-concave aggregation data */
    2023 SCIP_Real* fvals, /**< array containing all corner values of the aggregation */
    2024 SCIP_Real* facet /**< current facet candidate (of dimension ecaggr->nvars + 1) */
    2025 )
    2026{
    2027 SCIP_Real maxviolation;
    2028 SCIP_Real val;
    2029 unsigned int i;
    2030 unsigned int ncorner;
    2031 unsigned int prev;
    2032
    2033 assert(scip != NULL);
    2034 assert(ecaggr != NULL);
    2035 assert(fvals != NULL);
    2036 assert(facet != NULL);
    2037
    2038 ncorner = (unsigned int) poweroftwo[ecaggr->nvars];
    2039 maxviolation = 0.0;
    2040
    2041 /* check for the origin */
    2042 val = facet[ecaggr->nvars];
    2043 for( i = 0; i < (unsigned int) ecaggr->nvars; ++i )
    2044 val += facet[i] * SCIPvarGetLbLocal(ecaggr->vars[i]);
    2045
    2046 /* update maximum violation */
    2047 maxviolation = MAX(val - fvals[0], maxviolation);
    2048 assert(SCIPisFeasEQ(scip, maxviolation, 0.0));
    2049
    2050 prev = 0;
    2051 for( i = 1; i < ncorner; ++i )
    2052 {
    2053 unsigned int gray;
    2054 unsigned int diff;
    2055 unsigned int pos;
    2056
    2057 gray = i ^ (i >> 1);
    2058 diff = gray ^ prev;
    2059
    2060 /* compute position of unique 1 of diff */
    2061 pos = 0;
    2062 while( (diff >>= 1) != 0 )
    2063 ++pos;
    2064
    2065 if( gray > prev )
    2066 val += facet[pos] * (SCIPvarGetUbLocal(ecaggr->vars[pos]) - SCIPvarGetLbLocal(ecaggr->vars[pos]));
    2067 else
    2068 val -= facet[pos] * (SCIPvarGetUbLocal(ecaggr->vars[pos]) - SCIPvarGetLbLocal(ecaggr->vars[pos]));
    2069
    2070 /* update maximum violation */
    2071 maxviolation = MAX(val - fvals[gray], maxviolation);
    2072 assert(SCIPisFeasEQ(scip, maxviolation, 0.0));
    2073
    2074 prev = gray;
    2075 }
    2076
    2077 SCIPdebugMsg(scip, "maximum violation of facet: %2.8e\n", maxviolation);
    2078
    2079 /* there seem to be numerical problems if the violation is too large; in this case we reject the facet */
    2080 if( maxviolation > ADJUSTFACETTOL )
    2081 return FALSE;
    2082
    2083 /* adjust constant part of the facet */
    2084 facet[ecaggr->nvars] -= maxviolation;
    2085
    2086 return TRUE;
    2087}
    2088
    2089/** set up LP interface to solve LPs to compute the facet of the convex envelope */
    2090static
    2092 SCIP* scip, /**< SCIP data structure */
    2093 SCIP_SEPADATA* sepadata /**< separation data */
    2094 )
    2095{
    2096 SCIP_Real* obj;
    2097 SCIP_Real* lb;
    2098 SCIP_Real* ub;
    2099 SCIP_Real* val;
    2100 int* beg;
    2101 int* ind;
    2102 int nnonz;
    2103 int ncols;
    2104 int nrows;
    2105 int i;
    2106 int k;
    2107
    2108 assert(scip != NULL);
    2109 assert(sepadata != NULL);
    2110 assert(sepadata->nnlrowaggrs > 0);
    2111
    2112 /* LP interface has been already created with enough rows/columns*/
    2113 if( sepadata->lpi != NULL && sepadata->lpisize >= sepadata->maxecsize )
    2114 return SCIP_OKAY;
    2115
    2116 /* size of lpi is too small; reconstruct lpi */
    2117 if( sepadata->lpi != NULL )
    2118 {
    2119 SCIP_CALL( SCIPlpiFree(&sepadata->lpi) );
    2120 sepadata->lpi = NULL;
    2121 }
    2122
    2123 assert(sepadata->lpi == NULL);
    2124 SCIP_CALL( SCIPlpiCreate(&(sepadata->lpi), SCIPgetMessagehdlr(scip), "e.c. LP", SCIP_OBJSEN_MINIMIZE) );
    2125 sepadata->lpisize = sepadata->maxecsize;
    2126
    2127 nrows = sepadata->maxecsize + 1;
    2128 ncols = poweroftwo[nrows - 1];
    2129 nnonz = (ncols * (nrows + 1)) / 2;
    2130 k = 0;
    2131
    2132 /* allocate necessary memory */
    2133 SCIP_CALL( SCIPallocBufferArray(scip, &obj, ncols) );
    2134 SCIP_CALL( SCIPallocBufferArray(scip, &lb, ncols) );
    2135 SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
    2136 SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
    2137 SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
    2138 SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
    2139
    2140 /* calculate nonzero entries in the LP; set obj, lb, and ub to zero */
    2141 for( i = 0; i < ncols; ++i )
    2142 {
    2143 int row;
    2144 int a;
    2145
    2146 obj[i] = 0.0;
    2147 lb[i] = 0.0;
    2148 ub[i] = 0.0;
    2149
    2150 SCIPdebugMsg(scip, "col %i starts at position %d\n", i, k);
    2151 beg[i] = k;
    2152 row = 0;
    2153 a = 1;
    2154
    2155 /* iterate through the bit representation of i */
    2156 while( a <= i )
    2157 {
    2158 if( (a & i) != 0 )
    2159 {
    2160 val[k] = 1.0;
    2161 ind[k] = row;
    2162
    2163 SCIPdebugMsg(scip, " val[%d][%d] = 1 (position %d)\n", row, i, k);
    2164
    2165 ++k;
    2166 }
    2167
    2168 a <<= 1; /*lint !e701*/
    2169 ++row;
    2170 assert(poweroftwo[row] == a);
    2171 }
    2172
    2173 /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
    2174 val[k] = 1.0;
    2175 ind[k] = nrows - 1;
    2176 ++k;
    2177 SCIPdebugMsg(scip, " val[%d][%d] = 1 (position %d)\n", nrows - 1, i, k);
    2178 }
    2179 assert(k == nnonz);
    2180
    2181 /*
    2182 * add all columns to the LP interface
    2183 * CPLEX needs the row to exist before adding columns, so we create the rows with dummy sides
    2184 * note that the assert is not needed once somebody fixes the LPI
    2185 */
    2186 assert(nrows <= ncols);
    2187 SCIP_CALL( SCIPlpiAddRows(sepadata->lpi, nrows, obj, obj, NULL, 0, NULL, NULL, NULL) );
    2188 SCIP_CALL( SCIPlpiAddCols(sepadata->lpi, ncols, obj, lb, ub, NULL, nnonz, beg, ind, val) );
    2189
    2190 /* free allocated memory */
    2197
    2198 return SCIP_OKAY;
    2199}
    2200
    2201/** evaluates an edge-concave aggregation at a corner of the domain [l,u] */
    2202static
    2204 SCIP_ECAGGR* ecaggr, /**< edge-concave aggregation data */
    2205 int k /**< k-th corner */
    2206 )
    2207{
    2208 SCIP_Real val;
    2209 int i;
    2210
    2211 assert(ecaggr != NULL);
    2212 assert(k >= 0 && k < poweroftwo[ecaggr->nvars]);
    2213
    2214 val = 0.0;
    2215
    2216 for( i = 0; i < ecaggr->nterms; ++i )
    2217 {
    2218 SCIP_Real coef;
    2219 SCIP_Real bound1;
    2220 SCIP_Real bound2;
    2221 int idx1;
    2222 int idx2;
    2223
    2224 idx1 = ecaggr->termvars1[i];
    2225 idx2 = ecaggr->termvars2[i];
    2226 coef = ecaggr->termcoefs[i];
    2227 assert(idx1 >= 0 && idx1 < ecaggr->nvars);
    2228 assert(idx2 >= 0 && idx2 < ecaggr->nvars);
    2229
    2230 bound1 = ((poweroftwo[idx1]) & k) == 0 ? SCIPvarGetLbLocal(ecaggr->vars[idx1]) : SCIPvarGetUbLocal(ecaggr->vars[idx1]); /*lint !e661*/
    2231 bound2 = ((poweroftwo[idx2]) & k) == 0 ? SCIPvarGetLbLocal(ecaggr->vars[idx2]) : SCIPvarGetUbLocal(ecaggr->vars[idx2]); /*lint !e661*/
    2232
    2233 val += coef * bound1 * bound2;
    2234 }
    2235
    2236 return val;
    2237}
    2238
    2239/** returns (val - lb) / (ub - lb) for a in [lb, ub] */
    2240static
    2242 SCIP* scip, /**< SCIP data structure */
    2243 SCIP_Real lb, /**< lower bound */
    2244 SCIP_Real ub, /**< upper bound */
    2245 SCIP_Real val /**< value in [lb,ub] */
    2246 )
    2247{
    2248 assert(scip != NULL);
    2249 assert(!SCIPisInfinity(scip, -lb));
    2250 assert(!SCIPisInfinity(scip, ub));
    2251 assert(!SCIPisInfinity(scip, REALABS(val)));
    2252 assert(!SCIPisFeasEQ(scip, ub - lb, 0.0)); /* this would mean that a variable has been fixed */
    2253
    2254 /* adjust val */
    2255 val = MIN(val, ub);
    2256 val = MAX(val, lb);
    2257
    2258 val = (val - lb) / (ub - lb);
    2259 assert(val >= 0.0 && val <= 1.0);
    2260
    2261 return val;
    2262}
    2263
    2264/** computes a facet of the convex envelope of an edge concave aggregation
    2265 *
    2266 * The algorithm solves the following LP:
    2267 * \f{align}{
    2268 * \min & \sum_i \lambda_i f(v_i)\\
    2269 * s.t. & \sum_i \lambda_i v_i = x\\
    2270 * & \sum_i \lambda_i = 1\\
    2271 * & \lambda \geq 0
    2272 * \f}
    2273 * where \f$f\f$ is an edge concave function, \f$x\in [l,u]\f$ is a solution of the current relaxation, and \f$v_i\f$ are the vertices of \f$[l,u]\f$.
    2274 * The method transforms the problem to the domain \f$[0,1]^n\f$, computes a facet, and transforms this facet to the
    2275 * original space. The dual solution of the LP above are the coefficients of the facet.
    2276 *
    2277 * The complete algorithm works as follows:
    2278 * -# compute \f$f(v_i)\f$ for each corner \f$v_i\f$ of \f$[l,u]\f$
    2279 * -# set up the described LP for the transformed space
    2280 * -# solve the LP and store the resulting facet for the transformed space
    2281 * -# transform the facet to original space
    2282 * -# adjust and check facet with the algorithm of Rikun et al.
    2283 */
    2284static
    2286 SCIP* scip, /**< SCIP data structure */
    2287 SCIP_SEPADATA* sepadata, /**< separation data */
    2288 SCIP_SOL* sol, /**< solution (might be NULL) */
    2289 SCIP_ECAGGR* ecaggr, /**< edge-concave aggregation data */
    2290 SCIP_Real* facet, /**< array to store the coefficients of the resulting facet; size has to be at least (ecaggr->nvars + 1) */
    2291 SCIP_Real* facetval, /**< pointer to store the value of the facet evaluated at the current solution */
    2292 SCIP_Bool* success /**< pointer to store if we have found a facet */
    2293 )
    2294{
    2295 SCIP_Real* fvals;
    2296 SCIP_Real* side;
    2297 SCIP_Real* lb;
    2298 SCIP_Real* ub;
    2299 SCIP_Real perturbation;
    2300 int* inds;
    2301 int ncorner;
    2302 int ncols;
    2303 int nrows;
    2304 int i;
    2305
    2306 assert(scip != NULL);
    2307 assert(sepadata != NULL);
    2308 assert(ecaggr != NULL);
    2309 assert(facet != NULL);
    2310 assert(facetval != NULL);
    2311 assert(success != NULL);
    2312 assert(ecaggr->nvars <= sepadata->maxecsize);
    2313
    2314 *facetval = -SCIPinfinity(scip);
    2315 *success = FALSE;
    2316
    2317 /* create LP if this has not been done yet */
    2318 SCIP_CALL( createLP(scip, sepadata) );
    2319
    2320 assert(sepadata->lpi != NULL);
    2321 assert(sepadata->lpisize >= ecaggr->nvars);
    2322
    2323 SCIP_CALL( SCIPlpiGetNCols(sepadata->lpi, &ncols) );
    2324 SCIP_CALL( SCIPlpiGetNRows(sepadata->lpi, &nrows) );
    2325 ncorner = poweroftwo[ecaggr->nvars];
    2326
    2327 assert(ncorner <= ncols);
    2328 assert(ecaggr->nvars + 1 <= nrows);
    2329 assert(nrows <= ncols);
    2330
    2331 /* allocate necessary memory */
    2332 SCIP_CALL( SCIPallocBufferArray(scip, &fvals, ncols) );
    2333 SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
    2334 SCIP_CALL( SCIPallocBufferArray(scip, &lb, ncols) );
    2335 SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
    2336 SCIP_CALL( SCIPallocBufferArray(scip, &side, ncols) );
    2337
    2338 /*
    2339 * 1. compute f(v_i) for each corner v_i of [l,u]
    2340 * 2. set up the described LP for the transformed space
    2341 */
    2342 for( i = 0; i < ncols; ++i )
    2343 {
    2344 fvals[i] = i < ncorner ? evalCorner(ecaggr, i) : 0.0;
    2345 inds[i] = i;
    2346
    2347 /* update bounds; fix variables to zero which are currently not in the LP */
    2348 lb[i] = 0.0;
    2349 ub[i] = i < ncorner ? 1.0 : 0.0;
    2350 SCIPdebugMsg(scip, "bounds of LP col %d = [%e, %e]; obj = %e\n", i, lb[i], ub[i], fvals[i]);
    2351 }
    2352
    2353 /* update lhs and rhs */
    2354 perturbation = 0.001;
    2355 for( i = 0; i < nrows; ++i )
    2356 {
    2357 /* note that the last row corresponds to sum_{j} \lambda_j = 1 */
    2358 if( i < ecaggr->nvars )
    2359 {
    2360 SCIP_VAR* x;
    2361
    2362 x = ecaggr->vars[i];
    2363 assert(x != NULL);
    2364
    2366
    2367 /* perturb point to enforce an LP solution with ecaggr->nvars + 1 nonzero */
    2368 side[i] += side[i] > perturbation ? -perturbation : perturbation;
    2369 perturbation /= 1.2;
    2370 }
    2371 else
    2372 {
    2373 side[i] = (i == nrows - 1) ? 1.0 : 0.0;
    2374 }
    2375
    2376 SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, side[i], side[i]);
    2377 }
    2378
    2379 /* update LP */
    2380 SCIP_CALL( SCIPlpiChgObj(sepadata->lpi, ncols, inds, fvals) );
    2381 SCIP_CALL( SCIPlpiChgBounds(sepadata->lpi, ncols, inds, lb, ub) );
    2382 SCIP_CALL( SCIPlpiChgSides(sepadata->lpi, nrows, inds, side, side) );
    2383
    2384 /* free memory used to build the LP */
    2385 SCIPfreeBufferArray(scip, &side);
    2388 SCIPfreeBufferArray(scip, &inds);
    2389
    2390 /*
    2391 * 3. solve the LP and store the resulting facet for the transformed space
    2392 */
    2393 if( USEDUALSIMPLEX ) /*lint !e774 !e506*/
    2394 {
    2395 SCIP_CALL( SCIPlpiSolveDual(sepadata->lpi) );
    2396 }
    2397 else
    2398 {
    2399 SCIP_CALL( SCIPlpiSolvePrimal(sepadata->lpi) );
    2400 }
    2401
    2402 /* the dual solution corresponds to the coefficients of the facet in the transformed problem; note that it might be
    2403 * the case that the dual solution has more components than the facet array
    2404 */
    2405 if( ecaggr->nvars + 1 == ncols )
    2406 {
    2407 SCIP_CALL( SCIPlpiGetSol(sepadata->lpi, NULL, NULL, facet, NULL, NULL) );
    2408 }
    2409 else
    2410 {
    2411 SCIP_Real* dualsol;
    2412
    2413 SCIP_CALL( SCIPallocBufferArray(scip, &dualsol, nrows) );
    2414
    2415 /* get the dual solution */
    2416 SCIP_CALL( SCIPlpiGetSol(sepadata->lpi, NULL, NULL, dualsol, NULL, NULL) );
    2417
    2418 for( i = 0; i < ecaggr->nvars; ++i )
    2419 facet[i] = dualsol[i];
    2420
    2421 /* constant part of the facet is the last component of the dual solution */
    2422 facet[ecaggr->nvars] = dualsol[nrows - 1];
    2423
    2424 SCIPfreeBufferArray(scip, &dualsol);
    2425 }
    2426
    2427#ifdef SCIP_DEBUG
    2428 SCIPdebugMsg(scip, "facet for the transformed problem: ");
    2429 for( i = 0; i < ecaggr->nvars; ++i )
    2430 {
    2431 SCIPdebugMsgPrint(scip, "%3.4e * %s + ", facet[i], SCIPvarGetName(ecaggr->vars[i]));
    2432 }
    2433 SCIPdebugMsgPrint(scip, "%3.4e\n", facet[ecaggr->nvars]);
    2434#endif
    2435
    2436 /*
    2437 * 4. transform the facet to original space
    2438 * we now have the linear underestimator L(x) = beta^T x + beta_0, which needs to be transform to the original space
    2439 * the underestimator in the original space, G(x) = alpha^T x + alpha_0, is given by G(x) = L(T(x)), where T(.) is
    2440 * the transformation applied in step 2; therefore,
    2441 * alpha_i = beta_i/(ub_i - lb_i)
    2442 * alpha_0 = beta_0 - sum_i lb_i * beta_i/(ub_i - lb_i)
    2443 */
    2444
    2445 SCIPdebugMsg(scip, "facet in orig. space: ");
    2446 *facetval = 0.0;
    2447
    2448 for( i = 0; i < ecaggr->nvars; ++i )
    2449 {
    2450 SCIP_Real varlb;
    2451 SCIP_Real varub;
    2452
    2453 varlb = SCIPvarGetLbLocal(ecaggr->vars[i]);
    2454 varub = SCIPvarGetUbLocal(ecaggr->vars[i]);
    2455 assert(!SCIPisEQ(scip, varlb, varub));
    2456
    2457 /* substract (\beta_i * lb_i) / (ub_i - lb_i) from current alpha_0 */
    2458 facet[ecaggr->nvars] -= (facet[i] * varlb) / (varub - varlb);
    2459
    2460 /* set \alpha_i := \beta_i / (ub_i - lb_i) */
    2461 facet[i] = facet[i] / (varub - varlb);
    2462 *facetval += facet[i] * SCIPgetSolVal(scip, sol, ecaggr->vars[i]);
    2463
    2464 SCIPdebugMsgPrint(scip, "%3.4e * %s + ", facet[i], SCIPvarGetName(ecaggr->vars[i]));
    2465 }
    2466
    2467 /* add constant part to the facet value */
    2468 *facetval += facet[ecaggr->nvars];
    2469 SCIPdebugMsgPrint(scip, "%3.4e\n", facet[ecaggr->nvars]);
    2470
    2471 /*
    2472 * 5. adjust and check facet with the algorithm of Rikun et al.
    2473 */
    2474
    2475 if( checkRikun(scip, ecaggr, fvals, facet) )
    2476 {
    2477 SCIPdebugMsg(scip, "facet pass the check of Rikun et al.\n");
    2478 *success = TRUE;
    2479 }
    2480
    2481 /* free allocated memory */
    2482 SCIPfreeBufferArray(scip, &fvals);
    2483
    2484 return SCIP_OKAY;
    2485}
    2486
    2487/*
    2488 * miscellaneous methods
    2489 */
    2490
    2491/** method to add a facet of the convex envelope of an edge-concave aggregation to a given cut */
    2492static
    2494 SCIP* scip, /**< SCIP data structure */
    2495 SCIP_SOL* sol, /**< current solution (might be NULL) */
    2496 SCIP_ROW* cut, /**< current cut (modifiable) */
    2497 SCIP_Real* facet, /**< coefficient of the facet (dimension nvars + 1) */
    2498 SCIP_VAR** vars, /**< variables of the facet */
    2499 int nvars, /**< number of variables in the facet */
    2500 SCIP_Real* cutconstant, /**< pointer to update the constant part of the facet */
    2501 SCIP_Real* cutactivity, /**< pointer to update the activity of the cut */
    2502 SCIP_Bool* success /**< pointer to store if everything went fine */
    2503 )
    2504{
    2505 int i;
    2506
    2507 assert(cut != NULL);
    2508 assert(facet != NULL);
    2509 assert(vars != NULL);
    2510 assert(nvars > 0);
    2511 assert(cutconstant != NULL);
    2512 assert(cutactivity != NULL);
    2513 assert(success != NULL);
    2514
    2515 *success = TRUE;
    2516
    2517 for( i = 0; i < nvars; ++i )
    2518 {
    2519 if( SCIPisInfinity(scip, REALABS(facet[i])) )
    2520 {
    2521 *success = FALSE;
    2522 return SCIP_OKAY;
    2523 }
    2524
    2525 if( !SCIPisZero(scip, facet[i]) )
    2526 {
    2527 /* add only a constant if the variable has been fixed */
    2528 if( SCIPvarGetLbLocal(vars[i]) == SCIPvarGetUbLocal(vars[i]) ) /*lint !e777*/
    2529 {
    2530 assert(SCIPisFeasEQ(scip, SCIPvarGetLbLocal(vars[i]), SCIPgetSolVal(scip, sol, vars[i])));
    2531 *cutconstant += facet[i] * SCIPgetSolVal(scip, sol, vars[i]);
    2532 *cutactivity += facet[i] * SCIPgetSolVal(scip, sol, vars[i]);
    2533 }
    2534 else
    2535 {
    2536 *cutactivity += facet[i] * SCIPgetSolVal(scip, sol, vars[i]);
    2537 SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[i], facet[i]) );
    2538 }
    2539 }
    2540 }
    2541
    2542 /* add constant part of the facet */
    2543 *cutconstant += facet[nvars];
    2544 *cutactivity += facet[nvars];
    2545
    2546 return SCIP_OKAY;
    2547}
    2548
    2549/** method to add a linear term to a given cut */
    2550static
    2552 SCIP* scip, /**< SCIP data structure */
    2553 SCIP_SOL* sol, /**< current solution (might be NULL) */
    2554 SCIP_ROW* cut, /**< current cut (modifiable) */
    2555 SCIP_VAR* x, /**< linear variable */
    2556 SCIP_Real coeff, /**< coefficient */
    2557 SCIP_Real* cutconstant, /**< pointer to update the constant part of the facet */
    2558 SCIP_Real* cutactivity, /**< pointer to update the activity of the cut */
    2559 SCIP_Bool* success /**< pointer to store if everything went fine */
    2560 )
    2561{
    2562 SCIP_Real activity;
    2563
    2564 assert(cut != NULL);
    2565 assert(x != NULL);
    2566 assert(!SCIPisZero(scip, coeff));
    2567 assert(!SCIPisInfinity(scip, coeff));
    2568 assert(cutconstant != NULL);
    2569 assert(cutactivity != NULL);
    2570 assert(success != NULL);
    2571
    2572 *success = TRUE;
    2573 activity = SCIPgetSolVal(scip, sol, x) * coeff;
    2574
    2575 /* do not add a term if the activity is -infinity */
    2576 if( SCIPisInfinity(scip, -1.0 * REALABS(activity)) )
    2577 {
    2578 *success = FALSE;
    2579 return SCIP_OKAY;
    2580 }
    2581
    2582 /* add activity to the constant part if the variable has been fixed */
    2583 if( SCIPvarGetLbLocal(x) == SCIPvarGetUbLocal(x) ) /*lint !e777*/
    2584 {
    2586 *cutconstant += activity;
    2587 SCIPdebugMsg(scip, "add to cut: %e\n", activity);
    2588 }
    2589 else
    2590 {
    2591 SCIP_CALL( SCIPaddVarToRow(scip, cut, x, coeff) );
    2592 SCIPdebugMsg(scip, "add to cut: %e * %s\n", coeff, SCIPvarGetName(x));
    2593 }
    2594
    2595 *cutactivity += activity;
    2596
    2597 return SCIP_OKAY;
    2598}
    2599
    2600/** method to add an underestimate of a bilinear term to a given cut */
    2601static
    2603 SCIP* scip, /**< SCIP data structure */
    2604 SCIP_SOL* sol, /**< current solution (might be NULL) */
    2605 SCIP_ROW* cut, /**< current cut (modifiable) */
    2606 SCIP_VAR* x, /**< first bilinear variable */
    2607 SCIP_VAR* y, /**< seconds bilinear variable */
    2608 SCIP_Real coeff, /**< coefficient */
    2609 SCIP_Real* cutconstant, /**< pointer to update the constant part of the facet */
    2610 SCIP_Real* cutactivity, /**< pointer to update the activity of the cut */
    2611 SCIP_Bool* success /**< pointer to store if everything went fine */
    2612 )
    2613{
    2614 SCIP_Real activity;
    2615
    2616 assert(cut != NULL);
    2617 assert(x != NULL);
    2618 assert(y != NULL);
    2619 assert(!SCIPisZero(scip, coeff));
    2620 assert(cutconstant != NULL);
    2621 assert(cutactivity != NULL);
    2622 assert(success != NULL);
    2623
    2624 *success = TRUE;
    2625 activity = coeff * SCIPgetSolVal(scip, sol, x) * SCIPgetSolVal(scip, sol, y);
    2626
    2627 if( SCIPisInfinity(scip, REALABS(coeff)) )
    2628 {
    2629 *success = FALSE;
    2630 return SCIP_OKAY;
    2631 }
    2632
    2633 /* do not add a term if the activity is -infinity */
    2634 if( SCIPisInfinity(scip, -1.0 * REALABS(activity)) )
    2635 {
    2636 *success = FALSE;
    2637 return SCIP_OKAY;
    2638 }
    2639
    2640 /* quadratic case */
    2641 if( x == y )
    2642 {
    2643 SCIP_Real refpoint;
    2644 SCIP_Real lincoef;
    2645 SCIP_Real linconst;
    2646
    2647 lincoef = 0.0;
    2648 linconst = 0.0;
    2649 refpoint = SCIPgetSolVal(scip, sol, x);
    2650
    2651 /* adjust the reference point */
    2652 refpoint = SCIPisLT(scip, refpoint, SCIPvarGetLbLocal(x)) ? SCIPvarGetLbLocal(x) : refpoint;
    2653 refpoint = SCIPisGT(scip, refpoint, SCIPvarGetUbLocal(x)) ? SCIPvarGetUbLocal(x) : refpoint;
    2654 assert(SCIPisLE(scip, refpoint, SCIPvarGetUbLocal(x)) && SCIPisGE(scip, refpoint, SCIPvarGetLbLocal(x)));
    2655
    2656 if( SCIPisPositive(scip, coeff) )
    2657 SCIPaddSquareLinearization(scip, coeff, refpoint, SCIPvarIsIntegral(x), &lincoef, &linconst, success);
    2658 else
    2659 SCIPaddSquareSecant(scip, coeff, SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x), &lincoef, &linconst, success);
    2660
    2661 *cutactivity += lincoef * refpoint + linconst;
    2662 *cutconstant += linconst;
    2663
    2664 /* add underestimate to cut */
    2665 SCIP_CALL( SCIPaddVarToRow(scip, cut, x, lincoef) );
    2666
    2667 SCIPdebugMsg(scip, "add to cut: %e * %s + %e\n", lincoef, SCIPvarGetName(x), linconst);
    2668 }
    2669 /* bilinear case */
    2670 else
    2671 {
    2672 SCIP_Real refpointx;
    2673 SCIP_Real refpointy;
    2674 SCIP_Real lincoefx;
    2675 SCIP_Real lincoefy;
    2676 SCIP_Real linconst;
    2677
    2678 lincoefx = 0.0;
    2679 lincoefy = 0.0;
    2680 linconst = 0.0;
    2681 refpointx = SCIPgetSolVal(scip, sol, x);
    2682 refpointy = SCIPgetSolVal(scip, sol, y);
    2683
    2684 /* adjust the reference points */
    2685 refpointx = SCIPisLT(scip, refpointx, SCIPvarGetLbLocal(x)) ? SCIPvarGetLbLocal(x) : refpointx;
    2686 refpointx = SCIPisGT(scip, refpointx, SCIPvarGetUbLocal(x)) ? SCIPvarGetUbLocal(x) : refpointx;
    2687 refpointy = SCIPisLT(scip, refpointy, SCIPvarGetLbLocal(y)) ? SCIPvarGetLbLocal(y) : refpointy;
    2688 refpointy = SCIPisGT(scip, refpointy, SCIPvarGetUbLocal(y)) ? SCIPvarGetUbLocal(y) : refpointy;
    2689 assert(SCIPisLE(scip, refpointx, SCIPvarGetUbLocal(x)) && SCIPisGE(scip, refpointx, SCIPvarGetLbLocal(x)));
    2690 assert(SCIPisLE(scip, refpointy, SCIPvarGetUbLocal(y)) && SCIPisGE(scip, refpointy, SCIPvarGetLbLocal(y)));
    2691
    2693 SCIPvarGetUbLocal(y), refpointy, FALSE, &lincoefx, &lincoefy, &linconst, success);
    2694
    2695 *cutactivity += lincoefx * refpointx + lincoefy * refpointy + linconst;
    2696 *cutconstant += linconst;
    2697
    2698 /* add underestimate to cut */
    2699 SCIP_CALL( SCIPaddVarToRow(scip, cut, x, lincoefx) );
    2700 SCIP_CALL( SCIPaddVarToRow(scip, cut, y, lincoefy) );
    2701
    2702 SCIPdebugMsg(scip, "add to cut: %e * %s + %e * %s + %e\n", lincoefx, SCIPvarGetName(x), lincoefy,
    2703 SCIPvarGetName(y), linconst);
    2704 }
    2705
    2706 return SCIP_OKAY;
    2707}
    2708
    2709/** method to compute and add a cut for a nonlinear row aggregation and a given solution
    2710 *
    2711 * we compute for each edge concave aggregation one facet;
    2712 * the remaining bilinear terms will be underestimated with McCormick, secants or linearizations;
    2713 * constant and linear terms will be added to the cut directly
    2714 */
    2715static
    2717 SCIP* scip, /**< SCIP data structure */
    2718 SCIP_SEPA* sepa, /**< separator */
    2719 SCIP_SEPADATA* sepadata, /**< separator data */
    2720 SCIP_NLROWAGGR* nlrowaggr, /**< nonlinear row aggregation */
    2721 SCIP_SOL* sol, /**< current solution (might be NULL) */
    2722 SCIP_Bool* separated, /**< pointer to store if we could separate the current solution */
    2723 SCIP_Bool* cutoff /**< pointer to store if the current node gets cut off */
    2724 )
    2725{
    2726 SCIP_ROW* cut;
    2727 SCIP_Real* bestfacet;
    2728 SCIP_Real bestfacetval;
    2729 SCIP_Real cutconstant;
    2730 SCIP_Real cutactivity;
    2731 int bestfacetsize;
    2732 char cutname[SCIP_MAXSTRLEN];
    2733 SCIP_Bool found;
    2734 SCIP_Bool islocalcut;
    2735 int i;
    2736
    2737 assert(separated != NULL);
    2738 assert(cutoff != NULL);
    2739 assert(nlrowaggr->necaggr > 0);
    2740 assert(nlrowaggr->nlrow != NULL);
    2741 assert(SCIPnlrowIsInNLP(nlrowaggr->nlrow));
    2742
    2743 *separated = FALSE;
    2744 *cutoff = FALSE;
    2745 /* we use SCIPgetDepth because we add the cut to the global cut pool if cut is globally valid */
    2746 islocalcut = SCIPgetDepth(scip) != 0;
    2747
    2748 /* create the cut */
    2749 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "ec");
    2750 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), SCIPinfinity(scip), islocalcut, FALSE,
    2751 sepadata->dynamiccuts) );
    2753
    2754 /* track rhs and activity of the cut */
    2755 cutconstant = nlrowaggr->constant;
    2756 cutactivity = 0.0;
    2757
    2758 /* allocate necessary memory */
    2759 bestfacetsize = sepadata->maxaggrsize + 1;
    2760 SCIP_CALL( SCIPallocBufferArray(scip, &bestfacet, bestfacetsize) );
    2761
    2762#ifdef SCIP_DEBUG
    2763 SCIP_CALL( SCIPprintNlRow(scip, nlrowaggr->nlrow, NULL) );
    2764
    2765 SCIPdebugMsg(scip, "current solution:\n");
    2766 for( i = 0; i < SCIPgetNVars(scip); ++i )
    2767 {
    2768 SCIP_VAR* var = SCIPgetVars(scip)[i];
    2769 SCIPdebugMsg(scip, " %s = [%e, %e] solval = %e\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var),
    2770 SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var));
    2771 }
    2772#endif
    2773
    2774 /* compute a facet for each edge-concave aggregation */
    2775 for( i = 0; i < nlrowaggr->necaggr; ++i )
    2776 {
    2777 SCIP_ECAGGR* ecaggr;
    2778 SCIP_Bool success;
    2779
    2780 ecaggr = nlrowaggr->ecaggr[i];
    2781 assert(ecaggr != NULL);
    2782
    2783 /* compute a facet of the convex envelope */
    2784 SCIP_CALL( computeConvexEnvelopeFacet(scip, sepadata, sol, ecaggr, bestfacet, &bestfacetval, &found) );
    2785
    2786 SCIPdebugMsg(scip, "found facet for edge-concave aggregation %d/%d ? %s\n", i, nlrowaggr->necaggr,
    2787 found ? "yes" : "no");
    2788
    2789#ifdef SCIP_DEBUG
    2790 if( found )
    2791 printFacet(scip, ecaggr->vars, ecaggr->nvars, bestfacet, bestfacetval);
    2792#endif
    2793
    2794 /* do not add any cut because we did not found a facet for at least one edge-concave aggregation */
    2795 if( !found ) /*lint !e774*/
    2796 goto TERMINATE;
    2797
    2798 /* add facet to the cut and update the rhs and activity of the cut */
    2799 SCIP_CALL( addFacetToCut(scip, sol, cut, bestfacet, ecaggr->vars, ecaggr->nvars, &cutconstant, &cutactivity,
    2800 &success) );
    2801
    2802 if( !success )
    2803 goto TERMINATE;
    2804 }
    2805
    2806 /* compute an underestimate for each bilinear term which is not in any edge-concave aggregation */
    2807 for( i = 0; i < nlrowaggr->nremterms; ++i )
    2808 {
    2809 SCIP_VAR* x;
    2810 SCIP_VAR* y;
    2811 SCIP_Bool success;
    2812
    2813 x = nlrowaggr->remtermvars1[i];
    2814 y = nlrowaggr->remtermvars2[i];
    2815 assert(x != NULL);
    2816 assert(y != NULL);
    2817
    2818 SCIP_CALL( addBilinearTermToCut(scip, sol, cut, x, y, nlrowaggr->remtermcoefs[i], &cutconstant, &cutactivity,
    2819 &success) );
    2820
    2821 if( !success )
    2822 goto TERMINATE;
    2823 }
    2824
    2825 /* add all linear terms to the cut */
    2826 for( i = 0; i < nlrowaggr->nlinvars; ++i )
    2827 {
    2828 SCIP_VAR* x;
    2829 SCIP_Real coef;
    2830 SCIP_Bool success;
    2831
    2832 x = nlrowaggr->linvars[i];
    2833 assert(x != NULL);
    2834
    2835 coef = nlrowaggr->lincoefs[i];
    2836
    2837 SCIP_CALL( addLinearTermToCut(scip, sol, cut, x, coef, &cutconstant, &cutactivity, &success) );
    2838
    2839 if( !success )
    2840 goto TERMINATE;
    2841 }
    2842
    2843 SCIPdebugMsg(scip, "cut activity = %e rhs(nlrow) = %e\n", cutactivity, nlrowaggr->rhs);
    2844
    2845 /* set rhs of the cut (substract the constant part of the cut) */
    2846 SCIP_CALL( SCIPchgRowRhs(scip, cut, nlrowaggr->rhs - cutconstant) );
    2848
    2849 /* check activity of the row; this assert can fail because of numerics */
    2850 /* assert(SCIPisFeasEQ(scip, cutactivity - cutconstant, SCIPgetRowSolActivity(scip, cut, sol)) ); */
    2851
    2852#ifdef SCIP_DEBUG
    2853 SCIP_CALL( SCIPprintRow(scip, cut, NULL) );
    2854#endif
    2855
    2856 SCIPdebugMsg(scip, "EC cut <%s>: act=%f eff=%f rank=%d range=%e\n",
    2859
    2860 /* try to add the cut has a finite rhs, is efficacious, and does not exceed the maximum cut range */
    2861 if( !SCIPisInfinity(scip, nlrowaggr->rhs - cutconstant) && SCIPisCutEfficacious(scip, sol, cut)
    2862 && SCIPgetRowMaxCoef(scip, cut) / SCIPgetRowMinCoef(scip, cut) < sepadata->cutmaxrange )
    2863 {
    2864 /* add the cut if it is separating the given solution by at least minviolation */
    2865 if( SCIPisGE(scip, cutactivity - nlrowaggr->rhs, sepadata->minviolation) )
    2866 {
    2867 SCIP_CALL( SCIPaddRow(scip, cut, FALSE, cutoff) );
    2868 *separated = TRUE;
    2869 SCIPdebugMsg(scip, "added separating cut\n");
    2870 }
    2871
    2872 if( !(*cutoff) && !islocalcut )
    2873 {
    2874 SCIP_CALL( SCIPaddPoolCut(scip, cut) );
    2875 SCIPdebugMsg(scip, "added cut to cut pool\n");
    2876 }
    2877 }
    2878
    2879TERMINATE:
    2880 /* free allocated memory */
    2881 SCIPfreeBufferArray(scip, &bestfacet);
    2882
    2883 /* release the row */
    2884 SCIP_CALL( SCIPreleaseRow(scip, &cut) );
    2885
    2886 return SCIP_OKAY;
    2887}
    2888
    2889/** returns whether it is possible to compute a cut for a given nonlinear row aggregation */
    2890static
    2892 SCIP* scip, /**< SCIP data structure */
    2893 SCIP_SOL* sol, /**< current solution (might be NULL) */
    2894 SCIP_NLROWAGGR* nlrowaggr /**< nonlinear row aggregation */
    2895 )
    2896{
    2897 int i;
    2898
    2899 assert(scip != NULL);
    2900 assert(nlrowaggr != NULL);
    2901
    2902 if( !SCIPnlrowIsInNLP(nlrowaggr->nlrow) )
    2903 {
    2904 SCIPdebugMsg(scip, "nlrow is not in NLP anymore\n");
    2905 return FALSE;
    2906 }
    2907
    2908 for( i = 0; i < nlrowaggr->nquadvars; ++i )
    2909 {
    2910 SCIP_VAR* var = nlrowaggr->quadvars[i];
    2911 assert(var != NULL);
    2912
    2913 /* check whether the variable has infinite bounds */
    2915 || SCIPisInfinity(scip, REALABS(SCIPgetSolVal(scip, sol, var))) )
    2916 {
    2917 SCIPdebugMsg(scip, "nlrow aggregation contains unbounded variables\n");
    2918 return FALSE;
    2919 }
    2920
    2921 /* check whether the variable has been fixed and is in one edge-concave aggregation */
    2922 if( nlrowaggr->quadvar2aggr[i] >= 0 && SCIPisFeasEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
    2923 {
    2924 SCIPdebugMsg(scip, "nlrow aggregation contains fixed variables in an e.c. aggregation\n");
    2925 return FALSE;
    2926 }
    2927 }
    2928
    2929 return TRUE;
    2930}
    2931
    2932/** searches and tries to add edge-concave cuts */
    2933static
    2935 SCIP* scip, /**< SCIP data structure */
    2936 SCIP_SEPA* sepa, /**< separator */
    2937 SCIP_SEPADATA* sepadata, /**< separator data */
    2938 int depth, /**< current depth */
    2939 SCIP_SOL* sol, /**< current solution */
    2940 SCIP_RESULT* result /**< pointer to store the result of the separation call */
    2941 )
    2942{
    2943 int nmaxcuts;
    2944 int ncuts;
    2945 int i;
    2946
    2947 assert(*result == SCIP_DIDNOTRUN);
    2948
    2949 SCIPdebugMsg(scip, "separate cuts...\n");
    2950
    2951 /* skip if there are no nonlinear row aggregations */
    2952 if( sepadata->nnlrowaggrs == 0 )
    2953 {
    2954 SCIPdebugMsg(scip, "no aggregations exists -> skip call\n");
    2955 return SCIP_OKAY;
    2956 }
    2957
    2958 /* get the maximal number of cuts allowed in a separation round */
    2959 nmaxcuts = depth == 0 ? sepadata->maxsepacutsroot : sepadata->maxsepacuts;
    2960 ncuts = 0;
    2961
    2962 /* try to compute cuts for each nonlinear row independently */
    2963 for( i = 0; i < sepadata->nnlrowaggrs && ncuts < nmaxcuts && !SCIPisStopped(scip); ++i )
    2964 {
    2965 SCIP_NLROWAGGR* nlrowaggr;
    2966 SCIP_Bool separated;
    2967 SCIP_Bool cutoff;
    2968
    2969 nlrowaggr = sepadata->nlrowaggrs[i];
    2970 assert(nlrowaggr != NULL);
    2971
    2972 /* skip nonlinear aggregations for which it is obviously not possible to compute a cut */
    2973 if( !isPossibleToComputeCut(scip, sol, nlrowaggr) )
    2974 return SCIP_OKAY;
    2975
    2976 *result = (*result == SCIP_DIDNOTRUN) ? SCIP_DIDNOTFIND : *result;
    2977
    2978 SCIPdebugMsg(scip, "try to compute a cut for nonlinear row aggregation %d\n", i);
    2979
    2980 /* compute and add cut */
    2981 SCIP_CALL( computeCut(scip, sepa, sepadata, nlrowaggr, sol, &separated, &cutoff) );
    2982 SCIPdebugMsg(scip, "found a cut: %s cutoff: %s\n", separated ? "yes" : "no", cutoff ? "yes" : "no");
    2983
    2984 /* stop if the current node gets cut off */
    2985 if( cutoff )
    2986 {
    2987 assert(separated);
    2988 *result = SCIP_CUTOFF;
    2989 return SCIP_OKAY;
    2990 }
    2991
    2992 /* do not compute more cuts if we already separated the given solution */
    2993 if( separated )
    2994 {
    2995 assert(!cutoff);
    2996 *result = SCIP_SEPARATED;
    2997 ++ncuts;
    2998 }
    2999 }
    3000
    3001 return SCIP_OKAY;
    3002}
    3003
    3004/*
    3005 * Callback methods of separator
    3006 */
    3007
    3008/** copy method for separator plugins (called when SCIP copies plugins) */
    3009static
    3010SCIP_DECL_SEPACOPY(sepaCopyEccuts)
    3011{ /*lint --e{715}*/
    3012 assert(scip != NULL);
    3013 assert(sepa != NULL);
    3014 assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
    3015
    3016 /* call inclusion method of constraint handler */
    3018
    3019 return SCIP_OKAY;
    3020}
    3021
    3022/** destructor of separator to free user data (called when SCIP is exiting) */
    3023static
    3024SCIP_DECL_SEPAFREE(sepaFreeEccuts)
    3025{ /*lint --e{715}*/
    3026 SCIP_SEPADATA* sepadata;
    3027
    3028 sepadata = SCIPsepaGetData(sepa);
    3029 assert(sepadata != NULL);
    3030
    3031 SCIP_CALL( sepadataFree(scip, &sepadata) );
    3032 SCIPsepaSetData(sepa, NULL);
    3033
    3034 return SCIP_OKAY;
    3035}
    3036
    3037/** solving process deinitialization method of separator (called before branch and bound process data is freed) */
    3038static
    3039SCIP_DECL_SEPAEXITSOL(sepaExitsolEccuts)
    3040{ /*lint --e{715}*/
    3041 SCIP_SEPADATA* sepadata;
    3042
    3043 sepadata = SCIPsepaGetData(sepa);
    3044 assert(sepadata != NULL);
    3045
    3046 /* print statistics */
    3047#ifdef SCIP_STATISTIC
    3048 SCIPstatisticMessage("rhs-AGGR %d\n", sepadata->nrhsnlrowaggrs);
    3049 SCIPstatisticMessage("lhs-AGGR %d\n", sepadata->nlhsnlrowaggrs);
    3050 SCIPstatisticMessage("aggr. search time = %f\n", sepadata->aggrsearchtime);
    3051#endif
    3052
    3053 /* free nonlinear row aggregations */
    3054 SCIP_CALL( sepadataFreeNlrows(scip, sepadata) );
    3055
    3056 /* mark that we should search again for nonlinear row aggregations */
    3057 sepadata->searchedforaggr = FALSE;
    3058
    3059 SCIPdebugMsg(scip, "exitsol\n");
    3060
    3061 return SCIP_OKAY;
    3062}
    3063
    3064/** LP solution separation method of separator */
    3065static
    3066SCIP_DECL_SEPAEXECLP(sepaExeclpEccuts)
    3067{ /*lint --e{715}*/
    3068 SCIP_SEPADATA* sepadata;
    3069 int ncalls;
    3070
    3071 sepadata = SCIPsepaGetData(sepa);
    3072 assert(sepadata != NULL);
    3073
    3074 *result = SCIP_DIDNOTRUN;
    3075
    3076 if( !allowlocal )
    3077 return SCIP_OKAY;
    3078
    3079 /* check min- and maximal aggregation size */
    3080 if( sepadata->maxaggrsize < sepadata->minaggrsize )
    3082
    3083 /* only call separator, if we are not close to terminating */
    3084 if( SCIPisStopped(scip) )
    3085 return SCIP_OKAY;
    3086
    3087 /* skip if the LP is not constructed yet */
    3089 {
    3090 SCIPdebugMsg(scip, "Skip since NLP is not constructed yet.\n");
    3091 return SCIP_OKAY;
    3092 }
    3093
    3094 /* only call separator up to a maximum depth */
    3095 if ( sepadata->maxdepth >= 0 && depth > sepadata->maxdepth )
    3096 return SCIP_OKAY;
    3097
    3098 /* only call separator a given number of times at each node */
    3099 ncalls = SCIPsepaGetNCallsAtNode(sepa);
    3100 if ( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot)
    3101 || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) )
    3102 return SCIP_OKAY;
    3103
    3104 /* search for nonlinear row aggregations */
    3105 if( !sepadata->searchedforaggr )
    3106 {
    3107 int i;
    3108
    3109 SCIPstatistic( sepadata->aggrsearchtime -= SCIPgetTotalTime(scip) );
    3110
    3111 SCIPdebugMsg(scip, "search for nonlinear row aggregations\n");
    3112 for( i = 0; i < SCIPgetNNLPNlRows(scip) && !SCIPisStopped(scip); ++i )
    3113 {
    3114 SCIP_NLROW* nlrow = SCIPgetNLPNlRows(scip)[i];
    3115 SCIP_CALL( findAndStoreEcAggregations(scip, sepadata, nlrow, NULL) );
    3116 }
    3117 sepadata->searchedforaggr = TRUE;
    3118
    3119 SCIPstatistic( sepadata->aggrsearchtime += SCIPgetTotalTime(scip) );
    3120 }
    3121
    3122 /* search for edge-concave cuts */
    3123 SCIP_CALL( separateCuts(scip, sepa, sepadata, depth, NULL, result) );
    3124
    3125 return SCIP_OKAY;
    3126}
    3127
    3128/*
    3129 * separator specific interface methods
    3130 */
    3131
    3132/** creates the edge-concave separator and includes it in SCIP
    3133 *
    3134 * @ingroup SeparatorIncludes
    3135 */
    3137 SCIP* scip /**< SCIP data structure */
    3138 )
    3139{
    3140 SCIP_SEPADATA* sepadata;
    3141 SCIP_SEPA* sepa;
    3142
    3143 /* create eccuts separator data */
    3144 SCIP_CALL( sepadataCreate(scip, &sepadata) );
    3145
    3146 /* include separator */
    3148 SEPA_USESSUBSCIP, SEPA_DELAY, sepaExeclpEccuts, NULL, sepadata) );
    3149
    3150 assert(sepa != NULL);
    3151
    3152 /* set non fundamental callbacks via setter functions */
    3153 SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyEccuts) );
    3154 SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeEccuts) );
    3155 SCIP_CALL( SCIPsetSepaExitsol(scip, sepa, sepaExitsolEccuts) );
    3156
    3157 /* add eccuts separator parameters */
    3159 "separating/" SEPA_NAME "/dynamiccuts",
    3160 "should generated cuts be removed from the LP if they are no longer tight?",
    3161 &sepadata->dynamiccuts, FALSE, DEFAULT_DYNAMICCUTS, NULL, NULL) );
    3162
    3164 "separating/" SEPA_NAME "/maxrounds",
    3165 "maximal number of eccuts separation rounds per node (-1: unlimited)",
    3166 &sepadata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
    3167
    3169 "separating/" SEPA_NAME "/maxroundsroot",
    3170 "maximal number of eccuts separation rounds in the root node (-1: unlimited)",
    3171 &sepadata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
    3172
    3174 "separating/" SEPA_NAME "/maxdepth",
    3175 "maximal depth at which the separator is applied (-1: unlimited)",
    3176 &sepadata->maxdepth, FALSE, DEFAULT_MAXDEPTH, -1, INT_MAX, NULL, NULL) );
    3177
    3179 "separating/" SEPA_NAME "/maxsepacuts",
    3180 "maximal number of edge-concave cuts separated per separation round",
    3181 &sepadata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
    3182
    3184 "separating/" SEPA_NAME "/maxsepacutsroot",
    3185 "maximal number of edge-concave cuts separated per separation round in the root node",
    3186 &sepadata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
    3187
    3188 SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/cutmaxrange",
    3189 "maximal coef. range of a cut (max coef. divided by min coef.) in order to be added to LP relaxation",
    3190 &sepadata->cutmaxrange, FALSE, DEFAULT_CUTMAXRANGE, 0.0, SCIPinfinity(scip), NULL, NULL) );
    3191
    3192 SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/minviolation",
    3193 "minimal violation of an edge-concave cut to be separated",
    3194 &sepadata->minviolation, FALSE, DEFAULT_MINVIOLATION, 0.0, 0.5, NULL, NULL) );
    3195
    3197 "separating/" SEPA_NAME "/minaggrsize",
    3198 "search for edge-concave aggregations of at least this size",
    3199 &sepadata->minaggrsize, TRUE, DEFAULT_MINAGGRSIZE, 3, 5, NULL, NULL) );
    3200
    3202 "separating/" SEPA_NAME "/maxaggrsize",
    3203 "search for edge-concave aggregations of at most this size",
    3204 &sepadata->maxaggrsize, TRUE, DEFAULT_MAXAGGRSIZE, 3, 5, NULL, NULL) );
    3205
    3207 "separating/" SEPA_NAME "/maxbilinterms",
    3208 "maximum number of bilinear terms allowed to be in a quadratic constraint",
    3209 &sepadata->maxbilinterms, TRUE, DEFAULT_MAXBILINTERMS, 0, INT_MAX, NULL, NULL) );
    3210
    3212 "separating/" SEPA_NAME "/maxstallrounds",
    3213 "maximum number of unsuccessful rounds in the edge-concave aggregation search",
    3214 &sepadata->maxstallrounds, TRUE, DEFAULT_MAXSTALLROUNDS, 0, INT_MAX, NULL, NULL) );
    3215
    3216 return SCIP_OKAY;
    3217}
    SCIP_VAR * a
    Definition: circlepacking.c:66
    SCIP_VAR ** y
    Definition: circlepacking.c:64
    SCIP_VAR ** x
    Definition: circlepacking.c:63
    Constraint handler for XOR constraints, .
    #define NULL
    Definition: def.h:248
    #define SCIP_MAXSTRLEN
    Definition: def.h:269
    #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_CALL_TERMINATE(retcode, x, TERM)
    Definition: def.h:376
    #define REALABS(x)
    Definition: def.h:182
    #define SCIP_CALL(x)
    Definition: def.h:355
    #define SCIP_CALL_FINALLY(x, y)
    Definition: def.h:397
    void SCIPaddSquareLinearization(SCIP *scip, SCIP_Real sqrcoef, SCIP_Real refpoint, SCIP_Bool isint, SCIP_Real *lincoef, SCIP_Real *linconstant, SCIP_Bool *success)
    Definition: expr_pow.c:3245
    void SCIPaddSquareSecant(SCIP *scip, SCIP_Real sqrcoef, SCIP_Real lb, SCIP_Real ub, SCIP_Real *lincoef, SCIP_Real *linconstant, SCIP_Bool *success)
    Definition: expr_pow.c:3313
    #define nnodes
    Definition: gastrans.c:74
    #define narcs
    Definition: gastrans.c:77
    SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
    SCIP_RETCODE SCIPcreateConsBasicXor(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_Bool rhs, int nvars, SCIP_VAR **vars)
    Definition: cons_xor.c:6084
    SCIP_RETCODE SCIPcreateConsBasicLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs)
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:759
    SCIP_RETCODE SCIPfree(SCIP **scip)
    Definition: scip_general.c:402
    SCIP_RETCODE SCIPcreate(SCIP **scip)
    Definition: scip_general.c:370
    SCIP_STATUS SCIPgetStatus(SCIP *scip)
    Definition: scip_general.c:562
    SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_prob.c:1907
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:3274
    SCIP_VAR ** SCIPgetVars(SCIP *scip)
    Definition: scip_prob.c:2201
    SCIP_RETCODE SCIPsetObjsense(SCIP *scip, SCIP_OBJSENSE objsense)
    Definition: scip_prob.c:1417
    SCIP_RETCODE SCIPcreateProbBasic(SCIP *scip, const char *name)
    Definition: scip_prob.c:182
    void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
    Definition: misc.c:3095
    SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
    Definition: misc.c:3061
    SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3466
    SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
    Definition: misc.c:3179
    SCIP_RETCODE SCIPlpiChgSides(SCIP_LPI *lpi, int nrows, const int *ind, const SCIP_Real *lhs, const SCIP_Real *rhs)
    Definition: lpi_clp.cpp:1179
    SCIP_RETCODE SCIPlpiAddRows(SCIP_LPI *lpi, int nrows, const SCIP_Real *lhs, const SCIP_Real *rhs, char **rownames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
    Definition: lpi_clp.cpp:920
    SCIP_RETCODE SCIPlpiChgBounds(SCIP_LPI *lpi, int ncols, const int *ind, const SCIP_Real *lb, const SCIP_Real *ub)
    Definition: lpi_clp.cpp:1096
    SCIP_RETCODE SCIPlpiFree(SCIP_LPI **lpi)
    Definition: lpi_clp.cpp:643
    SCIP_RETCODE SCIPlpiGetSol(SCIP_LPI *lpi, SCIP_Real *objval, SCIP_Real *primsol, SCIP_Real *dualsol, SCIP_Real *activity, SCIP_Real *redcost)
    Definition: lpi_clp.cpp:2816
    SCIP_RETCODE SCIPlpiSolveDual(SCIP_LPI *lpi)
    Definition: lpi_clp.cpp:1908
    SCIP_RETCODE SCIPlpiAddCols(SCIP_LPI *lpi, int ncols, const SCIP_Real *obj, const SCIP_Real *lb, const SCIP_Real *ub, char **colnames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
    Definition: lpi_clp.cpp:758
    SCIP_RETCODE SCIPlpiSolvePrimal(SCIP_LPI *lpi)
    Definition: lpi_clp.cpp:1833
    SCIP_RETCODE SCIPlpiCreate(SCIP_LPI **lpi, SCIP_MESSAGEHDLR *messagehdlr, const char *name, SCIP_OBJSEN objsen)
    Definition: lpi_clp.cpp:531
    SCIP_RETCODE SCIPlpiChgObj(SCIP_LPI *lpi, int ncols, const int *ind, const SCIP_Real *obj)
    Definition: lpi_clp.cpp:1252
    SCIP_RETCODE SCIPlpiGetNCols(SCIP_LPI *lpi, int *ncols)
    Definition: lpi_clp.cpp:1447
    SCIP_RETCODE SCIPlpiGetNRows(SCIP_LPI *lpi, int *nrows)
    Definition: lpi_clp.cpp:1429
    #define SCIPdebugMsgPrint
    Definition: scip_message.h:79
    SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
    Definition: scip_message.c:88
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    void SCIPaddBilinMcCormick(SCIP *scip, SCIP_Real bilincoef, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real refpointx, SCIP_Real lby, SCIP_Real uby, SCIP_Real refpointy, SCIP_Bool overestimate, SCIP_Real *lincoefx, SCIP_Real *lincoefy, SCIP_Real *linconstant, SCIP_Bool *success)
    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 SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
    Definition: scip_param.c:545
    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 SCIPsetHeuristics(SCIP *scip, SCIP_PARAMSETTING paramsetting, SCIP_Bool quiet)
    Definition: scip_param.c:930
    SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
    Definition: scip_param.c:487
    SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
    Definition: scip_param.c:307
    SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:57
    SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
    Definition: scip_param.c:603
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
    Definition: scip_cut.c:336
    SCIP_Real SCIPgetCutEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
    Definition: scip_cut.c:94
    SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
    Definition: scip_cut.c:117
    SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
    Definition: scip_cut.c:225
    void SCIPexprGetQuadraticBilinTerm(SCIP_EXPR *expr, int termidx, SCIP_EXPR **expr1, SCIP_EXPR **expr2, SCIP_Real *coef, int *pos2, SCIP_EXPR **prodexpr)
    Definition: expr.c:4226
    SCIP_Bool SCIPexprAreQuadraticExprsVariables(SCIP_EXPR *expr)
    Definition: expr.c:4262
    void SCIPexprGetQuadraticData(SCIP_EXPR *expr, SCIP_Real *constant, int *nlinexprs, SCIP_EXPR ***linexprs, SCIP_Real **lincoefs, int *nquadexprs, int *nbilinexprs, SCIP_Real **eigenvalues, SCIP_Real **eigenvectors)
    Definition: expr.c:4141
    SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1457
    SCIP_RETCODE SCIPcheckExprQuadratic(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool *isquadratic)
    Definition: scip_expr.c:2402
    SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
    Definition: expr_var.c:424
    void SCIPexprGetQuadraticQuadTerm(SCIP_EXPR *quadexpr, int termidx, SCIP_EXPR **expr, SCIP_Real *lincoef, SCIP_Real *sqrcoef, int *nadjbilin, int **adjbilin, SCIP_EXPR **sqrexpr)
    Definition: expr.c:4186
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    BMS_BLKMEM * SCIPblkmem(SCIP *scip)
    Definition: scip_mem.c:57
    #define SCIPensureBlockMemoryArray(scip, ptr, arraysizeptr, minsize)
    Definition: scip_mem.h:107
    #define SCIPallocClearBufferArray(scip, ptr, num)
    Definition: scip_mem.h:126
    int SCIPcalcMemGrowSize(SCIP *scip, int num)
    Definition: scip_mem.c:139
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #define SCIPallocBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:93
    #define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
    Definition: scip_mem.h:99
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
    Definition: scip_mem.h:111
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    #define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
    Definition: scip_mem.h:105
    SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
    Definition: scip_nlp.c:110
    int SCIPgetNNLPNlRows(SCIP *scip)
    Definition: scip_nlp.c:341
    SCIP_NLROW ** SCIPgetNLPNlRows(SCIP *scip)
    Definition: scip_nlp.c:319
    SCIP_Real SCIPnlrowGetRhs(SCIP_NLROW *nlrow)
    Definition: nlp.c:1914
    SCIP_Real SCIPnlrowGetLhs(SCIP_NLROW *nlrow)
    Definition: nlp.c:1904
    int SCIPnlrowGetNLinearVars(SCIP_NLROW *nlrow)
    Definition: nlp.c:1864
    SCIP_VAR ** SCIPnlrowGetLinearVars(SCIP_NLROW *nlrow)
    Definition: nlp.c:1874
    SCIP_Real SCIPnlrowGetConstant(SCIP_NLROW *nlrow)
    Definition: nlp.c:1854
    SCIP_EXPR * SCIPnlrowGetExpr(SCIP_NLROW *nlrow)
    Definition: nlp.c:1894
    SCIP_Bool SCIPnlrowIsInNLP(SCIP_NLROW *nlrow)
    Definition: nlp.c:1953
    SCIP_Real * SCIPnlrowGetLinearCoefs(SCIP_NLROW *nlrow)
    Definition: nlp.c:1884
    SCIP_RETCODE SCIPprintNlRow(SCIP *scip, SCIP_NLROW *nlrow, FILE *file)
    Definition: scip_nlp.c:1617
    SCIP_Real SCIPgetRowMaxCoef(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1886
    SCIP_Real SCIPgetRowMinCoef(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1868
    SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1581
    SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1604
    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
    SCIP_RETCODE SCIPchgRowRhs(SCIP *scip, SCIP_ROW *row, SCIP_Real rhs)
    Definition: scip_lp.c:1553
    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
    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_RETCODE SCIPsetSepaExitsol(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAEXITSOL((*sepaexitsol)))
    Definition: scip_sepa.c:237
    SCIP_SEPADATA * SCIPsepaGetData(SCIP_SEPA *sepa)
    Definition: sepa.c:636
    void SCIPsepaSetData(SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata)
    Definition: sepa.c:646
    SCIP_RETCODE SCIPsetSepaCopy(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPACOPY((*sepacopy)))
    Definition: scip_sepa.c:157
    SCIP_SOL * SCIPgetBestSol(SCIP *scip)
    Definition: scip_sol.c:2981
    SCIP_RETCODE SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
    Definition: scip_sol.c:2349
    int SCIPgetNSols(SCIP *scip)
    Definition: scip_sol.c:2882
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1765
    SCIP_RETCODE SCIPfreeTransform(SCIP *scip)
    Definition: scip_solve.c:3462
    SCIP_RETCODE SCIPsolve(SCIP *scip)
    Definition: scip_solve.c:2635
    SCIP_Real SCIPgetSolvingTime(SCIP *scip)
    Definition: scip_timing.c:378
    SCIP_Real SCIPgetTotalTime(SCIP *scip)
    Definition: scip_timing.c:351
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24268
    SCIP_RETCODE SCIPchgVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
    Definition: scip_var.c:5875
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24142
    int SCIPvarGetIndex(SCIP_VAR *var)
    Definition: var.c:23652
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23267
    SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
    Definition: scip_var.c:1887
    SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
    Definition: var.c:23490
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24234
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24120
    SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
    Definition: scip_var.c:184
    SCIP_RETCODE SCIPincludeSepaEccuts(SCIP *scip)
    Definition: sepa_eccuts.c:3136
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    #define BMSclearMemory(ptr)
    Definition: memory.h:129
    #define BMSclearMemoryArray(ptr, num)
    Definition: memory.h:130
    internal methods for NLP management
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    #define SCIPstatisticMessage
    Definition: pub_message.h:123
    #define SCIPdebug(x)
    Definition: pub_message.h:93
    #define SCIPdebugMessage
    Definition: pub_message.h:96
    #define SCIPstatistic(x)
    Definition: pub_message.h:120
    SCIP_RETCODE SCIPincludeDefaultPlugins(SCIP *scip)
    default SCIP plugins
    #define SEPA_PRIORITY
    Definition: sepa_eccuts.c:47
    #define CLIQUE_MINWEIGHT
    Definition: sepa_eccuts.c:55
    static SCIP_RETCODE doSeachEcAggr(SCIP *scip, SCIP *subscip, SCIP_SEPADATA *sepadata, SCIP_NLROW *nlrow, SCIP_SOL *sol, SCIP_Bool rhsaggr, int *quadvar2aggr, int *nfound)
    Definition: sepa_eccuts.c:1554
    static SCIP_RETCODE ecaggrAddBilinTerm(SCIP *scip, SCIP_ECAGGR *ecaggr, SCIP_VAR *x, SCIP_VAR *y, SCIP_Real coef)
    Definition: sepa_eccuts.c:237
    static SCIP_RETCODE sepadataCreate(SCIP *scip, SCIP_SEPADATA **sepadata)
    Definition: sepa_eccuts.c:728
    static SCIP_RETCODE searchEcAggrWithMIP(SCIP *subscip, SCIP_Real timelimit, int nedges, SCIP_Bool *aggrleft, SCIP_Bool *found)
    Definition: sepa_eccuts.c:1248
    #define SEPA_DELAY
    Definition: sepa_eccuts.c:51
    static SCIP_RETCODE nlrowaggrCreate(SCIP *scip, SCIP_NLROW *nlrow, SCIP_NLROWAGGR **nlrowaggr, int *quadvar2aggr, int nfound, SCIP_Bool rhsaggr)
    Definition: sepa_eccuts.c:430
    static SCIP_DECL_SEPAFREE(sepaFreeEccuts)
    Definition: sepa_eccuts.c:3024
    static SCIP_RETCODE ecaggrAddQuadvar(SCIP_ECAGGR *ecaggr, SCIP_VAR *x)
    Definition: sepa_eccuts.c:226
    #define USEDUALSIMPLEX
    Definition: sepa_eccuts.c:76
    #define ADJUSTFACETTOL
    Definition: sepa_eccuts.c:75
    static SCIP_Real transformValue(SCIP *scip, SCIP_Real lb, SCIP_Real ub, SCIP_Real val)
    Definition: sepa_eccuts.c:2241
    #define CLIQUE_MAXFIRSTNODEWEIGHT
    Definition: sepa_eccuts.c:53
    static SCIP_RETCODE separateCuts(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, int depth, SCIP_SOL *sol, SCIP_RESULT *result)
    Definition: sepa_eccuts.c:2934
    #define DEFAULT_DYNAMICCUTS
    Definition: sepa_eccuts.c:59
    static SCIP_RETCODE addFacetToCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_Real *facet, SCIP_VAR **vars, int nvars, SCIP_Real *cutconstant, SCIP_Real *cutactivity, SCIP_Bool *success)
    Definition: sepa_eccuts.c:2493
    static SCIP_RETCODE sepadataAddNlrowaggr(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_NLROWAGGR *nlrowaggr)
    Definition: sepa_eccuts.c:800
    static SCIP_RETCODE findAndStoreEcAggregations(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_NLROW *nlrow, SCIP_SOL *sol)
    Definition: sepa_eccuts.c:1915
    #define SEPA_DESC
    Definition: sepa_eccuts.c:46
    static SCIP_RETCODE nlrowaggrAddLinearTerm(SCIP *scip, SCIP_NLROWAGGR *nlrowaggr, SCIP_VAR *linvar, SCIP_Real lincoef)
    Definition: sepa_eccuts.c:352
    #define DEFAULT_MAXROUNDSROOT
    Definition: sepa_eccuts.c:61
    static SCIP_RETCODE updateMIP(SCIP *subscip, SCIP_NLROW *nlrow, SCIP_VAR **forwardarcs, SCIP_VAR **backwardarcs, int *quadvar2aggr, int *nedges)
    Definition: sepa_eccuts.c:1083
    #define SEPA_USESSUBSCIP
    Definition: sepa_eccuts.c:50
    static SCIP_RETCODE searchEcAggr(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_NLROW *nlrow, SCIP_SOL *sol, SCIP_Bool rhsaggr, int *quadvar2aggr, int *nfound)
    Definition: sepa_eccuts.c:1751
    static SCIP_RETCODE nlrowaggrAddQuadraticVar(SCIP *scip, SCIP_NLROWAGGR *nlrowaggr, SCIP_VAR *quadvar)
    Definition: sepa_eccuts.c:385
    static SCIP_RETCODE addBilinearTermToCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_VAR *x, SCIP_VAR *y, SCIP_Real coeff, SCIP_Real *cutconstant, SCIP_Real *cutactivity, SCIP_Bool *success)
    Definition: sepa_eccuts.c:2602
    #define DEFAULT_MAXDEPTH
    Definition: sepa_eccuts.c:62
    static SCIP_Bool isPossibleToComputeCut(SCIP *scip, SCIP_SOL *sol, SCIP_NLROWAGGR *nlrowaggr)
    Definition: sepa_eccuts.c:2891
    static SCIP_Real phi(SCIP *scip, SCIP_Real val, SCIP_Real lb, SCIP_Real ub)
    Definition: sepa_eccuts.c:844
    #define DEFAULT_MINVIOLATION
    Definition: sepa_eccuts.c:67
    static SCIP_RETCODE sepadataFreeNlrows(SCIP *scip, SCIP_SEPADATA *sepadata)
    Definition: sepa_eccuts.c:744
    #define CLIQUE_BACKTRACKFREQ
    Definition: sepa_eccuts.c:57
    #define CLIQUE_MAXNTREENODES
    Definition: sepa_eccuts.c:56
    static SCIP_RETCODE nlrowaggrFree(SCIP *scip, SCIP_NLROWAGGR **nlrowaggr)
    Definition: sepa_eccuts.c:652
    static SCIP_RETCODE nlrowaggrAddRemBilinTerm(SCIP_NLROWAGGR *nlrowaggr, SCIP_VAR *x, SCIP_VAR *y, SCIP_Real coef)
    Definition: sepa_eccuts.c:405
    static SCIP_RETCODE addLinearTermToCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_VAR *x, SCIP_Real coeff, SCIP_Real *cutconstant, SCIP_Real *cutactivity, SCIP_Bool *success)
    Definition: sepa_eccuts.c:2551
    static SCIP_RETCODE storeAggrFromMIP(SCIP *subscip, SCIP_NLROW *nlrow, SCIP_VAR **forwardarcs, SCIP_VAR **backwardarcs, int *quadvar2aggr, int nfoundsofar)
    Definition: sepa_eccuts.c:1162
    static SCIP_DECL_SEPAEXITSOL(sepaExitsolEccuts)
    Definition: sepa_eccuts.c:3039
    #define DEFAULT_MAXSEPACUTSROOT
    Definition: sepa_eccuts.c:64
    static SCIP_DECL_SEPACOPY(sepaCopyEccuts)
    Definition: sepa_eccuts.c:3010
    static SCIP_DECL_SEPAEXECLP(sepaExeclpEccuts)
    Definition: sepa_eccuts.c:3066
    static SCIP_RETCODE computeCut(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, SCIP_NLROWAGGR *nlrowaggr, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
    Definition: sepa_eccuts.c:2716
    static SCIP_RETCODE sepadataFree(SCIP *scip, SCIP_SEPADATA **sepadata)
    Definition: sepa_eccuts.c:774
    #define DEFAULT_MAXAGGRSIZE
    Definition: sepa_eccuts.c:69
    static SCIP_RETCODE createTcliqueGraph(SCIP_NLROW *nlrow, TCLIQUE_GRAPH **graph, SCIP_Real *nodeweights)
    Definition: sepa_eccuts.c:1314
    static SCIP_RETCODE ecaggrFree(SCIP *scip, SCIP_ECAGGR **ecaggr)
    Definition: sepa_eccuts.c:205
    #define SEPA_MAXBOUNDDIST
    Definition: sepa_eccuts.c:49
    static SCIP_RETCODE createLP(SCIP *scip, SCIP_SEPADATA *sepadata)
    Definition: sepa_eccuts.c:2091
    #define DEFAULT_MINAGGRSIZE
    Definition: sepa_eccuts.c:68
    static SCIP_RETCODE computeConvexEnvelopeFacet(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_SOL *sol, SCIP_ECAGGR *ecaggr, SCIP_Real *facet, SCIP_Real *facetval, SCIP_Bool *success)
    Definition: sepa_eccuts.c:2285
    #define SEPA_FREQ
    Definition: sepa_eccuts.c:48
    static SCIP_RETCODE createMIP(SCIP *scip, SCIP *subscip, SCIP_SEPADATA *sepadata, SCIP_NLROW *nlrow, SCIP_Bool rhsaggr, SCIP_VAR **forwardarcs, SCIP_VAR **backwardarcs, SCIP_Real *nodeweights, int *nedges, int *narcs)
    Definition: sepa_eccuts.c:869
    static SCIP_Bool checkRikun(SCIP *scip, SCIP_ECAGGR *ecaggr, SCIP_Real *fvals, SCIP_Real *facet)
    Definition: sepa_eccuts.c:2020
    #define DEFAULT_MAXSEPACUTS
    Definition: sepa_eccuts.c:63
    #define SEPA_NAME
    Definition: sepa_eccuts.c:45
    #define DEFAULT_MAXSTALLROUNDS
    Definition: sepa_eccuts.c:71
    #define SUBSCIP_NODELIMIT
    Definition: sepa_eccuts.c:73
    #define DEFAULT_MAXBILINTERMS
    Definition: sepa_eccuts.c:70
    #define DEFAULT_MAXROUNDS
    Definition: sepa_eccuts.c:60
    static SCIP_RETCODE searchEcAggrWithCliques(SCIP *scip, TCLIQUE_GRAPH *graph, SCIP_SEPADATA *sepadata, SCIP_NLROW *nlrow, int *quadvar2aggr, int nfoundsofar, SCIP_Bool rhsaggr, SCIP_Bool *foundaggr, SCIP_Bool *foundclique)
    Definition: sepa_eccuts.c:1405
    static SCIP_RETCODE ecaggrCreateEmpty(SCIP *scip, SCIP_ECAGGR **ecaggr, int nquadvars, int nquadterms)
    Definition: sepa_eccuts.c:175
    static SCIP_Real evalCorner(SCIP_ECAGGR *ecaggr, int k)
    Definition: sepa_eccuts.c:2203
    #define DEFAULT_CUTMAXRANGE
    Definition: sepa_eccuts.c:65
    static SCIP_RETCODE isCandidate(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_NLROW *nlrow, SCIP_Bool *rhscandidate, SCIP_Bool *lhscandidate)
    Definition: sepa_eccuts.c:1784
    static const int poweroftwo[]
    Definition: sepa_eccuts.c:79
    static SCIP_RETCODE nlrowaggrStoreLinearTerms(SCIP *scip, SCIP_NLROWAGGR *nlrowaggr, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nlinvars)
    Definition: sepa_eccuts.c:311
    edge concave cut separator
    int * termvars1
    Definition: sepa_eccuts.c:95
    int termsize
    Definition: sepa_eccuts.c:98
    SCIP_Real * termcoefs
    Definition: sepa_eccuts.c:94
    int * termvars2
    Definition: sepa_eccuts.c:96
    int nterms
    Definition: sepa_eccuts.c:97
    SCIP_VAR ** vars
    Definition: sepa_eccuts.c:90
    int varsize
    Definition: sepa_eccuts.c:92
    int nvars
    Definition: sepa_eccuts.c:91
    SCIP_VAR ** linvars
    Definition: sepa_eccuts.c:112
    int linvarssize
    Definition: sepa_eccuts.c:115
    int remtermsize
    Definition: sepa_eccuts.c:127
    SCIP_VAR ** remtermvars2
    Definition: sepa_eccuts.c:124
    SCIP_Real * lincoefs
    Definition: sepa_eccuts.c:113
    SCIP_Bool rhsaggr
    Definition: sepa_eccuts.c:106
    SCIP_Real * remtermcoefs
    Definition: sepa_eccuts.c:125
    int quadvarssize
    Definition: sepa_eccuts.c:121
    int * quadvar2aggr
    Definition: sepa_eccuts.c:118
    SCIP_Real constant
    Definition: sepa_eccuts.c:130
    SCIP_VAR ** quadvars
    Definition: sepa_eccuts.c:117
    SCIP_Real rhs
    Definition: sepa_eccuts.c:129
    int nquadvars
    Definition: sepa_eccuts.c:120
    int nlinvars
    Definition: sepa_eccuts.c:114
    SCIP_NLROW * nlrow
    Definition: sepa_eccuts.c:105
    SCIP_ECAGGR ** ecaggr
    Definition: sepa_eccuts.c:109
    int nremterms
    Definition: sepa_eccuts.c:126
    SCIP_VAR ** remtermvars1
    Definition: sepa_eccuts.c:123
    SCIP_Real rhs
    Definition: struct_nlp.h:68
    tclique user interface
    @ TCLIQUE_OPTIMAL
    Definition: tclique.h:66
    void tcliqueChangeWeight(TCLIQUE_GRAPH *tcliquegraph, int node, TCLIQUE_WEIGHT weight)
    void tcliqueFree(TCLIQUE_GRAPH **tcliquegraph)
    enum TCLIQUE_Status TCLIQUE_STATUS
    Definition: tclique.h:68
    void tcliqueMaxClique(TCLIQUE_GETNNODES((*getnnodes)), TCLIQUE_GETWEIGHTS((*getweights)), TCLIQUE_ISEDGE((*isedge)), TCLIQUE_SELECTADJNODES((*selectadjnodes)), TCLIQUE_GRAPH *tcliquegraph, TCLIQUE_NEWSOL((*newsol)), TCLIQUE_DATA *tcliquedata, int *maxcliquenodes, int *nmaxcliquenodes, TCLIQUE_WEIGHT *maxcliqueweight, TCLIQUE_WEIGHT maxfirstnodeweight, TCLIQUE_WEIGHT minweight, int maxntreenodes, int backtrackfreq, int maxnzeroextensions, int fixednode, int *ntreenodes, TCLIQUE_STATUS *status)
    TCLIQUE_Bool tcliqueFlush(TCLIQUE_GRAPH *tcliquegraph)
    struct TCLIQUE_Graph TCLIQUE_GRAPH
    Definition: tclique.h:49
    TCLIQUE_Bool tcliqueCreate(TCLIQUE_GRAPH **tcliquegraph)
    TCLIQUE_Bool tcliqueAddNode(TCLIQUE_GRAPH *tcliquegraph, int node, TCLIQUE_WEIGHT weight)
    TCLIQUE_Bool tcliqueAddEdge(TCLIQUE_GRAPH *tcliquegraph, int node1, int node2)
    @ SCIP_OBJSEN_MINIMIZE
    Definition: type_lpi.h:43
    @ SCIP_PARAMSETTING_AGGRESSIVE
    Definition: type_paramset.h:61
    @ SCIP_OBJSENSE_MAXIMIZE
    Definition: type_prob.h:47
    @ 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_PARAMETERWRONGVAL
    Definition: type_retcode.h:57
    @ 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
    @ SCIP_STATUS_UNBOUNDED
    Definition: type_stat.h:45
    @ SCIP_STATUS_INFORUNBD
    Definition: type_stat.h:46
    @ SCIP_STATUS_INFEASIBLE
    Definition: type_stat.h:44
    @ SCIP_VARTYPE_BINARY
    Definition: type_var.h:64