Scippy

    SCIP

    Solving Constraint Integer Programs

    tclique_branch.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program */
    4/* TCLIQUE --- Algorithm for Maximum Cliques */
    5/* */
    6/* Copyright (c) 1996-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 TCLIQUE; see the file LICENSE. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file tclique_branch.c
    26 * @ingroup OTHER_CFILES
    27 * @brief branch and bound part of algorithm for maximum cliques
    28 * @author Tobias Achterberg
    29 * @author Ralf Borndoerfer
    30 * @author Zoltan Kormos
    31 * @author Kati Wolter
    32 */
    33
    34/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    35
    36#include <stdio.h>
    37#include <assert.h>
    38#include <stdlib.h>
    39#include <limits.h>
    40
    41#include "tclique/tclique.h"
    42#include "tclique/tclique_def.h"
    45
    46
    47
    48#define CHUNK_SIZE (64)
    49#define CLIQUEHASH_INITSIZE (1024)
    50
    51
    52
    53
    54/***************************
    55 * clique hash table methods
    56 ***************************/
    57
    58typedef struct clique CLIQUE; /**< single element of the clique hash table */
    59
    60/** single element of the clique hash table */
    61struct clique
    62{
    63 int* nodes; /**< node number of the clique elements */
    64 int nnodes; /**< length of the clique */
    65};
    66
    67typedef struct cliquehash CLIQUEHASH; /**< hash table for storing cliques */
    68
    69/** hash table for storing cliques */
    70struct cliquehash
    71{
    72 CLIQUE** cliques; /**< elements of the table */
    73 int cliquessize; /**< size of the table */
    74 int ncliques; /**< number of cliques stored in the table */
    75};
    76
    77
    78/** creates a clique */
    79static
    81 CLIQUE** clique, /**< pointer to the clique */
    82 int* nodes, /**< nodes of the clique */
    83 int nnodes /**< number of nodes in the clique */
    84 )
    85{
    86 int i;
    87
    88 assert(clique != NULL);
    89
    90 ALLOC_ABORT( BMSallocMemory(clique) );
    91 ALLOC_ABORT( BMSallocMemoryArray(&(*clique)->nodes, nnodes) );
    92
    93 /* sort the nodes into the clique's node array */
    94 for( i = 0; i < nnodes; ++i )
    95 {
    96 int node;
    97 int j;
    98
    99 node = nodes[i];
    100 for( j = i; j > 0 && node < (*clique)->nodes[j-1]; --j )
    101 (*clique)->nodes[j] = (*clique)->nodes[j-1];
    102 (*clique)->nodes[j] = node;
    103 }
    104 (*clique)->nnodes = nnodes;
    105}
    106
    107/** frees a clique */
    108static
    110 CLIQUE** clique /**< pointer to the clique */
    111 )
    112{
    113 assert(clique != NULL);
    114 assert(*clique != NULL);
    115
    116 BMSfreeMemoryArray(&(*clique)->nodes);
    117 BMSfreeMemory(clique);
    118}
    119
    120/** checks whether clique1 is a subset of clique2 and returns the following value:
    121 * == 0 if clique1 == clique2, or clique1 is contained in clique2,
    122 * < 0 if clique1 < clique2, and clique1 is not contained in clique2,
    123 * > 0 if clique1 > clique2, and clique1 is not contained in clique2
    124 */
    125static
    127 CLIQUE* clique1, /**< first clique to compare */
    128 CLIQUE* clique2 /**< second clique to compare */
    129 )
    130{
    131 int pos1;
    132 int pos2;
    133 TCLIQUE_Bool clique2smaller;
    134
    135 assert(clique1 != NULL);
    136 assert(clique2 != NULL);
    137
    138 pos1 = 0;
    139 pos2 = 0;
    140 clique2smaller = FALSE;
    141 while( pos1 < clique1->nnodes && pos2 < clique2->nnodes )
    142 {
    143 if( clique1->nodes[pos1] < clique2->nodes[pos2] )
    144 {
    145 /* clique1 has an element not contained in clique2: clique1 is lex-smaller, if clique2 was not
    146 * detected earlier to be lex-smaller
    147 */
    148 return (clique2smaller ? +1 : -1);
    149 }
    150 else if( clique1->nodes[pos1] > clique2->nodes[pos2] )
    151 {
    152 /* clique2 has an element not contained in clique1: clique2 is lex-smaller, but probably clique1 is
    153 * contained in clique2
    154 */
    155 pos2++;
    156 clique2smaller = TRUE;
    157 }
    158 else
    159 {
    160 pos1++;
    161 pos2++;
    162 }
    163 }
    164
    165 /* if clique1 has additional elements, it is not contained in clique2 */
    166 if( pos1 < clique1->nnodes )
    167 return (clique2smaller ? +1 : -1);
    168
    169 /* clique1 is contained in clique2 */
    170 return 0;
    171}
    172
    173#ifndef NDEBUG
    174/** performs an integrity check of the clique hash table */
    175static
    177 CLIQUEHASH* cliquehash /**< clique hash table */
    178 )
    179{
    180 int i;
    181
    182 assert(cliquehash != NULL);
    183
    184 for( i = 0; i < cliquehash->ncliques-1; ++i )
    185 assert(compSubcliques(cliquehash->cliques[i], cliquehash->cliques[i+1]) < 0);
    186}
    187#else
    188#define checkCliquehash(cliquehash) /**/
    189#endif
    190
    191/** creates a table for storing cliques */
    192static
    194 CLIQUEHASH** cliquehash, /**< pointer to store the clique hash table */
    195 int tablesize /**< initial size of the clique hash table */
    196 )
    197{
    198 assert(cliquehash != NULL);
    199 assert(tablesize > 0);
    200
    201 ALLOC_ABORT( BMSallocMemory(cliquehash) );
    202 ALLOC_ABORT( BMSallocMemoryArray(&(*cliquehash)->cliques, tablesize) );
    203 (*cliquehash)->cliquessize = tablesize;
    204 (*cliquehash)->ncliques = 0;
    205}
    206
    207/** clears the clique hash table and frees all inserted cliques */
    208static
    210 CLIQUEHASH* cliquehash /**< clique hash table */
    211 )
    212{
    213 int i;
    214
    215 assert(cliquehash != NULL);
    216
    217 /* free the cliques in the table */
    218 for( i = 0; i < cliquehash->ncliques; ++i )
    219 freeClique(&cliquehash->cliques[i]);
    220
    221 cliquehash->ncliques = 0;
    222}
    223
    224/** frees the table for storing cliques and all inserted cliques */
    225static
    227 CLIQUEHASH** cliquehash /**< pointer to the clique hash table */
    228 )
    229{
    230 assert(cliquehash != NULL);
    231 assert(*cliquehash != NULL);
    232
    233 /* free the cliques in the table */
    234 clearCliquehash(*cliquehash);
    235
    236 /* free the table data structure */
    237 BMSfreeMemoryArray(&(*cliquehash)->cliques);
    238 BMSfreeMemory(cliquehash);
    239}
    240
    241/** ensures, that the clique hash table is able to store at least the given number of cliques */
    242static
    244 CLIQUEHASH* cliquehash, /**< clique hash table */
    245 int num /**< minimal number of cliques to store */
    246 )
    247{
    248 assert(cliquehash != NULL);
    249
    250 if( num > cliquehash->cliquessize )
    251 {
    252 int newsize;
    253
    254 newsize = 2*cliquehash->cliquessize;
    255 if( num > newsize )
    256 newsize = num;
    257
    258 ALLOC_ABORT( BMSreallocMemoryArray(&cliquehash->cliques, newsize) );
    259 cliquehash->cliquessize = newsize;
    260 }
    261 assert(cliquehash->cliquessize >= num);
    262}
    263
    264#ifdef TCLIQUE_DEBUG
    265/** displayes clique hash table */
    266static
    267void printCliquehash(
    268 CLIQUEHASH* cliquehash /**< clique hash table */
    269 )
    270{
    271 int i;
    272
    273 assert(cliquehash != NULL);
    274
    275 debugMessage("cliquehash (%d cliques):\n", cliquehash->ncliques);
    276 for( i = 0; i < cliquehash->ncliques; ++i )
    277 {
    278 int j;
    279
    280 debugPrintf("%d:", i);
    281 for( j = 0; j < cliquehash->cliques[i]->nnodes; ++j )
    282 debugPrintf(" %d", cliquehash->cliques[i]->nodes[j]);
    283 debugPrintf("\n");
    284 }
    285}
    286#endif
    287
    288/** searches the given clique in the clique hash table and returns whether it (or a stronger clique) exists */
    289static
    291 CLIQUEHASH* cliquehash, /**< clique hash table */
    292 CLIQUE* clique, /**< clique to search in the table */
    293 int* insertpos /**< position where the clique should be inserted in the table */
    294 )
    295{
    296 int left;
    297 int right;
    298 int middle;
    299 int cmp;
    300
    301 assert(cliquehash != NULL);
    302 assert(cliquehash->cliquessize > 0);
    303 assert(clique != NULL);
    304 assert(insertpos != NULL);
    305
    306 /* perform a binary search on the clique hash table */
    307 left = 0;
    308 right = cliquehash->ncliques-1;
    309 while( left <= right )
    310 {
    311 middle = (left+right)/2;
    312 cmp = compSubcliques(clique, cliquehash->cliques[middle]);
    313 if( cmp > 0 )
    314 left = middle+1;
    315 else if( cmp < 0 )
    316 right = middle-1;
    317 else
    318 {
    319 *insertpos = middle;
    320 return TRUE;
    321 }
    322 }
    323
    324 /* we found the correct insertion position for the clique, but it might be contained in a lex-smaller clique */
    325 *insertpos = left;
    326 for( middle = left-1; middle >= 0; --middle )
    327 {
    328 cmp = compSubcliques(clique, cliquehash->cliques[middle]);
    329 assert(cmp >= 0);
    330 if( cmp == 0 )
    331 return TRUE;
    332 }
    333
    334 return FALSE;
    335}
    336
    337/** inserts clique into clique hash table */
    338static
    340 CLIQUEHASH* cliquehash, /**< clique hash table */
    341 CLIQUE* clique, /**< clique to search in the table */
    342 int insertpos /**< position to insert clique into table (returned by inCliquehash()) */
    343 )
    344{
    345 int i;
    346
    347 assert(cliquehash != NULL);
    348 assert(clique != NULL);
    349 assert(0 <= insertpos && insertpos <= cliquehash->ncliques);
    350
    351 /* allocate memory */
    352 ensureCliquehashSize(cliquehash, cliquehash->ncliques+1);
    353
    354 /* insert clique into table */
    355 for( i = cliquehash->ncliques; i > insertpos; --i )
    356 cliquehash->cliques[i] = cliquehash->cliques[i-1];
    357 cliquehash->cliques[insertpos] = clique;
    358 cliquehash->ncliques++;
    359
    360 /* check, whether the clique hash table is still sorted */
    361 checkCliquehash(cliquehash);
    362
    363 debug(printCliquehash(cliquehash));
    364}
    365
    366
    367
    368
    369/****************************
    370 * clique calculation methods
    371 ****************************/
    372
    373/** extends given clique by additional zero-weight nodes of the given node set */
    374static
    376 TCLIQUE_SELECTADJNODES((*selectadjnodes)),/**< user function to select adjacent edges */
    377 TCLIQUE_GRAPH* tcliquegraph, /**< pointer to graph data structure */
    378 int* buffer, /**< buffer of size nnodes */
    379 int* Vzero, /**< zero weighted nodes */
    380 int nVzero, /**< number of zero weighted nodes */
    381 int maxnzeroextensions, /**< maximal number of zero-valued variables extending the clique */
    382 int* curcliquenodes, /**< nodes of the clique */
    383 int* ncurcliquenodes /**< pointer to store number of nodes in the clique */
    384 )
    385{
    386 int i;
    387 int* zerocands;
    388 int nzerocands;
    389 int nzeroextensions;
    390
    391 assert(selectadjnodes != NULL);
    392 assert(buffer != NULL);
    393 assert(Vzero != NULL);
    394 assert(curcliquenodes != NULL);
    395 assert(ncurcliquenodes != NULL);
    396
    397 debugMessage("extending temporary clique (size %d) with zero-weighted nodes (nVzero=%d)\n", *ncurcliquenodes, nVzero);
    398
    399 if( maxnzeroextensions == 0 )
    400 return;
    401
    402 /* initialize the zero-weighted candidates for clique extension */
    403 zerocands = buffer;
    404 BMScopyMemoryArray(zerocands, Vzero, nVzero);
    405 nzerocands = nVzero;
    406
    407 /* for each node in the clique, remove non-adjacent nodes from the zero extension candidates */
    408 for( i = 0; i < *ncurcliquenodes && nzerocands > 0; ++i )
    409 {
    410 nzerocands = selectadjnodes(tcliquegraph, curcliquenodes[i], zerocands, nzerocands, zerocands);
    411 }
    412
    413 /* put zero-weighted candidates into the clique, and remove non-adjacent nodes from the candidate set */
    414 nzeroextensions = 0;
    415 while( nzerocands > 0 )
    416 {
    417 /* put first candidate into the clique */
    418 curcliquenodes[*ncurcliquenodes] = zerocands[0];
    419 (*ncurcliquenodes)++;
    420 nzerocands--;
    421 zerocands++;
    422 nzeroextensions++;
    423 if( nzeroextensions >= maxnzeroextensions )
    424 break;
    425
    426 /* remove candidates that are not adjacent to the inserted zero-weighted node */
    427 nzerocands = selectadjnodes(tcliquegraph, curcliquenodes[(*ncurcliquenodes)-1], zerocands, nzerocands, zerocands);
    428 }
    429}
    430
    431/** calls user callback after a new solution was found, that is better than the current incumbent
    432 *
    433 * The callback decides, whether this solution should be accepted as new incumbent, and whether the solution process
    434 * should be stopped.
    435 */
    436static
    438 TCLIQUE_SELECTADJNODES((*selectadjnodes)), /**< user function to select adjacent edges */
    439 TCLIQUE_GRAPH* tcliquegraph, /**< pointer to graph data structure */
    440 TCLIQUE_NEWSOL((*newsol)), /**< user function to call on every new solution */
    441 TCLIQUE_DATA* tcliquedata, /**< user data to pass to user callback function */
    442 CLIQUEHASH* cliquehash, /**< clique hash table */
    443 int* buffer, /**< buffer of size nnodes */
    444 int* Vzero, /**< zero weighted nodes */
    445 int nVzero, /**< number of zero weighted nodes */
    446 int maxnzeroextensions, /**< maximal number of zero-valued variables extending the clique */
    447 int* curcliquenodes, /**< nodes of the new clique */
    448 int ncurcliquenodes, /**< number of nodes in the new clique */
    449 TCLIQUE_WEIGHT curcliqueweight, /**< weight of the new clique */
    450 int* maxcliquenodes, /**< pointer to store nodes of the maximum weight clique */
    451 int* nmaxcliquenodes, /**< pointer to store number of nodes in the maximum weight clique */
    452 TCLIQUE_WEIGHT* maxcliqueweight, /**< pointer to store weight of the maximum weight clique */
    453 TCLIQUE_Bool* stopsolving /**< pointer to store whether the solving should be stopped */
    454 )
    455{
    456 CLIQUE* clique;
    457 int insertpos;
    458 TCLIQUE_Bool acceptsol;
    459
    460 assert(curcliquenodes != NULL);
    461 assert(maxcliquenodes != NULL);
    462 assert(nmaxcliquenodes != NULL);
    463 assert(maxcliqueweight != NULL);
    464 assert(curcliqueweight > *maxcliqueweight);
    465 assert(stopsolving != NULL);
    466 assert(newsol == NULL || cliquehash != NULL);
    467
    468 acceptsol = TRUE;
    469 *stopsolving = FALSE;
    470 clique = NULL;
    471 insertpos = 0;
    472
    473 if( newsol != NULL )
    474 {
    475 /* check whether the clique is already stored in the table */
    476 if( cliquehash->ncliques > 0 )
    477 {
    478 createClique(&clique, curcliquenodes, ncurcliquenodes);
    479 acceptsol = !inCliquehash(cliquehash, clique, &insertpos);
    480 }
    481 }
    482
    483 /* check, if this is a new clique */
    484 if( acceptsol )
    485 {
    486 /* extend the clique with the zero-weighted nodes */
    487 extendCliqueZeroWeight(selectadjnodes, tcliquegraph, buffer, Vzero, nVzero, maxnzeroextensions,
    488 curcliquenodes, &ncurcliquenodes);
    489
    490 if( newsol != NULL )
    491 {
    492 /* call user callback method */
    493 newsol(tcliquedata, curcliquenodes, ncurcliquenodes, curcliqueweight, maxcliqueweight, &acceptsol, stopsolving);
    494
    495 /* if clique was accepted, clear the clique hash table; otherwise, insert it into the clique hash table, such that
    496 * the same or a weaker clique is not presented to the user again
    497 */
    498 if( acceptsol )
    499 clearCliquehash(cliquehash);
    500 else
    501 {
    502 /* if the clique was not yet created, do it now */
    503 if( clique == NULL )
    504 {
    505 assert(insertpos == 0);
    506 assert(cliquehash->ncliques == 0);
    507 createClique(&clique, curcliquenodes, ncurcliquenodes);
    508 }
    509
    510 /* insert clique into clique hash table */
    511 insertClique(cliquehash, clique, insertpos);
    512 clique = NULL; /* the clique now belongs to the table */
    513 }
    514 }
    515 }
    516
    517 /* free the clique, if it was created and not put into the clique hash table */
    518 if( clique != NULL )
    519 freeClique(&clique);
    520
    521 if( acceptsol )
    522 {
    523 /* copy the solution to the incumbent */
    524 BMScopyMemoryArray(maxcliquenodes, curcliquenodes, ncurcliquenodes);
    525 *nmaxcliquenodes = ncurcliquenodes;
    526 if( curcliqueweight > *maxcliqueweight )
    527 *maxcliqueweight = curcliqueweight;
    528 }
    529
    530#ifdef TCLIQUE_DEBUG
    531 debugMessage(" -> clique %s (weight %d):", acceptsol ? "accepted" : "rejected", curcliqueweight);
    532 {
    533 int i;
    534 for( i = 0; i < ncurcliquenodes; ++i )
    535 debugPrintf(" %d", curcliquenodes[i]);
    536 debugPrintf("\n");
    537 }
    538#endif
    539}
    540
    541/** tries to find a clique, if V has only one or two nodes */
    542static
    544 TCLIQUE_GETWEIGHTS((*getweights)), /**< user function to get the node weights */
    545 TCLIQUE_ISEDGE((*isedge)), /**< user function to check for existence of an edge */
    546 TCLIQUE_GRAPH* tcliquegraph, /**< pointer to graph data structure */
    547 int* V, /**< non-zero weighted nodes for branching */
    548 int nV, /**< number of non-zero weighted nodes for branching */
    549 TCLIQUE_WEIGHT* apbound, /**< apriori bound of nodes for branching */
    550 int* tmpcliquenodes, /**< buffer for storing the temporary clique */
    551 int* ntmpcliquenodes, /**< pointer to store number of nodes of the temporary clique */
    552 TCLIQUE_WEIGHT* tmpcliqueweight /**< pointer to store weight of the temporary clique */
    553 )
    554{
    555 const TCLIQUE_WEIGHT* weights;
    556
    557 assert(getweights != NULL);
    558 assert(isedge != NULL);
    559 assert(tcliquegraph != NULL);
    560 assert(V != NULL);
    561 assert(0 <= nV && nV <= 2);
    562 assert(apbound != NULL);
    563 assert(tmpcliquenodes != NULL);
    564 assert(ntmpcliquenodes != NULL);
    565 assert(tmpcliqueweight != NULL);
    566
    567 weights = getweights(tcliquegraph);
    568 assert(nV == 0 || weights[V[0]] > 0);
    569 assert(nV <= 1 || weights[V[1]] > 0);
    570
    571 if( nV >= 1 )
    572 apbound[0] = weights[V[0]];
    573 if( nV >= 2 )
    574 apbound[1] = weights[V[1]];
    575
    576 /* check if nodes are adjacent */
    577 if( nV >= 2 && isedge(tcliquegraph, V[0], V[1]) )
    578 {
    579 assert(isedge(tcliquegraph, V[1], V[0]));
    580
    581 /* put nodes into clique */
    582 tmpcliquenodes[0] = V[0];
    583 tmpcliquenodes[1] = V[1];
    584 *ntmpcliquenodes = 2;
    585 *tmpcliqueweight = weights[V[0]] + weights[V[1]];
    586 apbound[0] += weights[V[1]];
    587 }
    588 else if( nV >= 2 && weights[V[1]] > weights[V[0]] )
    589 {
    590 /* put V[1] into clique */
    591 tmpcliquenodes[0] = V[1];
    592 *ntmpcliquenodes = 1;
    593 *tmpcliqueweight = weights[V[1]];
    594 }
    595 else if( nV >= 1 )
    596 {
    597 /* put V[0] into clique */
    598 tmpcliquenodes[0] = V[0];
    599 *ntmpcliquenodes = 1;
    600 *tmpcliqueweight = weights[V[0]];
    601 }
    602 else
    603 {
    604 *tmpcliqueweight = 0;
    605 *ntmpcliquenodes = 0;
    606 }
    607}
    608
    609/** calculates upper bound on remaining subgraph, and heuristically generates a clique */
    610static
    612 TCLIQUE_GETNNODES((*getnnodes)), /**< user function to get the number of nodes */
    613 TCLIQUE_GETWEIGHTS((*getweights)), /**< user function to get the node weights */
    614 TCLIQUE_ISEDGE((*isedge)), /**< user function to check for existence of an edge */
    615 TCLIQUE_SELECTADJNODES((*selectadjnodes)), /**< user function to select adjacent edges */
    616 TCLIQUE_GRAPH* tcliquegraph, /**< pointer to graph data structure */
    617 BMS_CHKMEM* mem, /**< block memory */
    618 int* buffer, /**< buffer of size nnodes */
    619 int* V, /**< non-zero weighted nodes for branching */
    620 int nV, /**< number of non-zero weighted nodes for branching */
    621 NBC* gsd, /**< neighbour color information of all nodes */
    622 TCLIQUE_Bool* iscolored, /**< coloring status of all nodes */
    623 TCLIQUE_WEIGHT* apbound, /**< apriori bound of nodes for branching */
    624 int* tmpcliquenodes, /**< buffer for storing the temporary clique */
    625 int* ntmpcliquenodes, /**< pointer to store number of nodes of the temporary clique */
    626 TCLIQUE_WEIGHT* tmpcliqueweight /**< pointer to store weight of the temporary clique */
    627 )
    628{
    629 assert(tmpcliqueweight != NULL);
    630
    631 /* check if we are in an easy case with at most 2 nodes left */
    632 if( nV <= 2 )
    633 {
    634 /* get 1- or 2-clique and bounds without coloring */
    635 reduced(getweights, isedge, tcliquegraph, V, nV, apbound, tmpcliquenodes, ntmpcliquenodes, tmpcliqueweight);
    636 return *tmpcliqueweight;
    637 }
    638 else
    639 {
    640 /* color the graph induces by nodes of V to get an upper bound for the remaining subgraph */
    641 return tcliqueColoring(getnnodes, getweights, selectadjnodes, tcliquegraph,
    642 mem, buffer, V, nV, gsd, iscolored, apbound,
    643 tmpcliquenodes, ntmpcliquenodes, tmpcliqueweight);
    644 }
    645}
    646
    647/** gets the index of the node of V with the maximum apriori bound; returns -1, if no node exists */
    648static
    650 int nV, /**< number of nodes of V */
    651 TCLIQUE_WEIGHT* apbound /**< apriori bound of nodes of V */
    652 )
    653{
    654 TCLIQUE_WEIGHT maxapbound;
    655 int maxindex;
    656 int i;
    657
    658 assert(apbound != NULL);
    659
    660 maxapbound = 0;
    661 maxindex = -1;
    662
    663 for( i = 0 ; i < nV; i++ )
    664 {
    665 assert(apbound[i] > 0);
    666 if( apbound[i] >= maxapbound )
    667 {
    668 maxapbound = apbound[i];
    669 maxindex = i;
    670 }
    671 }
    672
    673 return maxindex;
    674}
    675
    676/** gets the index of the node of V with the maximum apriori bound, but ignores nodes with weights
    677 * larger than the given maximal weight
    678 *
    679 * Returns -1 if no node with weight smaller or equal than maxweight is found.
    680 */
    681static
    683 int* V, /**< non-zero weighted nodes for branching */
    684 int nV, /**< number of non-zero weighted nodes for branching */
    685 const TCLIQUE_WEIGHT* apbound, /**< apriori bound of nodes of V */
    686 const TCLIQUE_WEIGHT* weights, /**< weights of nodes */
    687 TCLIQUE_WEIGHT maxweight /**< maximal weight of node to be candidate for selection */
    688 )
    689{
    690 TCLIQUE_WEIGHT maxapbound;
    691 int maxindex;
    692 int i;
    693
    694 assert(apbound != NULL);
    695
    696 maxapbound = 0;
    697 maxindex = -1;
    698
    699 for( i = 0 ; i < nV; i++ )
    700 {
    701 assert(apbound[i] > 0);
    702 assert(weights[V[i]] > 0);
    703
    704 if( apbound[i] >= maxapbound && weights[V[i]] <= maxweight )
    705 {
    706 maxapbound = apbound[i];
    707 maxindex = i;
    708 }
    709 }
    710
    711 return maxindex;
    712}
    713
    714/** branches the searching tree, branching nodes are selected in decreasing order of their apriori bound,
    715 * returns the level to which we should backtrack, or INT_MAX for continuing normally
    716 */
    717static
    719 TCLIQUE_GETNNODES((*getnnodes)), /**< user function to get the number of nodes */
    720 TCLIQUE_GETWEIGHTS((*getweights)), /**< user function to get the node weights */
    721 TCLIQUE_ISEDGE((*isedge)), /**< user function to check for existence of an edge */
    722 TCLIQUE_SELECTADJNODES((*selectadjnodes)),/**< user function to select adjacent edges */
    723 TCLIQUE_GRAPH* tcliquegraph, /**< pointer to graph data structure */
    724 TCLIQUE_NEWSOL((*newsol)), /**< user function to call on every new solution */
    725 TCLIQUE_DATA* tcliquedata, /**< user data to pass to user callback function */
    726 BMS_CHKMEM* mem, /**< block memory */
    727 CLIQUEHASH* cliquehash, /**< clique hash table */
    728 int* buffer, /**< buffer of size nnodes */
    729 int level, /**< level of b&b tree */
    730 int* V, /**< non-zero weighted nodes for branching */
    731 int nV, /**< number of non-zero weighted nodes for branching */
    732 int* Vzero, /**< zero weighted nodes */
    733 int nVzero, /**< number of zero weighted nodes */
    734 NBC* gsd, /**< neighbour color information of all nodes */
    735 TCLIQUE_Bool* iscolored, /**< coloring status of all nodes */
    736 int* K, /**< nodes from the b&b tree */
    737 TCLIQUE_WEIGHT weightK, /**< weight of the nodes from b&b tree */
    738 int* maxcliquenodes, /**< pointer to store nodes of the maximum weight clique */
    739 int* nmaxcliquenodes, /**< pointer to store number of nodes in the maximum weight clique */
    740 TCLIQUE_WEIGHT* maxcliqueweight, /**< pointer to store weight of the maximum weight clique */
    741 int* curcliquenodes, /**< pointer to store nodes of currenct clique */
    742 int* ncurcliquenodes, /**< pointer to store number of nodes in current clique */
    743 TCLIQUE_WEIGHT* curcliqueweight, /**< pointer to store weight of current clique */
    744 int* tmpcliquenodes, /**< buffer for storing the temporary clique */
    745 TCLIQUE_WEIGHT maxfirstnodeweight, /**< maximum weight of branching nodes in level 0; 0 if not used
    746 * (for cliques with at least one fractional node) */
    747 int* ntreenodes, /**< pointer to store number of nodes of b&b tree */
    748 int maxntreenodes, /**< maximal number of nodes of b&b tree */
    749 int backtrackfreq, /**< frequency to backtrack to first level of tree (0: no premature backtracking) */
    750 int maxnzeroextensions, /**< maximal number of zero-valued variables extending the clique */
    751 int fixednode, /**< node that is forced to be in the clique, or -1; must have positive weight */
    752 TCLIQUE_STATUS* status /**< pointer to store the status of the solving call */
    753 )
    754{
    755 TCLIQUE_Bool isleaf;
    756 const TCLIQUE_WEIGHT* weights;
    757 TCLIQUE_WEIGHT* apbound;
    758 TCLIQUE_WEIGHT subgraphweight;
    759 TCLIQUE_WEIGHT weightKold;
    760 TCLIQUE_WEIGHT tmpcliqueweight;
    761 int backtracklevel;
    762 int ntmpcliquenodes;
    763 int i;
    764
    765 assert(getnnodes != NULL);
    766 assert(getweights != NULL);
    767 assert(selectadjnodes != NULL);
    768 assert(mem != NULL);
    769 assert(V != NULL);
    770 assert(gsd != NULL);
    771 assert(iscolored != NULL);
    772 assert(K != NULL);
    773 assert(maxcliqueweight != NULL);
    774 assert(curcliquenodes != NULL);
    775 assert(ncurcliquenodes != NULL);
    776 assert(curcliqueweight != NULL);
    777 assert(ntreenodes != NULL);
    778 assert(maxfirstnodeweight >= 0);
    779 assert(*ntreenodes >= 0);
    780 assert(maxntreenodes >= 0);
    781 assert(status != NULL);
    782
    783 /* increase the number of nodes, and stop solving, if the node limit is exceeded */
    784 (*ntreenodes)++;
    785#ifdef TCLIQUE_DEBUG
    786 debugMessage("(level %d, treenode %d) maxclique = %d, curclique = %d [mem=%" SCIP_LONGINT_FORMAT " (%" SCIP_LONGINT_FORMAT "), cliques=%d]\n",
    787 level, *ntreenodes, *maxcliqueweight, *curcliqueweight,
    788 BMSgetChunkMemoryUsed(mem), BMSgetMemoryUsed(), cliquehash == NULL ? 0 : cliquehash->ncliques);
    789
    790 debugMessage(" -> current branching (weight %d):", weightK);
    791 for( i = 0; i < level; ++i )
    792 debugPrintf(" %d", K[i]);
    793 debugPrintf("\n");
    794 debugMessage(" -> branching candidates:");
    795 for( i = 0; i < nV; ++i )
    796 debugPrintf(" %d", V[i]);
    797 debugPrintf("\n");
    798#endif
    799 if( *ntreenodes > maxntreenodes )
    800 {
    801 *status = TCLIQUE_NODELIMIT;
    802 return TRUE;
    803 }
    804
    805 weights = getweights(tcliquegraph);
    806 backtracklevel = INT_MAX;
    807 isleaf = TRUE;
    808
    809 /* allocate temporary memory for a priori bounds */
    810 ALLOC_ABORT( BMSallocMemoryArray(&apbound, nV) );
    811 BMSclearMemoryArray(apbound, nV);
    812
    813 /* use coloring relaxation to generate an upper bound for the current subtree and a heuristic solution */
    814 subgraphweight = boundSubgraph(getnnodes, getweights, isedge, selectadjnodes, tcliquegraph,
    815 mem, buffer, V, nV, gsd, iscolored, apbound,
    816 tmpcliquenodes, &ntmpcliquenodes, &tmpcliqueweight);
    817
    818#ifndef NDEBUG
    819 /* check correctness of V and apbound arrays */
    820 for( i = 0; i < nV; ++i )
    821 {
    822 assert(0 <= V[i] && V[i] < getnnodes(tcliquegraph));
    823 assert(i == 0 || V[i-1] < V[i]);
    824 assert(apbound[i] >= 0);
    825 assert((apbound[i] == 0) == (weights[V[i]] == 0));
    826 }
    827#endif
    828
    829 /* check, whether the heuristic solution is better than the current subtree's solution;
    830 * if the user wanted to have a fixed variable inside the clique and we are in level 0, we first have to
    831 * fix this variable in this level (the current clique might not contain the fixed node)
    832 */
    833 if( weightK + tmpcliqueweight > *curcliqueweight && (level > 0 || fixednode == -1) )
    834 {
    835 /* install the newly generated clique as current clique */
    836 for( i = 0; i < level; ++i )
    837 curcliquenodes[i] = K[i];
    838 for( i = 0; i < ntmpcliquenodes; ++i )
    839 curcliquenodes[level+i] = tmpcliquenodes[i];
    840 *ncurcliquenodes = level + ntmpcliquenodes;
    841 *curcliqueweight = weightK + tmpcliqueweight;
    842
    843#ifdef TCLIQUE_DEBUG
    844 debugMessage(" -> new current clique with weight %d at node %d in level %d:",
    845 *curcliqueweight, *ntreenodes, level);
    846 for( i = 0; i < *ncurcliquenodes; ++i )
    847 debugPrintf(" %d", curcliquenodes[i]);
    848 debugPrintf("\n");
    849#endif
    850 }
    851
    852 /* discard subtree, if the upper bound is not better than the weight of the currently best clique;
    853 * if only 2 nodes are left, the maximal weighted clique was already calculated in boundSubgraph() and nothing
    854 * more has to be done;
    855 * however, if the user wanted to have a fixed node and we are in the first decision level, we have to continue
    856 */
    857 if( weightK + subgraphweight > *maxcliqueweight && (nV > 2 || (fixednode >= 0 && level == 0)) )
    858 {
    859 int* Vcurrent;
    860 int nVcurrent;
    861 int nValive;
    862 int branchingnode;
    863
    864 assert(nV > 0);
    865
    866 /* process current subtree */
    867 level++;
    868
    869 /* set up data structures */
    870 ALLOC_ABORT( BMSallocMemoryArray(&Vcurrent, nV-1) );
    871
    872 nValive = nV;
    873 weightKold = weightK;
    874
    875 debugMessage("============================ branching level %d ===============================\n", level);
    876
    877 /* branch on the nodes of V by decreasing order of their apriori bound */
    878 while( backtracklevel >= level && nValive > 0 )
    879 {
    880 int branchidx;
    881
    882 /* check if we meet the backtracking frequency - in this case abort the search until we have reached first level */
    883 if( level > 1 && backtrackfreq > 0 && (*ntreenodes) % backtrackfreq == 0 )
    884 {
    885 backtracklevel = 1;
    886 break;
    887 }
    888
    889 /* get next branching node */
    890 if( level == 1 && fixednode >= 0 )
    891 {
    892 /* select the fixed node as first "branching" candidate */
    893 for( branchidx = 0; branchidx < nValive && V[branchidx] != fixednode; branchidx++ )
    894 {}
    895 assert(branchidx < nValive);
    896 assert(V[branchidx] == fixednode);
    897 }
    898 else if( level == 1 && maxfirstnodeweight > 0 )
    899 branchidx = getMaxApBoundIndexNotMaxWeight(V, nValive, apbound, weights, maxfirstnodeweight);
    900 else
    901 branchidx = getMaxApBoundIndex(nValive, apbound);
    902 if( branchidx < 0 )
    903 break;
    904 assert(0 <= branchidx && branchidx < nValive && nValive <= nV);
    905 assert(apbound[branchidx] > 0);
    906 assert(weights[V[branchidx]] > 0);
    907
    908 /* test a priori bound */
    909 if( (weightKold + apbound[branchidx]) <= *maxcliqueweight )
    910 break;
    911
    912 debugMessage("%d. branching in level %d (treenode %d): bidx=%d, node %d, weight %d, upperbound: %d+%d = %d, maxclique=%d\n",
    913 nV-nValive+1, level, *ntreenodes, branchidx, V[branchidx], weights[V[branchidx]], weightKold,
    914 apbound[branchidx], weightKold + apbound[branchidx], *maxcliqueweight);
    915
    916 /* because we branch on this node, the node is no leaf in the tree */
    917 isleaf = FALSE;
    918
    919 /* update the set of nodes from the b&b tree
    920 * K = K & {branchingnode}
    921 */
    922 branchingnode = V[branchidx];
    923 K[level-1] = branchingnode;
    924 weightK = weightKold + weights[branchingnode];
    925
    926 /* update the set of nodes for branching
    927 * V = V \ {branchingnode}
    928 */
    929 nValive--;
    930 for( i = branchidx; i < nValive; ++i )
    931 {
    932 V[i] = V[i+1];
    933 apbound[i] = apbound[i+1];
    934 }
    935
    936 /* set the nodes for the next level of b&b tree
    937 * Vcurrent = nodes of V, that are adjacent to branchingnode
    938 */
    939 nVcurrent = selectadjnodes(tcliquegraph, branchingnode, V, nValive, Vcurrent);
    940
    941 /* process the selected subtree */
    942 backtracklevel = branch(getnnodes, getweights, isedge, selectadjnodes, tcliquegraph, newsol, tcliquedata, /*lint !e838*/
    943 mem, cliquehash, buffer,
    944 level, Vcurrent, nVcurrent, Vzero, nVzero, gsd, iscolored, K, weightK,
    945 maxcliquenodes, nmaxcliquenodes, maxcliqueweight,
    946 curcliquenodes, ncurcliquenodes, curcliqueweight, tmpcliquenodes,
    947 maxfirstnodeweight, ntreenodes, maxntreenodes, backtrackfreq, maxnzeroextensions, -1, status);
    948
    949 /* if all other candidates stayed in the candidate list, the current branching was optimal and
    950 * there is no need to try the remaining ones
    951 */
    952 if( nVcurrent == nValive )
    953 {
    954 debugMessage("branching on node %d was optimal - ignoring remaining candidates\n", branchingnode);
    955 nValive = 0;
    956 }
    957
    958 /* if we had a fixed node, ignore all other nodes */
    959 if( fixednode >= 0 )
    960 nValive = 0;
    961 }
    962
    963 debugMessage("========================== branching level %d end =============================\n\n", level);
    964
    965 /* free data structures */
    966 BMSfreeMemoryArray(&Vcurrent);
    967 }
    968
    969 /* check, whether any branchings have been applied, or if this node is a leaf of the branching tree */
    970 if( isleaf )
    971 {
    972 /* the current clique is the best clique found on the path to this leaf
    973 * -> check, whether it is an improvement to the currently best clique
    974 */
    975 if( *curcliqueweight > *maxcliqueweight )
    976 {
    977 TCLIQUE_Bool stopsolving;
    978
    979 debugMessage("found clique of weight %d at node %d in level %d\n", *curcliqueweight, *ntreenodes, level);
    980 newSolution(selectadjnodes, tcliquegraph, newsol, tcliquedata, cliquehash, buffer, Vzero, nVzero,
    981 maxnzeroextensions, curcliquenodes, *ncurcliquenodes, *curcliqueweight,
    982 maxcliquenodes, nmaxcliquenodes, maxcliqueweight, &stopsolving);
    983
    984 if( stopsolving )
    985 {
    986 debugMessage(" -> solving terminated by callback method\n");
    987 backtracklevel = 0;
    988 }
    989 }
    990
    991 /* discard the current clique */
    992 *ncurcliquenodes = 0;
    993 *curcliqueweight = 0;
    994 }
    995
    996#ifdef TCLIQUE_DEBUG
    997 if( level > backtracklevel )
    998 {
    999 debugMessage("premature backtracking after %d nodes - level %d\n", *ntreenodes, level);
    1000 }
    1001#endif
    1002
    1003 /* free data structures */
    1004 BMSfreeMemoryArray(&apbound);
    1005
    1006 return backtracklevel;
    1007}
    1008
    1009/** finds maximum weight clique */
    1011 TCLIQUE_GETNNODES((*getnnodes)), /**< user function to get the number of nodes */
    1012 TCLIQUE_GETWEIGHTS((*getweights)), /**< user function to get the node weights */
    1013 TCLIQUE_ISEDGE((*isedge)), /**< user function to check for existence of an edge */
    1014 TCLIQUE_SELECTADJNODES((*selectadjnodes)),/**< user function to select adjacent edges */
    1015 TCLIQUE_GRAPH* tcliquegraph, /**< pointer to graph data structure that is passed to graph callbacks */
    1016 TCLIQUE_NEWSOL((*newsol)), /**< user function to call on every new solution */
    1017 TCLIQUE_DATA* tcliquedata, /**< user data to pass to new solution callback function */
    1018 int* maxcliquenodes, /**< pointer to store nodes of the maximum weight clique */
    1019 int* nmaxcliquenodes, /**< pointer to store number of nodes in the maximum weight clique */
    1020 TCLIQUE_WEIGHT* maxcliqueweight, /**< pointer to store weight of the maximum weight clique */
    1021 TCLIQUE_WEIGHT maxfirstnodeweight, /**< maximum weight of branching nodes in level 0; 0 if not used
    1022 * for cliques with at least one fractional node) */
    1023 TCLIQUE_WEIGHT minweight, /**< lower bound for weight of generated cliques */
    1024 int maxntreenodes, /**< maximal number of nodes of b&b tree */
    1025 int backtrackfreq, /**< frequency to backtrack to first level of tree (0: no premature backtracking) */
    1026 int maxnzeroextensions, /**< maximal number of zero-valued variables extending the clique */
    1027 int fixednode, /**< node that is forced to be in the clique, or -1; must have positive weight */
    1028 int* ntreenodes, /**< pointer to store the number of used tree nodes (or NULL) */
    1029 TCLIQUE_STATUS* status /**< pointer to store the status of the solving call */
    1030 )
    1031{
    1032 CLIQUEHASH* cliquehash;
    1033 const TCLIQUE_WEIGHT* weights;
    1034 int* buffer;
    1035 int* K;
    1036 int* V;
    1037 int* Vzero;
    1038 int nnodes;
    1039 int nV;
    1040 int nVzero;
    1041 int i;
    1042 BMS_CHKMEM* mem;
    1043 NBC* gsd;
    1044 TCLIQUE_Bool* iscolored;
    1045 int* curcliquenodes;
    1046 int ncurcliquenodes;
    1047 TCLIQUE_WEIGHT curcliqueweight;
    1048 int* tmpcliquenodes;
    1049 int nbbtreenodes;
    1050 int backtracklevel;
    1051
    1052 assert(maxcliquenodes != NULL);
    1053 assert(nmaxcliquenodes != NULL);
    1054 assert(maxcliqueweight != NULL);
    1055 assert(maxntreenodes >= 0);
    1056 assert(backtrackfreq >= 0);
    1057 assert(maxnzeroextensions >= 0);
    1058 assert(status != NULL);
    1059
    1060 *status = TCLIQUE_OPTIMAL;
    1061
    1062 /* use default graph callbacks, if NULL pointers are given */
    1063 if( getnnodes == NULL )
    1064 getnnodes = tcliqueGetNNodes;
    1065 if( getweights == NULL )
    1066 getweights = tcliqueGetWeights;
    1067 if( isedge == NULL )
    1068 isedge = tcliqueIsEdge;
    1069 if( selectadjnodes == NULL )
    1070 selectadjnodes = tcliqueSelectAdjnodes;
    1071
    1072 /* get number of nodes */
    1073 nnodes = getnnodes(tcliquegraph);
    1074
    1075 debugMessage("calculating maximal weighted clique in graph (%d nodes)\n", nnodes);
    1076
    1077 /* set up data structures */
    1078 if( newsol != NULL )
    1080 else
    1081 cliquehash = NULL;
    1087 ALLOC_ABORT( BMSallocMemoryArray(&iscolored, nnodes) );
    1088 ALLOC_ABORT( BMSallocMemoryArray(&curcliquenodes, nnodes) );
    1089 ALLOC_ABORT( BMSallocMemoryArray(&tmpcliquenodes, nnodes) );
    1090
    1091 /* set weight and number of nodes of maximum weighted clique */
    1092 *nmaxcliquenodes = 0;
    1093 *maxcliqueweight = minweight-1;
    1094 ncurcliquenodes = 0;
    1095 curcliqueweight = 0;
    1096 nbbtreenodes = 0;
    1097
    1098 /* set up V and Vzero */
    1099 weights = getweights(tcliquegraph);
    1100 assert(weights != NULL);
    1101 nV = 0;
    1102 nVzero = 0;
    1103 for( i = 0 ; i < nnodes; i++ )
    1104 {
    1105 if( weights[i] == 0 )
    1106 {
    1107 Vzero[nVzero] = i;
    1108 nVzero++;
    1109 }
    1110 else
    1111 {
    1112 V[nV] = i;
    1113 nV++;
    1114 }
    1115 }
    1116
    1117 /* initialize own memory allocator for coloring */
    1118 mem = BMScreateChunkMemory(sizeof(LIST_ITV), CHUNK_SIZE, -1);
    1119
    1120 /* branch to find maximum weight clique */
    1121 backtracklevel = branch(getnnodes, getweights, isedge, selectadjnodes, tcliquegraph, newsol, tcliquedata, mem,
    1122 cliquehash, buffer, 0, V, nV, Vzero, nVzero, gsd, iscolored, K, 0,
    1123 maxcliquenodes, nmaxcliquenodes, maxcliqueweight,
    1124 curcliquenodes, &ncurcliquenodes, &curcliqueweight, tmpcliquenodes,
    1125 maxfirstnodeweight, &nbbtreenodes, maxntreenodes, backtrackfreq, maxnzeroextensions, fixednode, status);
    1126
    1127 if ( ntreenodes != NULL )
    1128 *ntreenodes = nbbtreenodes;
    1129
    1130 if( backtracklevel != INT_MAX && *status == TCLIQUE_OPTIMAL )
    1131 *status = TCLIQUE_USERABORT;
    1132
    1133 /* delete own memory allocator for coloring */
    1135
    1136 /* free data structures */
    1137 BMSfreeMemoryArray(&tmpcliquenodes);
    1138 BMSfreeMemoryArray(&curcliquenodes);
    1139 BMSfreeMemoryArray(&iscolored);
    1140 BMSfreeMemoryArray(&gsd);
    1141 BMSfreeMemoryArray(&Vzero);
    1144 BMSfreeMemoryArray(&buffer);
    1145 if( newsol != NULL )
    1146 freeCliquehash(&cliquehash);
    1147} /*lint !e438*/
    #define NULL
    Definition: def.h:248
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:148
    #define nnodes
    Definition: gastrans.c:74
    memory allocation routines
    #define BMSfreeMemory(ptr)
    Definition: memory.h:145
    #define BMSreallocMemoryArray(ptr, num)
    Definition: memory.h:127
    #define BMSgetChunkMemoryUsed(mem)
    Definition: memory.h:317
    struct BMS_ChkMem BMS_CHKMEM
    Definition: memory.h:302
    #define BMSgetMemoryUsed()
    Definition: memory.h:156
    #define BMSallocMemoryArray(ptr, num)
    Definition: memory.h:123
    #define BMSfreeMemoryArray(ptr)
    Definition: memory.h:147
    #define BMScopyMemoryArray(ptr, source, num)
    Definition: memory.h:134
    #define BMSdestroyChunkMemory(mem)
    Definition: memory.h:309
    #define BMScreateChunkMemory(sz, isz, gbf)
    Definition: memory.h:307
    #define BMSclearMemoryArray(ptr, num)
    Definition: memory.h:130
    #define BMSallocMemory(ptr)
    Definition: memory.h:118
    tclique user interface
    #define TCLIQUE_GETWEIGHTS(x)
    Definition: tclique.h:105
    #define TCLIQUE_GETNNODES(x)
    Definition: tclique.h:97
    #define TCLIQUE_ISEDGE(x)
    Definition: tclique.h:115
    @ TCLIQUE_NODELIMIT
    Definition: tclique.h:64
    @ TCLIQUE_USERABORT
    Definition: tclique.h:65
    @ TCLIQUE_OPTIMAL
    Definition: tclique.h:66
    #define TCLIQUE_SELECTADJNODES(x)
    Definition: tclique.h:130
    enum TCLIQUE_Status TCLIQUE_STATUS
    Definition: tclique.h:68
    int TCLIQUE_WEIGHT
    Definition: tclique.h:48
    struct TCLIQUE_Graph TCLIQUE_GRAPH
    Definition: tclique.h:49
    #define TCLIQUE_Bool
    Definition: tclique.h:53
    #define TCLIQUE_NEWSOL(x)
    Definition: tclique.h:88
    static void clearCliquehash(CLIQUEHASH *cliquehash)
    static void newSolution(TCLIQUE_SELECTADJNODES((*selectadjnodes)), TCLIQUE_GRAPH *tcliquegraph, TCLIQUE_NEWSOL((*newsol)), TCLIQUE_DATA *tcliquedata, CLIQUEHASH *cliquehash, int *buffer, int *Vzero, int nVzero, int maxnzeroextensions, int *curcliquenodes, int ncurcliquenodes, TCLIQUE_WEIGHT curcliqueweight, int *maxcliquenodes, int *nmaxcliquenodes, TCLIQUE_WEIGHT *maxcliqueweight, TCLIQUE_Bool *stopsolving)
    static int branch(TCLIQUE_GETNNODES((*getnnodes)), TCLIQUE_GETWEIGHTS((*getweights)), TCLIQUE_ISEDGE((*isedge)), TCLIQUE_SELECTADJNODES((*selectadjnodes)), TCLIQUE_GRAPH *tcliquegraph, TCLIQUE_NEWSOL((*newsol)), TCLIQUE_DATA *tcliquedata, BMS_CHKMEM *mem, CLIQUEHASH *cliquehash, int *buffer, int level, int *V, int nV, int *Vzero, int nVzero, NBC *gsd, TCLIQUE_Bool *iscolored, int *K, TCLIQUE_WEIGHT weightK, int *maxcliquenodes, int *nmaxcliquenodes, TCLIQUE_WEIGHT *maxcliqueweight, int *curcliquenodes, int *ncurcliquenodes, TCLIQUE_WEIGHT *curcliqueweight, int *tmpcliquenodes, TCLIQUE_WEIGHT maxfirstnodeweight, int *ntreenodes, int maxntreenodes, int backtrackfreq, int maxnzeroextensions, int fixednode, TCLIQUE_STATUS *status)
    struct clique CLIQUE
    static void freeClique(CLIQUE **clique)
    static void extendCliqueZeroWeight(TCLIQUE_SELECTADJNODES((*selectadjnodes)), TCLIQUE_GRAPH *tcliquegraph, int *buffer, int *Vzero, int nVzero, int maxnzeroextensions, int *curcliquenodes, int *ncurcliquenodes)
    static TCLIQUE_Bool inCliquehash(CLIQUEHASH *cliquehash, CLIQUE *clique, int *insertpos)
    #define CLIQUEHASH_INITSIZE
    struct cliquehash CLIQUEHASH
    static void ensureCliquehashSize(CLIQUEHASH *cliquehash, int num)
    static void checkCliquehash(CLIQUEHASH *cliquehash)
    static void createClique(CLIQUE **clique, int *nodes, int nnodes)
    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)
    static void insertClique(CLIQUEHASH *cliquehash, CLIQUE *clique, int insertpos)
    static int getMaxApBoundIndexNotMaxWeight(int *V, int nV, const TCLIQUE_WEIGHT *apbound, const TCLIQUE_WEIGHT *weights, TCLIQUE_WEIGHT maxweight)
    static void freeCliquehash(CLIQUEHASH **cliquehash)
    static int compSubcliques(CLIQUE *clique1, CLIQUE *clique2)
    static TCLIQUE_WEIGHT boundSubgraph(TCLIQUE_GETNNODES((*getnnodes)), TCLIQUE_GETWEIGHTS((*getweights)), TCLIQUE_ISEDGE((*isedge)), TCLIQUE_SELECTADJNODES((*selectadjnodes)), TCLIQUE_GRAPH *tcliquegraph, BMS_CHKMEM *mem, int *buffer, int *V, int nV, NBC *gsd, TCLIQUE_Bool *iscolored, TCLIQUE_WEIGHT *apbound, int *tmpcliquenodes, int *ntmpcliquenodes, TCLIQUE_WEIGHT *tmpcliqueweight)
    static int getMaxApBoundIndex(int nV, TCLIQUE_WEIGHT *apbound)
    #define CHUNK_SIZE
    static void createCliquehash(CLIQUEHASH **cliquehash, int tablesize)
    static void reduced(TCLIQUE_GETWEIGHTS((*getweights)), TCLIQUE_ISEDGE((*isedge)), TCLIQUE_GRAPH *tcliquegraph, int *V, int nV, TCLIQUE_WEIGHT *apbound, int *tmpcliquenodes, int *ntmpcliquenodes, TCLIQUE_WEIGHT *tmpcliqueweight)
    TCLIQUE_WEIGHT tcliqueColoring(TCLIQUE_GETNNODES((*getnnodes)), TCLIQUE_GETWEIGHTS((*getweights)), TCLIQUE_SELECTADJNODES((*selectadjnodes)), TCLIQUE_GRAPH *tcliquegraph, BMS_CHKMEM *mem, int *buffer, int *V, int nV, NBC *gsd, TCLIQUE_Bool *iscolored, TCLIQUE_WEIGHT *apbound, int *clique, int *nclique, TCLIQUE_WEIGHT *weightclique)
    coloring part of algorithm for maximum cliques
    struct _LIST_ITV LIST_ITV
    struct _NBC NBC
    tclique defines
    #define debug(x)
    Definition: tclique_def.h:79
    #define ALLOC_ABORT(x)
    Definition: tclique_def.h:50
    #define debugPrintf
    Definition: tclique_def.h:81
    #define debugMessage
    Definition: tclique_def.h:80