Scippy

    SCIP

    Solving Constraint Integer Programs

    sepa_clique.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_clique.c
    26 * @ingroup DEFPLUGINS_SEPA
    27 * @brief clique separator
    28 * @author Kati Wolter
    29 * @author Tobias Achterberg
    30 */
    31
    32/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    33
    35#include "scip/pub_implics.h"
    36#include "scip/pub_lp.h"
    37#include "scip/pub_message.h"
    38#include "scip/pub_misc.h"
    39#include "scip/pub_sepa.h"
    40#include "scip/pub_var.h"
    41#include "scip/scip_branch.h"
    42#include "scip/scip_cut.h"
    43#include "scip/scip_general.h"
    44#include "scip/scip_lp.h"
    45#include "scip/scip_mem.h"
    46#include "scip/scip_message.h"
    47#include "scip/scip_numerics.h"
    48#include "scip/scip_param.h"
    49#include "scip/scip_prob.h"
    50#include "scip/scip_sepa.h"
    51#include "scip/scip_sol.h"
    52#include "scip/scip_var.h"
    53#include "scip/sepa_clique.h"
    54#include "tclique/tclique.h"
    55#include <string.h>
    56#ifndef _WIN32
    57#include <strings.h> /*lint --e{766}*/
    58#endif
    59
    60
    61#define SEPA_NAME "clique"
    62#define SEPA_DESC "clique separator of stable set relaxation"
    63#define SEPA_PRIORITY -5000
    64#define SEPA_FREQ 0
    65#define SEPA_MAXBOUNDDIST 0.0
    66#define SEPA_USESSUBSCIP FALSE /**< does the separator use a secondary SCIP instance? */
    67#define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
    68
    69#define DEFAULT_SCALEVAL 1000.0 /**< factor for scaling weights */
    70#define DEFAULT_MAXTREENODES 10000 /**< maximal number of nodes in branch and bound tree (-1: no limit) */
    71#define DEFAULT_BACKTRACKFREQ 1000 /**< frequency for premature backtracking up to tree level 1 (0: no backtracking) */
    72#define DEFAULT_MAXSEPACUTS 10 /**< maximal number of clique cuts separated per separation round (-1: no limit) */
    73#define DEFAULT_MAXZEROEXTENSIONS 1000 /**< maximal number of zero-valued variables extending the clique (-1: no limit) */
    74#define DEFAULT_CLIQUETABLEMEM 20000.0 /**< maximal memory size of dense clique table (in kb) */
    75#define DEFAULT_CLIQUEDENSITY 0.00 /**< minimal density of cliques to use a dense clique table */
    76
    77
    78/*
    79 * Data structures
    80 */
    81
    82/** separator data */
    83struct SCIP_SepaData
    84{
    85 TCLIQUE_GRAPH* tcliquegraph; /**< tclique graph data structure */
    86 SCIP* scip; /**< SCIP data structure */
    87 SCIP_SEPA* sepa; /**< separator */
    88 SCIP_SOL* sol; /**< primal solution that is currently separated */
    89 SCIP_Real* varsolvals; /**< LP solution of binary variables (contained in a 3-clique in implgraph) */
    90 SCIP_Real scaleval; /**< factor for scaling weights */
    91 SCIP_Longint ncalls; /**< number of calls to the clique separator */
    92 int maxtreenodes; /**< maximal number of nodes in branch and bound tree (-1: no limit) */
    93 int backtrackfreq; /**< frequency for premature backtracking up to tree level 1 (0: no backtracking) */
    94 int maxsepacuts; /**< maximal number of clique cuts separated per separation round (-1: no limit) */
    95 int maxzeroextensions; /**< maximal number of zero-valued variables extending the clique (-1: no limit) */
    96 SCIP_Real cliquetablemem; /**< maximal memory size of dense clique table (in kb) */
    97 SCIP_Real cliquedensity; /**< minimal density of cliques to use a dense clique table */
    98 int ncuts; /**< number of cuts found */
    99 SCIP_Bool tcliquegraphloaded; /**< TRUE if tcliquegraph is already loaded (tcliquegraph can be NULL),
    100 * FALSE otherwise */
    101 SCIP_Bool cutoff; /**< whether the clique algorithm detected a cutoff */
    102 SCIP_RETCODE retcode; /**< error code which might occur during the maximal clique algorithm */
    103};
    104
    105/** tclique graph data */
    106struct TCLIQUE_Graph
    107{
    108 SCIP_VAR** vars; /**< active problem variables (or negated variables) the nodes belong to */
    109 TCLIQUE_WEIGHT* weights; /**< weight of nodes */
    110 int* adjnodesidxs; /**< indices in adjnodes array of first adjacent nodes for each node */
    111 int* cliqueidsidxs; /**< indices in cliqueids array of first clique the node is contained in */
    112 int* adjnodes; /**< adjacent nodes of edges */
    113 unsigned int* cliqueids; /**< unique ids of cliques */
    114 unsigned int* cliquetable; /**< dense bitvector clique table (array stored as a vector) */
    115 int adjnodessize; /**< size of adjnodes array */
    116 int cliqueidssize; /**< size of cliqueids array */
    117 int nnodes; /**< number of nodes in graph */
    118 int tablewidth; /**< number of unsigned ints per row in the table */
    119
    120 int maxnnodes; /**< allocated memory for some arrays */
    121};
    122
    123
    124/*
    125 * Methods for tclique graph
    126 */
    127
    128/** creates an empty tclique graph data structure */
    129static
    131 SCIP* scip, /**< SCIP data structure */
    132 TCLIQUE_GRAPH** tcliquegraph /**< pointer to tclique graph data */
    133 )
    134{
    135 int maxnnodes;
    136
    137 assert(tcliquegraph != NULL);
    138
    139 SCIP_CALL( SCIPallocBlockMemory(scip, tcliquegraph) );
    140
    141 /* there are at most 2*nbinvars nodes in the graph */
    142 maxnnodes = 2*SCIPgetNBinVars(scip);
    143 assert(maxnnodes > 0);
    144
    145 /* allocate memory for tclique graph arrays */
    146 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*tcliquegraph)->vars, maxnnodes) );
    147 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*tcliquegraph)->weights, maxnnodes) );
    148 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*tcliquegraph)->adjnodesidxs, maxnnodes+1) );
    149 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*tcliquegraph)->cliqueidsidxs, maxnnodes+1) );
    150 (*tcliquegraph)->adjnodesidxs[0] = 0; /* the last slot defines the end of the last node */
    151 (*tcliquegraph)->cliqueidsidxs[0] = 0; /* the last slot defines the end of the last node */
    152 (*tcliquegraph)->adjnodes = NULL;
    153 (*tcliquegraph)->cliqueids = NULL;
    154 (*tcliquegraph)->cliquetable = NULL;
    155 (*tcliquegraph)->adjnodessize = 0;
    156 (*tcliquegraph)->cliqueidssize = 0;
    157 (*tcliquegraph)->nnodes = 0;
    158 (*tcliquegraph)->tablewidth = 0;
    159 (*tcliquegraph)->maxnnodes = maxnnodes; /* remember allocated memory */
    160
    161 return SCIP_OKAY;
    162}
    163
    164/** frees the tclique graph data structure and releases all captured variables */
    165static
    167 SCIP* scip, /**< SCIP data structure */
    168 TCLIQUE_GRAPH** tcliquegraph /**< pointer to tclique graph data */
    169 )
    170{
    171 int v;
    172
    173 assert(tcliquegraph != NULL);
    174 assert(*tcliquegraph != NULL);
    175
    176 /* release variables */
    177 for( v = 0; v < (*tcliquegraph)->nnodes; ++v )
    178 {
    179 SCIP_CALL( SCIPreleaseVar(scip, &(*tcliquegraph)->vars[v]) );
    180 }
    181
    182 /* free memory */
    183 SCIPfreeBlockMemoryArray(scip, &(*tcliquegraph)->vars, (*tcliquegraph)->maxnnodes);
    184 SCIPfreeBlockMemoryArray(scip, &(*tcliquegraph)->weights, (*tcliquegraph)->maxnnodes);
    185 SCIPfreeBlockMemoryArray(scip, &(*tcliquegraph)->adjnodesidxs, (*tcliquegraph)->maxnnodes + 1);
    186 SCIPfreeBlockMemoryArray(scip, &(*tcliquegraph)->cliqueidsidxs, (*tcliquegraph)->maxnnodes + 1);
    187 SCIPfreeMemoryArrayNull(scip, &(*tcliquegraph)->adjnodes);
    188 SCIPfreeMemoryArrayNull(scip, &(*tcliquegraph)->cliqueids);
    189 SCIPfreeMemoryArrayNull(scip, &(*tcliquegraph)->cliquetable);
    190 SCIPfreeBlockMemory(scip, tcliquegraph);
    191
    192 return SCIP_OKAY;
    193}
    194
    195
    196/** ensures that the cliqueids array can store at least num entries */
    197static
    199 SCIP* scip, /**< SCIP data structure */
    200 TCLIQUE_GRAPH* tcliquegraph, /**< tclique graph data */
    201 int num /**< minimal number of adjacent nodes to be able to store in the array */
    202 )
    203{
    204 assert(tcliquegraph != NULL);
    205
    206 if( num > tcliquegraph->cliqueidssize )
    207 {
    208 tcliquegraph->cliqueidssize = SCIPcalcMemGrowSize(scip, num);
    209 SCIP_CALL( SCIPreallocMemoryArray(scip, &tcliquegraph->cliqueids, tcliquegraph->cliqueidssize) );
    210 }
    211 assert(num <= tcliquegraph->cliqueidssize);
    212
    213 return SCIP_OKAY;
    214}
    215
    216/** adds a node to the tclique graph defined as a variable-value pair; adds all cliques to the cliqueids array the
    217 * variable is contained in with the given value
    218 */
    219static
    221 SCIP* scip, /**< SCIP data structure */
    222 TCLIQUE_GRAPH** tcliquegraph, /**< pointer to tclique graph data */
    223 SCIP_VAR* var, /**< active binary problem variable */
    224 SCIP_Bool value, /**< value of the variable in the node */
    225 int* nodeidx /**< pointer to store the index of the new node */
    226 )
    227{
    228 SCIP_VAR* nodevar;
    229 unsigned int* cliqueids;
    230 SCIP_CLIQUE** cliques;
    231 int ncliques;
    232 int nadjnodes;
    233 int ncliqueids;
    234 int i;
    235
    236 assert(tcliquegraph != NULL);
    238 assert(SCIPvarIsActive(var));
    239 assert(nodeidx != NULL);
    240
    241 /* create tclique graph data if not yet existing */
    242 if( *tcliquegraph == NULL )
    243 {
    244 SCIP_CALL( tcliquegraphCreate(scip, tcliquegraph) );
    245 }
    246 assert(*tcliquegraph != NULL);
    247 assert((*tcliquegraph)->nnodes < 2*SCIPgetNBinVars(scip));
    248
    249 /* if the value is FALSE, use the negated variable for the node */
    250 if( !value )
    251 {
    252 SCIP_CALL( SCIPgetNegatedVar(scip, var, &nodevar) );
    253 }
    254 else
    255 nodevar = var;
    256
    257 /* get the current number of used entries in adjnodes and cliqueids arrays */
    258 nadjnodes = (*tcliquegraph)->adjnodesidxs[(*tcliquegraph)->nnodes];
    259 ncliqueids = (*tcliquegraph)->cliqueidsidxs[(*tcliquegraph)->nnodes];
    260
    261 /* insert the variable into the tclique graph */
    262 *nodeidx = (*tcliquegraph)->nnodes;
    263 SCIP_CALL( SCIPcaptureVar(scip, nodevar) );
    264 (*tcliquegraph)->vars[*nodeidx] = nodevar;
    265 (*tcliquegraph)->weights[*nodeidx] = 0;
    266 (*tcliquegraph)->nnodes++;
    267
    268 /* store the ids of the variable's cliques in the cliqueids array */
    269 ncliques = SCIPvarGetNCliques(var, value);
    270 cliques = SCIPvarGetCliques(var, value);
    271 SCIP_CALL( tcliquegraphEnsureCliqueidsSize(scip, *tcliquegraph, ncliqueids + ncliques) );
    272 cliqueids = (*tcliquegraph)->cliqueids;
    273 for( i = 0; i < ncliques; ++i )
    274 {
    275 assert(ncliqueids < (*tcliquegraph)->cliqueidssize);
    276 cliqueids[ncliqueids] = SCIPcliqueGetId(cliques[i]);
    277 assert(i == 0 || cliqueids[ncliqueids-1] <= cliqueids[ncliqueids]);
    278 ncliqueids++;
    279 }
    280
    281 /* store the new number of used entries in adjnodes and cliqueids arrays */
    282 (*tcliquegraph)->adjnodesidxs[(*tcliquegraph)->nnodes] = nadjnodes;
    283 (*tcliquegraph)->cliqueidsidxs[(*tcliquegraph)->nnodes] = ncliqueids;
    284
    285 return SCIP_OKAY;
    286}
    287
    288/** adds all variable/value pairs to the tclique graph that are contained in an existing 3-clique */
    289static
    291 SCIP* scip, /**< SCIP data structure */
    292 TCLIQUE_GRAPH** tcliquegraph, /**< pointer to tclique graph data */
    293 int** cliquegraphidx /**< array to store tclique graph node index of variable/value pairs */
    294 )
    295{
    296 SCIP_VAR** vars;
    297 int nvars;
    298 int i;
    299
    300 assert(tcliquegraph != NULL);
    301 assert(cliquegraphidx != NULL);
    302 assert(cliquegraphidx[0] != NULL);
    303 assert(cliquegraphidx[1] != NULL);
    304
    305 /* get binary problem variables */
    306 vars = SCIPgetVars(scip);
    307 nvars = SCIPgetNBinVars(scip);
    308
    309 for( i = 0; i < nvars; ++i )
    310 {
    311 SCIP_VAR* var;
    312 int value;
    313
    314 var = vars[i];
    315
    316 for( value = 0; value < 2; ++value )
    317 {
    318 assert(cliquegraphidx[value][i] == -1);
    319
    320 if( SCIPvarGetNCliques(var, (SCIP_Bool)value) >= 1 )
    321 {
    322 /* all cliques stored in the clique table are at least 3-cliques */
    323 SCIP_CALL( tcliquegraphAddNode(scip, tcliquegraph, var, (SCIP_Bool)value, &cliquegraphidx[value][i]) );
    324 }
    325 }
    326 }
    327
    328 return SCIP_OKAY;
    329}
    330
    331/** constructs dense clique incidence matrix
    332 *
    333 * @todo add implicit and integer variables appearing in cliques also to the clique table
    334 */
    335static
    337 SCIP* scip, /**< SCIP data structure */
    338 TCLIQUE_GRAPH* tcliquegraph, /**< tclique graph data */
    339 SCIP_Real cliquetablemem, /**< maximal memory size of dense clique table (in kb) */
    340 SCIP_Real cliquedensity /**< minimal density of cliques to store as dense table */
    341 )
    342{
    343 SCIP_CLIQUE** cliques;
    344 int* varids;
    345 unsigned int* cliquetable;
    347 int nbits;
    348 int tablesize;
    349 int tablewidth;
    350 int ncliques;
    351 int nelems;
    352 int i;
    353
    354 cliques = SCIPgetCliques(scip);
    355 ncliques = SCIPgetNCliques(scip);
    356 if( ncliques == 0 )
    357 return SCIP_OKAY;
    358
    359 assert(tcliquegraph != NULL);
    360
    361 /* calculate size of dense clique table */
    362 nbits = 8*sizeof(unsigned int);
    363 tcliquegraph->tablewidth = (tcliquegraph->nnodes + nbits-1) / nbits; /* number of ints needed */
    364
    365 /* check if dense clique table is too large (calculate as Reals to avoid overflow) */
    366 if( (SCIP_Real)tcliquegraph->nnodes * (SCIP_Real)tcliquegraph->tablewidth/1024.0 > cliquetablemem )
    367 return SCIP_OKAY;
    368
    369 /* calculate clique entry density */
    370 nelems = 0;
    371 for( i = 0; i < ncliques; ++i )
    372 nelems += SCIPcliqueGetNVars(cliques[i]);
    373 density = (SCIP_Real)nelems / ((SCIP_Real)ncliques * (SCIP_Real)tcliquegraph->nnodes);
    374 if( density < cliquedensity )
    375 return SCIP_OKAY;
    376
    377 /* allocate memory */
    378 tablesize = tcliquegraph->nnodes * tcliquegraph->tablewidth;
    379 SCIPdebugMsg(scip, "clique separator: constructing dense clique table (%d kb, %d cliques, %d nodes, density: %.2f)\n",
    380 tablesize/1024, SCIPgetNCliques(scip), tcliquegraph->nnodes, density);
    381
    382 SCIP_CALL( SCIPallocMemoryArray(scip, &tcliquegraph->cliquetable, tablesize) );
    383 BMSclearMemoryArray(tcliquegraph->cliquetable, tablesize);
    384
    385 /* insert the cliques as complete graphs to the incidence matrix */
    386 SCIP_CALL( SCIPallocBufferArray(scip, &varids, tcliquegraph->nnodes) );
    387 cliquetable = tcliquegraph->cliquetable;
    388 tablewidth = tcliquegraph->tablewidth;
    389 for( i = 0; i < ncliques && !SCIPisStopped(scip); ++i )
    390 {
    391 SCIP_VAR** vars;
    392 SCIP_Bool* vals;
    393 int nvars;
    394 int u;
    395 int v;
    396
    397 vars = SCIPcliqueGetVars(cliques[i]);
    398 vals = SCIPcliqueGetValues(cliques[i]);
    399 nvars = SCIPcliqueGetNVars(cliques[i]);
    400
    401 /* get the node numbers of the variables */
    402 for( u = 0; u < nvars && !SCIPisStopped(scip); ++u )
    403 {
    404 SCIP_VAR* var;
    405
    406 /* implicit integer and integer variables are currently not present in the constructed tclique graph */
    408 continue;
    409
    410 var = (vals[u] ? vars[u] : SCIPvarGetNegatedVar(vars[u]));
    411 assert(var != NULL); /* var must exist even if negated, since it is stored in the tcliquegraph */
    412 for( v = 0; v < tcliquegraph->nnodes && var != tcliquegraph->vars[v]; ++v )
    413 {}
    414 assert(v < tcliquegraph->nnodes);
    415 varids[u] = v;
    416 }
    417
    418 /* flag the edges in the incidence matrix (excluding diagonal entries) */
    419 for( u = 0; u < nvars-1 && !SCIPisStopped(scip); ++u )
    420 {
    421 int nu;
    422 int rowstart;
    423 int colofs;
    424 unsigned int colmask;
    425
    426 /* implicit integer and integer variables are currently not present in the constructed tclique graph */
    428 continue;
    429
    430 nu = varids[u];
    431 rowstart = nu*tablewidth;
    432 colofs = nu/nbits;
    433 colmask = 1U << (nu % nbits); /*lint !e701*/
    434 for( v = u+1; v < nvars; ++v )
    435 {
    436 int nv;
    437 unsigned int mask;
    438
    439 /* implicit integer and integer variables are currently not present in the constructed tclique graph */
    441 continue;
    442
    443 nv = varids[v];
    444 mask = 1U << (nv % nbits); /*lint !e701*/
    445 cliquetable[rowstart+nv/nbits] |= mask;
    446 cliquetable[nv*tablewidth+colofs] |= colmask;
    447 }
    448 }
    449 }
    450 SCIPfreeBufferArray(scip, &varids);
    451
    452 SCIPdebugMsg(scip, "clique separator: finished constructing dense clique table\n");
    453
    454 return SCIP_OKAY;
    455}
    456
    457/** creates tclique data structure using the implication graph;
    458 * only variables that are contained in a 3-clique are added as nodes to the clique graph
    459 */
    460static
    462 SCIP* scip, /**< SCIP data structure */
    463 SCIP_SEPADATA* sepadata /**< separator data */
    464 )
    465{
    466 int* cliquegraphidx[2];
    467 int nvars;
    468 int i;
    469
    470 assert(sepadata != NULL);
    471 assert(sepadata->tcliquegraph == NULL);
    472
    473 /* there is nothing to do, if no binary variables are present in the problem */
    474 nvars = SCIPgetNBinVars(scip);
    475 if( nvars == 0 )
    476 return SCIP_OKAY;
    477
    478 /* get temporary memory for mapping variable/value pairs to clique graph nodes */
    479 SCIP_CALL( SCIPallocBufferArray(scip, &cliquegraphidx[0], nvars) );
    480 SCIP_CALL( SCIPallocBufferArray(scip, &cliquegraphidx[1], nvars) );
    481 for( i = 0; i < nvars; ++i )
    482 {
    483 cliquegraphidx[0][i] = -1;
    484 cliquegraphidx[1][i] = -1;
    485 }
    486
    487 /* insert all variable/value pairs that are contained in an existing 3-clique */
    488 SCIP_CALL( tcliquegraphAddCliqueVars(scip, &sepadata->tcliquegraph, cliquegraphidx) );
    489
    490 /* it occurs that it might be that some cliques were not yet removed from the global clique array, so SCIPgetNClique
    491 * can be greater than 0, even if there is no clique with some variables left */
    492 /** @todo clean up empty cliques */
    493 if( sepadata->tcliquegraph != NULL )
    494 {
    495 /* construct the dense clique table */
    496 SCIP_CALL( tcliquegraphConstructCliqueTable(scip, sepadata->tcliquegraph, sepadata->cliquetablemem, sepadata->cliquedensity) );
    497 }
    498
    499 /* free temporary memory */
    500 SCIPfreeBufferArray(scip, &cliquegraphidx[1]);
    501 SCIPfreeBufferArray(scip, &cliquegraphidx[0]);
    502 if( SCIPisStopped(scip) && sepadata->tcliquegraph != NULL )
    503 SCIP_CALL( tcliquegraphFree(scip,&sepadata->tcliquegraph) );
    504 return SCIP_OKAY;
    505}
    506
    507/** updates the weights in the tclique graph data structure */
    508static
    510 SCIP* scip, /**< SCIP data structure */
    511 SCIP_SEPADATA* sepadata /**< separator data */
    512 )
    513{
    514 TCLIQUE_GRAPH* tcliquegraph;
    515 int i;
    516
    517 assert(sepadata != NULL);
    518 assert(sepadata->varsolvals != NULL);
    519
    520 tcliquegraph = sepadata->tcliquegraph;
    521 assert(tcliquegraph != NULL);
    522
    523 /* updates weight of all nodes in tclique data structure */
    524 for( i = 0; i < tcliquegraph->nnodes; i++ )
    525 {
    526 int weight;
    527
    528 weight = (TCLIQUE_WEIGHT)SCIPfeasFloor(scip, sepadata->varsolvals[i] * sepadata->scaleval);
    529 tcliquegraph->weights[i] = MAX(weight, 0);
    530 }
    531}
    532
    533
    534/*
    535 * TClique Graph Callbacks
    536 */
    537
    538/** gets number of nodes in the graph */
    539static
    540TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
    541{
    542 assert(tcliquegraph != NULL);
    543
    544 return tcliquegraph->nnodes;
    545}
    546
    547/** gets weight of nodes in the graph */
    548static
    549TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
    550{
    551 assert(tcliquegraph != NULL);
    552
    553 return tcliquegraph->weights;
    554}
    555
    556/** returns whether the nodes are member of a common clique */
    557static
    559 TCLIQUE_GRAPH* tcliquegraph, /**< tclique graph data */
    560 int node1, /**< first node */
    561 int node2 /**< second node */
    562 )
    563{
    564 assert(tcliquegraph != NULL);
    565
    566 /* return TRUE for equal nodes */
    567 if( node1 == node2 )
    568 return TRUE;
    569
    570 /* check whether the dense clique table was constructed */
    571 if( tcliquegraph->cliquetable != NULL )
    572 {
    573 int nbits;
    574 unsigned int mask;
    575 int colofs;
    576
    577 /* check entry in the table */
    578 nbits = 8*sizeof(unsigned int);
    579 mask = (1U << (node2 % nbits)); /*lint !e701*/
    580 colofs = node2 / nbits;
    581 assert(((tcliquegraph->cliquetable[node1*tcliquegraph->tablewidth + colofs] & mask) != 0)
    582 == ((tcliquegraph->cliquetable[node2*tcliquegraph->tablewidth + node1/nbits] & (1U << (node1 % nbits))) != 0)); /*lint !e701*/
    583 return ((tcliquegraph->cliquetable[node1*tcliquegraph->tablewidth + colofs] & mask) != 0);
    584 }
    585 else
    586 {
    587 unsigned int* cliqueids;
    588 int i1;
    589 int i2;
    590 int endi1;
    591 int endi2;
    592
    593 cliqueids = tcliquegraph->cliqueids;
    594 i1 = tcliquegraph->cliqueidsidxs[node1];
    595 endi1 = tcliquegraph->cliqueidsidxs[node1+1];
    596 i2 = tcliquegraph->cliqueidsidxs[node2];
    597 endi2 = tcliquegraph->cliqueidsidxs[node2+1];
    598 while( i1 < endi1 && i2 < endi2 )
    599 {
    600 while( i1 < endi1 && cliqueids[i1] < cliqueids[i2] )
    601 i1++;
    602 if( i1 == endi1 )
    603 break;
    604
    605 while( i2 < endi2 && cliqueids[i2] < cliqueids[i1] )
    606 i2++;
    607 if( i2 == endi2 )
    608 break;
    609
    610 if( cliqueids[i1] == cliqueids[i2] )
    611 return TRUE;
    612 }
    613
    614 return FALSE;
    615 }
    616}
    617
    618/** returns whether the edge (node1, node2) is in the graph */
    619static
    620TCLIQUE_ISEDGE(tcliqueIsedgeClique)
    621{
    622 int left;
    623 int right;
    624
    625 assert(tcliquegraph != NULL);
    626 assert(0 <= node1 && node1 < tcliquegraph->nnodes);
    627 assert(0 <= node2 && node2 < tcliquegraph->nnodes);
    628
    629 /* check if node2 is contained in adjacency list of node1 (list is ordered by adjacent nodes) */
    630 left = tcliquegraph->adjnodesidxs[node1];
    631 right = tcliquegraph->adjnodesidxs[node1+1]-1;
    632 while( left <= right )
    633 {
    634 int middle;
    635 int node;
    636
    637 middle = (left+right)/2;
    638 node = tcliquegraph->adjnodes[middle];
    639 if( node < node2 )
    640 left = middle+1;
    641 else if( node > node2 )
    642 right = middle-1;
    643 else
    644 return TRUE;
    645 }
    646
    647 /* check if the nodes are member of a common clique */
    648 return nodesHaveCommonClique(tcliquegraph, node1, node2);
    649}
    650
    651/** selects all nodes from a given set of nodes which are adjacent to a given node
    652 * and returns the number of selected nodes
    653 */
    654static
    655TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
    656{
    657 int* graphadjnodes;
    658 int nadjnodes;
    659 int nodeadjindex;
    660 int nodeadjend;
    661 int i;
    662
    663 assert(tcliquegraph != NULL);
    664 assert(0 <= node && node < tcliquegraph->nnodes);
    665 assert(nnodes == 0 || nodes != NULL);
    666 assert(adjnodes != NULL);
    667
    668 nadjnodes = 0;
    669
    670 /* check for each node in given nodes set, if it is adjacent to the given node or shares a common clique */
    671 graphadjnodes = tcliquegraph->adjnodes;
    672 nodeadjindex = tcliquegraph->adjnodesidxs[node];
    673 nodeadjend = tcliquegraph->adjnodesidxs[node+1];
    674 for( i = 0; i < nnodes; i++ )
    675 {
    676 /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
    677 assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
    678 assert(i == 0 || nodes[i-1] < nodes[i]);
    679 while( nodeadjindex < nodeadjend && graphadjnodes[nodeadjindex] < nodes[i] )
    680 nodeadjindex++;
    681 if( nodeadjindex < nodeadjend && graphadjnodes[nodeadjindex] == nodes[i] )
    682 {
    683 /* current node is adjacent to given node */
    684 adjnodes[nadjnodes] = nodes[i];
    685 nadjnodes++;
    686 }
    687 else
    688 {
    689 /* current node is not adjacent to given node: check if they share a common clique */
    690 if( nodesHaveCommonClique(tcliquegraph, node, nodes[i]) )
    691 {
    692 adjnodes[nadjnodes] = nodes[i];
    693 nadjnodes++;
    694 }
    695 }
    696 }
    697
    698 return nadjnodes;
    699}
    700
    701/** basic code for new cliques (needed because of error handling) */
    702static
    704 SCIP* scip, /**< SCIP data structure */
    705 SCIP_SEPA* sepa, /**< the cut separator itself */
    706 SCIP_SEPADATA* sepadata, /**< data of separator */
    707 int ncliquenodes, /**< number of nodes in clique */
    708 int* cliquenodes /**< nodes in clique */
    709 )
    710{
    711 SCIP_VAR** vars;
    712 SCIP_ROW* cut;
    713 char cutname[SCIP_MAXSTRLEN];
    714 int i;
    715
    716 vars = sepadata->tcliquegraph->vars;
    717 assert(sepadata->tcliquegraph->nnodes > 0);
    718 assert(vars != NULL);
    719
    720 /* create the cut (handle retcode since we do not have a backtrace) */
    721 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "clique%" SCIP_LONGINT_FORMAT "_%d", sepadata->ncalls, sepadata->ncuts);
    722 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), 1.0, FALSE, FALSE, TRUE) );
    723
    725
    726 assert(ncliquenodes <= sepadata->tcliquegraph->nnodes);
    727 /*SCIPdebugMsg(scip, " -> clique in graph:");*/
    728 for( i = 0; i < ncliquenodes; ++i )
    729 {
    730 assert(cliquenodes[i] < sepadata->tcliquegraph->nnodes);
    731 SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[cliquenodes[i]], 1.0) );
    732 /*SCIPdebugMsgPrint(scip, " [%d]<%s>", cliquenodes[i], SCIPvarGetName(vars[cliquenodes[i]]));*/
    733 }
    734 /*SCIPdebugMsgPrint(scip, "\n");*/
    736
    737 /* set cut rank: for clique cuts we always set to 1 */
    738 SCIProwChgRank(cut, 1);
    739
    740 /*SCIPdebug( SCIP_CALL(SCIPprintRow(scip, cut, NULL)) );*/
    741
    743
    744 /* release the row */
    745 SCIP_CALL( SCIPreleaseRow(scip, &cut) );
    746
    747 return SCIP_OKAY;
    748}
    749
    750/** generates cuts using a clique found by algorithm for maximum weight clique
    751 * and decides whether to stop generating cliques with the algorithm for maximum weight clique
    752 */
    753static
    754TCLIQUE_NEWSOL(tcliqueNewsolClique)
    755{
    756 SCIP_SEPADATA* sepadata;
    757 TCLIQUE_WEIGHT minweightinc;
    758
    759 assert(acceptsol != NULL);
    760 assert(stopsolving != NULL);
    761
    762 sepadata = (SCIP_SEPADATA*)tcliquedata;
    763 assert(sepadata != NULL);
    764 assert(sepadata->scip != NULL);
    765 assert(sepadata->sepa != NULL);
    766 assert(sepadata->tcliquegraph != NULL);
    767 assert(sepadata->ncuts >= 0);
    768
    769 /* we don't accept the solution as new incumbent, because we want to find many violated clique inequalities */
    770 *acceptsol = FALSE;
    771 *stopsolving = FALSE;
    772
    773 /* slightly increase the minimal weight for additional cliques */
    774 minweightinc = (cliqueweight - *minweight)/10;
    775 minweightinc = MAX(minweightinc, 1);
    776 *minweight += minweightinc;
    777
    778 /* adds cut if weight of the clique is greater than 1 */
    779 if( cliqueweight > sepadata->scaleval )
    780 {
    781 SCIP* scip;
    782 SCIP_SEPA* sepa;
    783 SCIP_Real* varsolvals;
    784 SCIP_Real unscaledweight;
    785 int i;
    786
    787 scip = sepadata->scip;
    788 sepa = sepadata->sepa;
    789 varsolvals = sepadata->varsolvals;
    790 assert(varsolvals != NULL);
    791
    792 /* calculate the weight of the clique in unscaled fractional variable space */
    793 unscaledweight = 0.0;
    794 for( i = 0; i < ncliquenodes; i++ )
    795 unscaledweight += varsolvals[cliquenodes[i]];
    796
    797 if( SCIPisEfficacious(scip, unscaledweight - 1.0) )
    798 {
    799 SCIP_RETCODE retcode;
    800
    801 /* explicitly handle return code */
    802 retcode = newsolCliqueAddRow(scip, sepa, sepadata, ncliquenodes, cliquenodes);
    803 if ( retcode == SCIP_OKAY )
    804 {
    805 SCIPdebugMsg(scip, " -> found clique cut (act=%g)\n", unscaledweight);
    806 sepadata->ncuts++;
    807
    808 /* if we found more than half the cuts we are allowed to generate, we accept the clique as new incumbent,
    809 * such that only more violated cuts are generated afterwards */
    810 if( sepadata->maxsepacuts >= 0 )
    811 {
    812 if( sepadata->ncuts > sepadata->maxsepacuts/2 )
    813 *acceptsol = TRUE;
    814 if( sepadata->ncuts >= sepadata->maxsepacuts )
    815 *stopsolving = TRUE;
    816 }
    817 }
    818 else
    819 {
    820 /* in case an internal SCIP error occurred we stop the algorithm and store the error code for later
    821 * evaluation
    822 */
    823 sepadata->retcode = retcode;
    824 *stopsolving = TRUE;
    825 }
    826 }
    827 }
    828}
    829
    830
    831/*
    832 * main separation method
    833 */
    834
    835/** searches and adds clique cuts that separate the given primal solution
    836 *
    837 * @todo Should the existing cliques in the table be separated before starting the tclique algorithm?
    838 * Is this done somewhere else?
    839 */
    840static
    842 SCIP* scip, /**< SCIP data structure */
    843 SCIP_SEPA* sepa, /**< the cut separator itself */
    844 SCIP_SOL* sol, /**< primal solution that should be separated, or NULL for LP solution */
    845 SCIP_RESULT* result /**< pointer to store the result of the separation call */
    846 )
    847{ /*lint --e{715}*/
    848 SCIP_SEPADATA* sepadata;
    849 TCLIQUE_GRAPH* tcliquegraph;
    850 int* cliquenodes;
    851 TCLIQUE_WEIGHT cliqueweight;
    852 TCLIQUE_STATUS tcliquestatus;
    853 int ncliquenodes;
    854 int maxtreenodes;
    855 int maxzeroextensions;
    856 SCIP_Bool infeasible;
    857
    858 assert(scip != NULL);
    859 assert(*result == SCIP_DIDNOTRUN);
    860
    861 infeasible = FALSE;
    862 /* get clique table */
    863 SCIP_CALL( SCIPcleanupCliques(scip, &infeasible) );
    864 if( infeasible )
    865 return SCIP_OKAY;
    866
    867 /* get separator data */
    868 sepadata = SCIPsepaGetData(sepa);
    869 assert(sepadata != NULL);
    870
    871 sepadata->sol = sol;
    872 sepadata->ncalls = SCIPsepaGetNCalls(sepa);
    873 sepadata->cutoff = FALSE;
    874 sepadata->ncuts = 0;
    875
    876 /* if we already detected that no implications between binary variables exist, nothing has to be done */
    877 if( sepadata->tcliquegraph == NULL && sepadata->tcliquegraphloaded )
    878 return SCIP_OKAY;
    879
    880 *result = SCIP_DIDNOTFIND;
    881
    882 /* load tclique data structure */
    883 if( !sepadata->tcliquegraphloaded )
    884 {
    885 assert(sepadata->tcliquegraph == NULL);
    886
    887 SCIPdebugMsg(scip, "loading implication and clique graph\n");
    888 SCIP_CALL( loadTcliquegraph(scip, sepadata) );
    889 sepadata->tcliquegraphloaded = TRUE;
    890
    891 if( sepadata->tcliquegraph == NULL )
    892 {
    893 if( SCIPisStopped(scip) )
    894 sepadata->tcliquegraphloaded = FALSE;
    895 /* we did not find any variables that are contained in a clique with at least 3 variables in the
    896 * implication graph or in the clique table -> nothing has to be done
    897 */
    898 else
    899 {
    900 SCIPdebugMsg(scip, "no 3-cliques found in implication graph\n");
    901 }
    902
    903 return SCIP_OKAY;
    904 }
    905 }
    906 tcliquegraph = sepadata->tcliquegraph;
    907 assert(tcliquegraph != NULL);
    908
    909 /* store LP-solution in sepadata and update weights in tclique data structure */
    910 SCIP_CALL( SCIPallocBufferArray(scip, &sepadata->varsolvals, tcliquegraph->nnodes) );
    911 SCIP_CALL( SCIPgetSolVals(scip, sol, tcliquegraph->nnodes, tcliquegraph->vars, sepadata->varsolvals) );
    912 updateTcliquegraph(scip, sepadata);
    913
    914 /* get maximal number of tree nodes and maximal zero-extensions */
    915 maxtreenodes = (sepadata->maxtreenodes == -1 ? INT_MAX : sepadata->maxtreenodes);
    916 maxzeroextensions = (sepadata->maxzeroextensions == -1 ? INT_MAX : sepadata->maxzeroextensions);
    917
    918 SCIPdebugMsg(scip, "searching for violated clique cuts\n");
    919
    920 sepadata->retcode = SCIP_OKAY;
    921
    922 /* finds maximum weight clique in tclique */
    923 SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, tcliquegraph->nnodes) );
    924 tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
    925 tcliquegraph, tcliqueNewsolClique, (TCLIQUE_DATA*)sepadata,
    926 cliquenodes, &ncliquenodes, &cliqueweight, (int)sepadata->scaleval-1, (int)sepadata->scaleval+1,
    927 maxtreenodes, sepadata->backtrackfreq, maxzeroextensions, -1, NULL, &tcliquestatus);
    928
    929 /* in case an internal error occurred during the maximal clique computation, evaluate that one */
    930 SCIP_CALL( sepadata->retcode );
    931
    932 SCIPdebugMsg(scip, "finished searching clique cuts: found %d cuts\n", sepadata->ncuts);
    933
    934 /* frees data structures */
    935 SCIPfreeBufferArray(scip, &cliquenodes);
    936 SCIPfreeBufferArray(scip, &sepadata->varsolvals);
    937
    938 /* adjust result code */
    939 if ( sepadata->cutoff )
    940 *result = SCIP_CUTOFF;
    941 else if( sepadata->ncuts > 0 )
    942 *result = SCIP_SEPARATED;
    943
    944 /* better reset the sol pointer in sepadata to avoid having an invalid pointer */
    945 sepadata->sol = NULL;
    946
    947 return SCIP_OKAY;
    948}
    949
    950
    951/*
    952 * Callback methods of separator
    953 */
    954
    955/** copy method for separator plugins (called when SCIP copies plugins) */
    956static
    957SCIP_DECL_SEPACOPY(sepaCopyClique)
    958{ /*lint --e{715}*/
    959 assert(scip != NULL);
    960 assert(sepa != NULL);
    961 assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
    962
    963 /* call inclusion method of constraint handler */
    965
    966 return SCIP_OKAY;
    967}
    968
    969
    970/** destructor of separator to free user data (called when SCIP is exiting) */
    971static
    972SCIP_DECL_SEPAFREE(sepaFreeClique)
    973{ /*lint --e{715}*/
    974 SCIP_SEPADATA* sepadata;
    975
    976 sepadata = SCIPsepaGetData(sepa);
    977 assert(sepadata != NULL);
    978 assert(sepadata->tcliquegraph == NULL);
    979
    980 SCIPfreeBlockMemory(scip, &sepadata);
    981 SCIPsepaSetData(sepa, NULL);
    982
    983 return SCIP_OKAY;
    984}
    985
    986
    987/** solving process deinitialization method of separator (called before branch and bound process data is freed) */
    988static
    989SCIP_DECL_SEPAEXITSOL(sepaExitsolClique)
    990{ /*lint --e{715}*/
    991 SCIP_SEPADATA* sepadata;
    992
    993 sepadata = SCIPsepaGetData(sepa);
    994 assert(sepadata != NULL);
    995
    996 /* free tclique data */
    997 if( sepadata->tcliquegraph != NULL )
    998 {
    999 SCIP_CALL( tcliquegraphFree(scip, &sepadata->tcliquegraph) );
    1000 }
    1001 assert(sepadata->tcliquegraph == NULL);
    1002 sepadata->tcliquegraphloaded = FALSE;
    1003
    1004 return SCIP_OKAY;
    1005}
    1006
    1007
    1008/** LP solution separation method of separator */
    1009static
    1010SCIP_DECL_SEPAEXECLP(sepaExeclpClique)
    1011{
    1012 /*lint --e{715}*/
    1013
    1014 *result = SCIP_DIDNOTRUN;
    1015
    1016 /* only call separator, if we are not close to terminating */
    1017 if( SCIPisStopped(scip) )
    1018 return SCIP_OKAY;
    1019
    1020 /* only call separator, if an optimal LP solution is at hand */
    1022 return SCIP_OKAY;
    1023
    1024 /* only call separator, if there are fractional variables */
    1025 if( SCIPgetNLPBranchCands(scip) == 0 )
    1026 return SCIP_OKAY;
    1027
    1028 /* separate cuts on the LP solution */
    1029 SCIP_CALL( separateCuts(scip, sepa, NULL, result) );
    1030
    1031 return SCIP_OKAY;
    1032}
    1033
    1034
    1035/** arbitrary primal solution separation method of separator */
    1036static
    1037SCIP_DECL_SEPAEXECSOL(sepaExecsolClique)
    1038{
    1039 /*lint --e{715}*/
    1040
    1041 *result = SCIP_DIDNOTRUN;
    1042
    1043 /* separate cuts on the given primal solution */
    1044 SCIP_CALL( separateCuts(scip, sepa, sol, result) );
    1045
    1046 return SCIP_OKAY;
    1047}
    1048
    1049
    1050/*
    1051 * separator specific interface methods
    1052 */
    1053
    1054/** creates the clique separator and includes it in SCIP */
    1056 SCIP* scip /**< SCIP data structure */
    1057 )
    1058{
    1059 SCIP_SEPADATA* sepadata;
    1060 SCIP_SEPA* sepa;
    1061
    1062 /* create clique separator data */
    1063 SCIP_CALL( SCIPallocBlockMemory(scip, &sepadata) );
    1064 sepadata->tcliquegraph = NULL;
    1065 sepadata->scip = scip;
    1066 sepadata->sol = NULL;
    1067 sepadata->varsolvals = NULL;
    1068 sepadata->ncalls = 0;
    1069 sepadata->ncuts = 0;
    1070 sepadata->tcliquegraphloaded = FALSE;
    1071
    1072 /* include separator */
    1075 sepaExeclpClique, sepaExecsolClique,
    1076 sepadata) );
    1077
    1078 assert(sepa != NULL);
    1079 sepadata->sepa = sepa;
    1080
    1081 /* set non-NULL pointers to callback methods */
    1082 SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyClique) );
    1083 SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeClique) );
    1084 SCIP_CALL( SCIPsetSepaExitsol(scip, sepa, sepaExitsolClique) );
    1085
    1086 /* add clique separator parameters */
    1088 "separating/clique/scaleval",
    1089 "factor for scaling weights",
    1090 &sepadata->scaleval, TRUE, DEFAULT_SCALEVAL, 1.0, SCIP_REAL_MAX, NULL, NULL) );
    1092 "separating/clique/maxtreenodes",
    1093 "maximal number of nodes in branch and bound tree (-1: no limit)",
    1094 &sepadata->maxtreenodes, TRUE, DEFAULT_MAXTREENODES, -1, INT_MAX, NULL, NULL) );
    1096 "separating/clique/backtrackfreq",
    1097 "frequency for premature backtracking up to tree level 1 (0: no backtracking)",
    1098 &sepadata->backtrackfreq, TRUE, DEFAULT_BACKTRACKFREQ, 0, INT_MAX, NULL, NULL) );
    1100 "separating/clique/maxsepacuts",
    1101 "maximal number of clique cuts separated per separation round (-1: no limit)",
    1102 &sepadata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, -1, INT_MAX, NULL, NULL) );
    1104 "separating/clique/maxzeroextensions",
    1105 "maximal number of zero-valued variables extending the clique (-1: no limit)",
    1106 &sepadata->maxzeroextensions, TRUE, DEFAULT_MAXZEROEXTENSIONS, -1, INT_MAX, NULL, NULL) );
    1108 "separating/clique/cliquetablemem",
    1109 "maximal memory size of dense clique table (in kb)",
    1110 &sepadata->cliquetablemem, TRUE, DEFAULT_CLIQUETABLEMEM, 0.0, (SCIP_Real)INT_MAX/1024.0, NULL, NULL) );
    1112 "separating/clique/cliquedensity",
    1113 "minimal density of cliques to use a dense clique table",
    1114 &sepadata->cliquedensity, TRUE, DEFAULT_CLIQUEDENSITY, 0.0, 1.0, NULL, NULL) );
    1115
    1116 return SCIP_OKAY;
    1117}
    #define NULL
    Definition: def.h:248
    #define SCIP_MAXSTRLEN
    Definition: def.h:269
    #define SCIP_Longint
    Definition: def.h:141
    #define SCIP_REAL_MAX
    Definition: def.h:158
    #define SCIP_Bool
    Definition: def.h:91
    #define SCIP_Real
    Definition: def.h:156
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define MAX(x, y)
    Definition: def.h:220
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:148
    #define SCIP_CALL(x)
    Definition: def.h:355
    #define nnodes
    Definition: gastrans.c:74
    static const SCIP_Real density
    Definition: gastrans.c:145
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:759
    SCIP_VAR ** SCIPgetVars(SCIP *scip)
    Definition: scip_prob.c:2201
    int SCIPgetNBinVars(SCIP *scip)
    Definition: scip_prob.c:2293
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:83
    SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:139
    int SCIPgetNLPBranchCands(SCIP *scip)
    Definition: scip_branch.c:436
    SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
    Definition: scip_cut.c:336
    SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
    Definition: scip_cut.c:135
    SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
    Definition: scip_lp.c:174
    #define SCIPfreeMemoryArrayNull(scip, ptr)
    Definition: scip_mem.h:81
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    #define SCIPreallocMemoryArray(scip, ptr, newnum)
    Definition: scip_mem.h:70
    #define SCIPallocMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:64
    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 SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    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 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
    void SCIProwChgRank(SCIP_ROW *row, int rank)
    Definition: lp.c:17928
    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
    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_Longint SCIPsepaGetNCalls(SCIP_SEPA *sepa)
    Definition: sepa.c:873
    SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
    Definition: scip_sol.c:1846
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
    SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
    Definition: var.c:23868
    SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
    Definition: var.c:23642
    SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23498
    SCIP_CLIQUE ** SCIPgetCliques(SCIP *scip)
    Definition: scip_var.c:9566
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23453
    SCIP_RETCODE SCIPcleanupCliques(SCIP *scip, SCIP_Bool *infeasible)
    Definition: scip_var.c:9469
    SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
    Definition: scip_var.c:1887
    SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
    Definition: scip_var.c:2166
    int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24642
    int SCIPgetNCliques(SCIP *scip)
    Definition: scip_var.c:9512
    SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24653
    SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:1853
    SCIP_RETCODE SCIPincludeSepaClique(SCIP *scip)
    Definition: sepa_clique.c:1055
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
    Definition: implics.c:3384
    int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
    Definition: implics.c:3374
    SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
    Definition: implics.c:3396
    unsigned int SCIPcliqueGetId(SCIP_CLIQUE *clique)
    Definition: implics.c:3406
    memory allocation routines
    #define BMSclearMemoryArray(ptr, num)
    Definition: memory.h:130
    public methods for implications, variable bounds, and cliques
    public methods for LP management
    public methods for message output
    public data structures and miscellaneous methods
    public methods for separators
    public methods for problem variables
    public methods for branching rule plugins and branching
    public methods for cuts and aggregation rows
    general public methods
    public methods for the LP relaxation, rows and columns
    public methods for memory management
    public methods for message handling
    public methods for numerical tolerances
    public methods for SCIP parameter handling
    public methods for global and local (sub)problems
    public methods for separator plugins
    public methods for solutions
    public methods for SCIP variables
    static SCIP_DECL_SEPAEXITSOL(sepaExitsolClique)
    Definition: sepa_clique.c:989
    #define SEPA_PRIORITY
    Definition: sepa_clique.c:63
    #define DEFAULT_SCALEVAL
    Definition: sepa_clique.c:69
    static SCIP_RETCODE tcliquegraphAddNode(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph, SCIP_VAR *var, SCIP_Bool value, int *nodeidx)
    Definition: sepa_clique.c:220
    #define DEFAULT_MAXTREENODES
    Definition: sepa_clique.c:70
    static SCIP_RETCODE tcliquegraphCreate(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
    Definition: sepa_clique.c:130
    #define SEPA_DELAY
    Definition: sepa_clique.c:67
    #define DEFAULT_CLIQUEDENSITY
    Definition: sepa_clique.c:75
    static SCIP_RETCODE tcliquegraphAddCliqueVars(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph, int **cliquegraphidx)
    Definition: sepa_clique.c:290
    static TCLIQUE_ISEDGE(tcliqueIsedgeClique)
    Definition: sepa_clique.c:620
    static SCIP_RETCODE tcliquegraphConstructCliqueTable(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_Real cliquetablemem, SCIP_Real cliquedensity)
    Definition: sepa_clique.c:336
    #define SEPA_DESC
    Definition: sepa_clique.c:62
    #define DEFAULT_BACKTRACKFREQ
    Definition: sepa_clique.c:71
    #define DEFAULT_CLIQUETABLEMEM
    Definition: sepa_clique.c:74
    #define SEPA_USESSUBSCIP
    Definition: sepa_clique.c:66
    static SCIP_DECL_SEPAEXECLP(sepaExeclpClique)
    Definition: sepa_clique.c:1010
    #define DEFAULT_MAXZEROEXTENSIONS
    Definition: sepa_clique.c:73
    static TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
    Definition: sepa_clique.c:655
    static SCIP_RETCODE tcliquegraphEnsureCliqueidsSize(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int num)
    Definition: sepa_clique.c:198
    static SCIP_RETCODE newsolCliqueAddRow(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, int ncliquenodes, int *cliquenodes)
    Definition: sepa_clique.c:703
    static SCIP_Bool nodesHaveCommonClique(TCLIQUE_GRAPH *tcliquegraph, int node1, int node2)
    Definition: sepa_clique.c:558
    static SCIP_RETCODE separateCuts(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
    Definition: sepa_clique.c:841
    static TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
    Definition: sepa_clique.c:549
    #define SEPA_MAXBOUNDDIST
    Definition: sepa_clique.c:65
    #define SEPA_FREQ
    Definition: sepa_clique.c:64
    static SCIP_DECL_SEPACOPY(sepaCopyClique)
    Definition: sepa_clique.c:957
    static TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
    Definition: sepa_clique.c:540
    #define DEFAULT_MAXSEPACUTS
    Definition: sepa_clique.c:72
    #define SEPA_NAME
    Definition: sepa_clique.c:61
    static SCIP_DECL_SEPAFREE(sepaFreeClique)
    Definition: sepa_clique.c:972
    static SCIP_DECL_SEPAEXECSOL(sepaExecsolClique)
    Definition: sepa_clique.c:1037
    static TCLIQUE_NEWSOL(tcliqueNewsolClique)
    Definition: sepa_clique.c:754
    static SCIP_RETCODE loadTcliquegraph(SCIP *scip, SCIP_SEPADATA *sepadata)
    Definition: sepa_clique.c:461
    static SCIP_RETCODE tcliquegraphFree(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
    Definition: sepa_clique.c:166
    static void updateTcliquegraph(SCIP *scip, SCIP_SEPADATA *sepadata)
    Definition: sepa_clique.c:509
    clique separator
    tclique user interface
    enum TCLIQUE_Status TCLIQUE_STATUS
    Definition: tclique.h:68
    int TCLIQUE_WEIGHT
    Definition: tclique.h:48
    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)
    struct TCLIQUE_Graph TCLIQUE_GRAPH
    Definition: tclique.h:49
    @ SCIP_LPSOLSTAT_OPTIMAL
    Definition: type_lp.h:44
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_CUTOFF
    Definition: type_result.h:48
    @ SCIP_DIDNOTFIND
    Definition: type_result.h:44
    @ SCIP_SEPARATED
    Definition: type_result.h:49
    enum SCIP_Result SCIP_RESULT
    Definition: type_result.h:61
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    struct SCIP_SepaData SCIP_SEPADATA
    Definition: type_sepa.h:52
    @ SCIP_VARTYPE_BINARY
    Definition: type_var.h:64