/* This file is a concatenation of the files cliquer.c, graph.c and reorder.c from cliquer-1.21 except the routines for reading and writing dimacs files.
Also some timing code is commented out because it is not used by nauty and causes portability problem on non-Unix systems (thanks to Isuru Fernando).
Some procedures which call cliquer with nauty-format graph are added. Apart from removing DIMACS, the cliquer procedures have not been changed except to include nautycliquer.h in place of the previously included files.
cliquer was kindly provided by Sampo Nisjkanen and Patric Ostergard.
Brendan McKay. Aug 27, 2016
*/
#include"nautycliquer.h"
/* * This file contains the clique searching routines. * * Copyright (C) 2002 Sampo Niskanen, Patric Östergård. * Licensed under the GNU GPL, read the file LICENSE for details. * This version covered by nauty&Traces licence, see file COPYRIGHT.
*/
/* Global variables used: */ /* These must be saved and restored in re-entrance. */ static TLS_ATTR int *clique_size; /* c[i] == max. clique size in {0,1,...,i-1} */ static TLS_ATTR set_t current_clique; /* Current clique being searched. */ static TLS_ATTR set_t best_clique; /* Largest/heaviest clique found so far. */ #if 0 staticstruct tms cputimer; /* Timer for opts->time_function() */ staticstruct timeval realtimer; /* Timer for opts->time_function() */ #endif static TLS_ATTR int clique_list_count=0; /* No. of cliques in opts->clique_list[] */ static TLS_ATTR int weight_multiplier=1; /* Weights multiplied by this when passing
* to time_function(). */
/* List cache (contains memory blocks of size g->n * sizeof(int)) */ static TLS_ATTR int **temp_list=NULL; static TLS_ATTR int temp_count=0;
/* * Macros for re-entrance. ENTRANCE_SAVE() must be called immediately * after variable definitions, ENTRANCE_RESTORE() restores global * variables to original values. entrance_level should be increased * and decreased accordingly.
*/ staticint entrance_level=0; /* How many levels for entrance have occurred? */
/* Number of clock ticks per second (as returned by sysconf(_SC_CLK_TCK)) */ staticint clocks_per_sec=0;
/* Recursion and helper functions */ static boolean sub_unweighted_single(int *table, int size, int min_size,
graph_t *g); staticint sub_unweighted_all(int *table, int size, int min_size, int max_size,
boolean maximal, graph_t *g,
clique_options *opts); staticint sub_weighted_all(int *table, int size, int weight, int current_weight, int prune_low, int prune_high, int min_weight, int max_weight, boolean maximal,
graph_t *g, clique_options *opts);
/***** Unweighted searches *****/ /* * Unweighted searches are done separately from weighted searches because * some effective pruning methods can be used when the vertex weights * are all 1. Single and all clique finding routines are separated, * because the single clique finding routine can store the found clique * while it is returning from the recursion, thus requiring no implicit * storing of the current clique. When searching for all cliques the * current clique must be stored.
*/
/* * unweighted_clique_search_single() * * Searches for a single clique of size min_size. Stores maximum clique * sizes into clique_size[]. * * table - the order of the vertices in g to use * min_size - minimum size of clique to search for. If min_size==0, * searches for a maximum clique. * g - the graph * opts - time printing options * * opts->time_function is called after each base-level recursion, if * non-NULL. (NOT IN THIS VERSION) * * Returns the size of the clique found, or 0 if min_size>0 and a clique * of that size was not found (or if time_function aborted the search). * The largest clique found is stored in current_clique. * * Note: Does NOT use opts->user_function of opts->clique_list.
*/ staticint unweighted_clique_search_single(int *table, int min_size,
graph_t *g, clique_options *opts) { #if 0 struct tms tms; struct timeval timeval; #endif int i,j; int v,w; int *newtable; int newsize;
v=table[0];
clique_size[v]=1;
set_empty(current_clique);
SET_ADD_ELEMENT(current_clique,v); if (min_size==1) return 1;
if (temp_count) {
temp_count--;
newtable=temp_list[temp_count];
} else {
newtable=malloc(g->n * sizeof(int));
} for (i=1; i < g->n; i++) {
w=v;
v=table[i];
newsize=0; for (j=0; j<i; j++) { if (GRAPH_IS_EDGE(g, v, table[j])) {
newtable[newsize]=table[j];
newsize++;
}
}
if (sub_unweighted_single(newtable,newsize,clique_size[w],g)) {
SET_ADD_ELEMENT(current_clique,v);
clique_size[v]=clique_size[w]+1;
} else {
clique_size[v]=clique_size[w];
}
if (min_size) { if (clique_size[v]>=min_size) {
temp_list[temp_count++]=newtable; return clique_size[v];
} if (clique_size[v]+g->n-i-1 < min_size) {
temp_list[temp_count++]=newtable; return 0;
}
}
}
temp_list[temp_count++]=newtable;
if (min_size) return 0; return clique_size[v];
}
/* * sub_unweighted_single() * * Recursion function for searching for a single clique of size min_size. * * table - subset of the vertices in graph * size - size of table * min_size - size of clique to look for within the subgraph * (decreased with every recursion) * g - the graph * * Returns TRUE if a clique of size min_size is found, FALSE otherwise. * If a clique of size min_size is found, it is stored in current_clique. * * clique_size[] for all values in table must be defined and correct, * otherwise inaccurate results may occur.
*/ static boolean sub_unweighted_single(int *table, int size, int min_size,
graph_t *g) { int i; int v; int *newtable; int *p1, *p2;
/* Zero or one vertices needed anymore. */ if (min_size <= 1) { if (size>0 && min_size==1) {
set_empty(current_clique);
SET_ADD_ELEMENT(current_clique,table[0]); returnTRUE;
} if (min_size==0) {
set_empty(current_clique); returnTRUE;
} returnFALSE;
} if (size < min_size) returnFALSE;
/* Dynamic memory allocation with cache */ if (temp_count) {
temp_count--;
newtable=temp_list[temp_count];
} else {
newtable=malloc(g->n * sizeof(int));
}
for (i = size-1; i >= 0; i--) {
v = table[i];
if (clique_size[v] < min_size) break; /* This is faster when compiling with gcc than placing
* this in the for-loop condition. */ if (i+1 < min_size) break;
/* Very ugly code, but works faster than "for (i=...)" */
p1 = newtable; for (p2=table; p2 < table+i; p2++) { int w = *p2; if (GRAPH_IS_EDGE(g, v, w)) {
*p1 = w;
p1++;
}
}
/* Avoid unneccessary loops (next size == p1-newtable) */ if (p1-newtable < min_size-1) continue; /* Now p1-newtable >= min_size-1 >= 2-1 == 1, so we can use
* p1-newtable-1 safely. */ if (clique_size[newtable[p1-newtable-1]] < min_size-1) continue;
/* * unweighted_clique_search_all() * * Searches for all cliques with size at least min_size and at most * max_size. Stores the cliques as opts declares. * * table - the order of the vertices in g to search * start - first index where the subgraph table[0], ..., table[start] * might include a requested kind of clique * min_size - minimum size of clique to search for. min_size > 0 ! * max_size - maximum size of clique to search for. If no upper limit * is desired, use eg. INT_MAX * maximal - requires cliques to be maximal * g - the graph * opts - time printing and clique storage options * * Cliques found are stored as defined by opts->user_function and * opts->clique_list. opts->time_function is called after each * base-level recursion, if non-NULL. * * clique_size[] must be defined and correct for all values of * table[0], ..., table[start-1]. * * Returns the number of cliques stored (not neccessarily number of cliques * in graph, if user/time_function aborts).
*/ staticint unweighted_clique_search_all(int *table, int start, int min_size, int max_size,
boolean maximal, graph_t *g,
clique_options *opts) { #if 0 struct timeval timeval; struct tms tms; #endif int i,j; int v; int *newtable; int newsize; int count=0;
/* * sub_unweighted_all() * * Recursion function for searching for all cliques of given size. * * table - subset of vertices of graph g * size - size of table * min_size - minimum size of cliques to search for (decreased with * every recursion) * max_size - maximum size of cliques to search for (decreased with * every recursion). If no upper limit is desired, use * eg. INT_MAX * maximal - require cliques to be maximal (passed through) * g - the graph * opts - storage options * * All cliques of suitable size found are stored according to opts. * * Returns the number of cliques found. If user_function returns FALSE, * then the number of cliques is returned negative. * * Uses current_clique to store the currently-being-searched clique. * clique_size[] for all values in table must be defined and correct, * otherwise inaccurate results may occur.
*/ staticint sub_unweighted_all(int *table, int size, int min_size, int max_size,
boolean maximal, graph_t *g,
clique_options *opts) { int i; int v; int n; int *newtable; int *p1, *p2; int count=0; /* Amount of cliques found */
if (min_size <= 0) { if ((!maximal) || is_maximal(current_clique,g)) { /* We've found one. Store it. */
count++; if (!store_clique(current_clique,g,opts)) { return -count;
}
} if (max_size <= 0) { /* If we add another element, size will be too big. */ return count;
}
}
if (size < min_size) { return count;
}
/* Dynamic memory allocation with cache */ if (temp_count) {
temp_count--;
newtable=temp_list[temp_count];
} else {
newtable=malloc(g->n * sizeof(int));
}
for (i=size-1; i>=0; i--) {
v = table[i]; if (clique_size[v] < min_size) { break;
} if (i+1 < min_size) { break;
}
/* Very ugly code, but works faster than "for (i=...)" */
p1 = newtable; for (p2=table; p2 < table+i; p2++) { int w = *p2; if (GRAPH_IS_EDGE(g, v, w)) {
*p1 = w;
p1++;
}
}
/***** Weighted clique searches *****/ /* * Weighted clique searches can use the same recursive routine, because * in both cases (single/all) they have to search through all potential * permutations searching for heavier cliques.
*/
/* * weighted_clique_search_single() * * Searches for a single clique of weight at least min_weight, and at * most max_weight. Stores maximum clique sizes into clique_size[] * (or min_weight-1, whichever is smaller). * * table - the order of the vertices in g to use * min_weight - minimum weight of clique to search for. If min_weight==0, * then searches for a maximum weight clique * max_weight - maximum weight of clique to search for. If no upper limit * is desired, use eg. INT_MAX * g - the graph * opts - time printing options * * opts->time_function is called after each base-level recursion, if * non-NULL. * * Returns 0 if a clique of requested weight was not found (also if * time_function requested an abort), otherwise returns >= 1. * If min_weight==0 (search for maximum-weight clique), then the return * value is the weight of the clique found. The found clique is stored * in best_clique. * * Note: Does NOT use opts->user_function of opts->clique_list.
*/ staticint weighted_clique_search_single(int *table, int min_weight, int max_weight, graph_t *g,
clique_options *opts) { #if 0 struct timeval timeval; struct tms tms; #endif int i,j; int v; int *newtable; int newsize; int newweight; int search_weight; int min_w;
clique_options localopts;
if (min_weight==0)
min_w=INT_MAX; else
min_w=min_weight;
if (min_weight==1) { /* min_weight==1 may cause trouble in the routine, and * it's trivial to check as it's own case.
* We write nothing to clique_size[]. */ for (i=0; i < g->n; i++) { if (g->weights[table[i]] <= max_weight) {
set_empty(best_clique);
SET_ADD_ELEMENT(best_clique,table[i]); return g->weights[table[i]];
}
} return 0;
}
#if 0 if (opts->time_function) {
gettimeofday(&timeval,NULL);
times(&tms); if (!opts->time_function(entrance_level,
i+1,g->n,clique_size[v] *
weight_multiplier,
(double)(tms.tms_utime-
cputimer.tms_utime)/
clocks_per_sec,
timeval.tv_sec-
realtimer.tv_sec+
(double)(timeval.tv_usec-
realtimer.tv_usec)/
1000000,opts)) {
set_free(current_clique);
current_clique=NULL; break;
}
} #endif
}
temp_list[temp_count++]=newtable; if (min_weight && (search_weight > 0)) { /* Requested clique has not been found. */ return 0;
} return clique_size[table[i-1]];
}
/* * weighted_clique_search_all() * * Searches for all cliques with weight at least min_weight and at most * max_weight. Stores the cliques as opts declares. * * table - the order of the vertices in g to search * start - first index where the subgraph table[0], ..., table[start] * might include a requested kind of clique * min_weight - minimum weight of clique to search for. min_weight > 0 ! * max_weight - maximum weight of clique to search for. If no upper limit * is desired, use eg. INT_MAX * maximal - search only for maximal cliques * g - the graph * opts - time printing and clique storage options * * Cliques found are stored as defined by opts->user_function and * opts->clique_list. opts->time_function is called after each * base-level recursion, if non-NULL. * * clique_size[] must be defined and correct for all values of * table[0], ..., table[start-1]. * * Returns the number of cliques stored (not neccessarily number of cliques * in graph, if user/time_function aborts).
*/ staticint weighted_clique_search_all(int *table, int start, int min_weight, int max_weight,
boolean maximal, graph_t *g,
clique_options *opts) { #if 0 struct timeval timeval; struct tms tms; #endif int i,j; int v; int *newtable; int newsize; int newweight;
/* * sub_weighted_all() * * Recursion function for searching for all cliques of given weight. * * table - subset of vertices of graph g * size - size of table * weight - total weight of vertices in table * current_weight - weight of clique found so far * prune_low - ignore all cliques with weight less or equal to this value * (often heaviest clique found so far) (passed through) * prune_high - maximum weight possible for clique in this subgraph * (passed through) * min_size - minimum weight of cliques to search for (passed through) * Must be greater than 0. * max_size - maximum weight of cliques to search for (passed through) * If no upper limit is desired, use eg. INT_MAX * maximal - search only for maximal cliques * g - the graph * opts - storage options * * All cliques of suitable weight found are stored according to opts. * * Returns weight of heaviest clique found (prune_low if a heavier clique * hasn't been found); if a clique with weight at least min_size is found * then min_size-1 is returned. If clique storage failed, -1 is returned. * * The largest clique found smaller than max_weight is stored in * best_clique, if non-NULL. * * Uses current_clique to store the currently-being-searched clique. * clique_size[] for all values in table must be defined and correct, * otherwise inaccurate results may occur. * * To search for a single maximum clique, use min_weight==max_weight==INT_MAX, * with best_clique non-NULL. To search for a single given-weight clique, * use opts->clique_list and opts->user_function=false_function. When * searching for all cliques, min_weight should be given the minimum weight * desired.
*/ staticint sub_weighted_all(int *table, int size, int weight, int current_weight, int prune_low, int prune_high, int min_weight, int max_weight, boolean maximal,
graph_t *g, clique_options *opts) { int i; int v,w; int *newtable; int *p1, *p2; int newweight;
if (current_weight >= min_weight) { if ((current_weight <= max_weight) &&
((!maximal) || is_maximal(current_clique,g))) { /* We've found one. Store it. */ if (!store_clique(current_clique,g,opts)) { return -1;
}
} if (current_weight >= max_weight) { /* Clique too heavy. */ return min_weight-1;
}
} if (size <= 0) { /* current_weight < min_weight, prune_low < min_weight,
* so return value is always < min_weight. */ if (current_weight>prune_low) { if (best_clique)
set_copy(best_clique,current_clique); if (current_weight < min_weight) return current_weight; else return min_weight-1;
} else { return prune_low;
}
}
/* Dynamic memory allocation with cache */ if (temp_count) {
temp_count--;
newtable=temp_list[temp_count];
} else {
newtable=malloc(g->n * sizeof(int));
}
for (i = size-1; i >= 0; i--) {
v = table[i]; if (current_weight+clique_size[v] <= prune_low) { /* Dealing with subset without heavy enough clique. */ break;
} if (current_weight+weight <= prune_low) { /* Even if all elements are added, won't do. */ break;
}
/* Very ugly code, but works faster than "for (i=...)" */
p1 = newtable;
newweight = 0; for (p2=table; p2 < table+i; p2++) {
w = *p2; if (GRAPH_IS_EDGE(g, v, w)) {
*p1 = w;
newweight += g->weights[w];
p1++;
}
}
w=g->weights[v];
weight-=w; /* Avoid a few unneccessary loops */ if (current_weight+w+newweight <= prune_low) { continue;
}
/* * store_clique() * * Stores a clique according to given user options. * * clique - the clique to store * opts - storage options * * Returns FALSE if opts->user_function() returned FALSE; otherwise * returns TRUE.
*/ static boolean store_clique(set_t clique, graph_t *g, clique_options *opts) {
clique_list_count++;
/* clique_list[] */ if (opts->clique_list) { /* * This has been a major source of bugs: * Has clique_list_count been set to 0 before calling * the recursions?
*/ if (clique_list_count <= 0) {
fprintf(stderr,"CLIQUER INTERNAL ERROR: " "clique_list_count has negative value!\n");
fprintf(stderr,"Please report as a bug.\n");
abort();
} if (clique_list_count <= opts->clique_list_length)
opts->clique_list[clique_list_count-1] =
set_duplicate(clique);
}
/* user_function() */ if (opts->user_function) { if (!opts->user_function(clique,g,opts)) { /* User function requested abort. */ returnFALSE;
}
}
returnTRUE;
}
/* * maximalize_clique() * * Adds greedily all possible vertices in g to set s to make it a maximal * clique. * * s - clique of vertices to make maximal * g - graph * * Note: Not very optimized (uses a simple O(n^2) routine), but is called * at maximum once per clique_xxx() call, so it shouldn't matter.
*/ staticvoid maximalize_clique(set_t s,graph_t *g) { int i,j;
boolean add;
for (i=0; i < g->n; i++) {
add=TRUE; for (j=0; j < g->n; j++) { if (SET_CONTAINS_FAST(s,j) && !GRAPH_IS_EDGE(g,i,j)) {
add=FALSE; break;
}
} if (add) {
SET_ADD_ELEMENT(s,i);
}
} return;
}
/* * is_maximal() * * Check whether a clique is maximal or not. * * clique - set of vertices in clique * g - graph * * Returns TRUE is clique is a maximal clique of g, otherwise FALSE.
*/ static boolean is_maximal(set_t clique, graph_t *g) { int i,j; int *table; int len;
boolean addable;
len=0; for (i=0; i < g->n; i++) if (SET_CONTAINS_FAST(clique,i))
table[len++]=i;
for (i=0; i < g->n; i++) {
addable=TRUE; for (j=0; j<len; j++) { if (!GRAPH_IS_EDGE(g,i,table[j])) {
addable=FALSE; break;
}
} if (addable) {
temp_list[temp_count++]=table; returnFALSE;
}
}
temp_list[temp_count++]=table; returnTRUE;
}
/* * false_function() * * Returns FALSE. Can be used as user_function.
*/ static boolean false_function(set_t clique,graph_t *g,clique_options *opts) { returnFALSE;
}
/***** API-functions *****/
/* * clique_unweighted_max_weight() * * Returns the size of the maximum (sized) clique in g (or 0 if search * was aborted). * * g - the graph * opts - time printing options * * Note: As we don't have an algorithm faster than actually finding * a maximum clique, we use clique_unweighted_find_single(). * This incurs only very small overhead.
*/ int clique_unweighted_max_weight(graph_t *g, clique_options *opts) {
set_t s; int size;
s=clique_unweighted_find_single(g,0,0,FALSE,opts); if (s==NULL) { /* Search was aborted. */ return 0;
}
size=set_size(s);
set_free(s); return size;
}
/* * clique_unweighted_find_single() * * Returns a clique with size at least min_size and at most max_size. * * g - the graph * min_size - minimum size of clique to search for. If min_size==0, * searches for maximum clique. * max_size - maximum size of clique to search for. If max_size==0, no * upper limit is used. If min_size==0, this must also be 0. * maximal - require returned clique to be maximal * opts - time printing options * * Returns the set of vertices forming the clique, or NULL if a clique * of requested size/maximality does not exist in the graph (or if * opts->time_function() requests abort). * * The returned clique is newly allocated and can be freed by set_free(). * * Note: Does NOT use opts->user_function() or opts->clique_list[].
*/
set_t clique_unweighted_find_single(graph_t *g,int min_size,int max_size,
boolean maximal, clique_options *opts) { int i; int *table;
set_t s;
for (i=0; i < g->n-1; i++) if (clique_size[table[i]]>=min_size) break; if (unweighted_clique_search_all(table,i,min_size,
max_size,maximal,
g,&localopts)) {
set_free(current_clique);
current_clique=s;
} else {
set_free(current_clique);
current_clique=NULL;
}
}
}
cleanreturn:
s=current_clique;
/* Free resources */ for (i=0; i < temp_count; i++)
free(temp_list[i]);
free(temp_list);
free(table);
free(clique_size);
ENTRANCE_RESTORE();
entrance_level--;
return s;
}
/* * clique_unweighted_find_all() * * Find all cliques with size at least min_size and at most max_size. * * g - the graph * min_size - minimum size of cliques to search for. If min_size==0, * searches for maximum cliques. * max_size - maximum size of cliques to search for. If max_size==0, no * upper limit is used. If min_size==0, this must also be 0. * maximal - require cliques to be maximal cliques * opts - time printing and clique storage options * * Returns the number of cliques found. This can be less than the number * of cliques in the graph iff opts->time_function() or opts->user_function() * returns FALSE (request abort). * * The cliques found are stored in opts->clique_list[] and * opts->user_function() is called with them (if non-NULL). The cliques * stored in opts->clique_list[] are newly allocated, and can be freed * by set_free().
*/ int clique_unweighted_find_all(graph_t *g, int min_size, int max_size,
boolean maximal, clique_options *opts) { int i; int *table; int count;
/* Search as normal until there is a chance to find a suitable
* clique. */ if (unweighted_clique_search_single(table,min_size,g,opts)==0) {
count=0; goto cleanreturn;
}
if (min_size==0 && max_size==0) {
min_size=max_size=clique_size[table[g->n-1]];
maximal=FALSE; /* No need to test, since we're searching
* for maximum cliques. */
} if (max_size==0) {
max_size=INT_MAX;
}
for (i=0; i < g->n-1; i++) if (clique_size[table[i]] >= min_size) break;
count=unweighted_clique_search_all(table,i,min_size,max_size,
maximal,g,opts);
/* * clique_max_weight() * * Returns the weight of the maximum weight clique in the graph (or 0 if * the search was aborted). * * g - the graph * opts - time printing options * * Note: As we don't have an algorithm faster than actually finding * a maximum weight clique, we use clique_find_single(). * This incurs only very small overhead.
*/ int clique_max_weight(graph_t *g,clique_options *opts) {
set_t s; int weight;
s=clique_find_single(g,0,0,FALSE,opts); if (s==NULL) { /* Search was aborted. */ return 0;
}
weight=graph_subgraph_weight(g,s);
set_free(s); return weight;
}
/* * clique_find_single() * * Returns a clique with weight at least min_weight and at most max_weight. * * g - the graph * min_weight - minimum weight of clique to search for. If min_weight==0, * searches for a maximum weight clique. * max_weight - maximum weight of clique to search for. If max_weight==0, * no upper limit is used. If min_weight==0, max_weight must * also be 0. * maximal - require returned clique to be maximal * opts - time printing options * * Returns the set of vertices forming the clique, or NULL if a clique * of requested weight/maximality does not exist in the graph (or if * opts->time_function() requests abort). * * The returned clique is newly allocated and can be freed by set_free(). * * Note: Does NOT use opts->user_function() or opts->clique_list[]. * Note: Automatically uses clique_unweighted_find_single if all vertex * weights are the same.
*/
set_t clique_find_single(graph_t *g,int min_weight,int max_weight,
boolean maximal, clique_options *opts) { int i; int *table;
set_t s;
if ((max_weight>0) && (min_weight>max_weight)) { /* state was not changed */
entrance_level--; return NULL;
}
#if 0 if (clocks_per_sec==0)
clocks_per_sec=sysconf(_SC_CLK_TCK);
ASSERT(clocks_per_sec>0); #endif
/* Check whether we can use unweighted routines. */ if (!graph_weighted(g)) {
min_weight=DIV_UP(min_weight,g->weights[0]); if (max_weight) {
max_weight=DIV_DOWN(max_weight,g->weights[0]); if (max_weight < min_weight) { /* state was not changed */
entrance_level--; return NULL;
}
}
if (weighted_clique_search_single(table,min_weight,max_weight,
g,opts)==0) { /* Requested clique has not been found. */
set_free(best_clique);
best_clique=NULL; goto cleanreturn;
} if (maximal && (min_weight>0)) {
maximalize_clique(best_clique,g); if (graph_subgraph_weight(g,best_clique) > max_weight) {
clique_options localopts;
for (i=0; i < g->n-1; i++) if ((clique_size[table[i]] >= min_weight) ||
(clique_size[table[i]] == 0)) break; if (!weighted_clique_search_all(table,i,min_weight,
max_weight,maximal,
g,&localopts)) {
set_free(best_clique);
best_clique=NULL;
}
}
}
cleanreturn:
s=best_clique;
/* Free resources */ for (i=0; i < temp_count; i++)
free(temp_list[i]);
free(temp_list);
temp_list=NULL;
temp_count=0;
free(table);
set_free(current_clique);
current_clique=NULL;
free(clique_size);
clique_size=NULL;
ENTRANCE_RESTORE();
entrance_level--;
return s;
}
/* * clique_find_all() * * Find all cliques with weight at least min_weight and at most max_weight. * * g - the graph * min_weight - minimum weight of cliques to search for. If min_weight==0, * searches for maximum weight cliques. * max_weight - maximum weight of cliques to search for. If max_weight==0, * no upper limit is used. If min_weight==0, max_weight must * also be 0. * maximal - require cliques to be maximal cliques * opts - time printing and clique storage options * * Returns the number of cliques found. This can be less than the number * of cliques in the graph iff opts->time_function() or opts->user_function() * returns FALSE (request abort). * * The cliques found are stored in opts->clique_list[] and * opts->user_function() is called with them (if non-NULL). The cliques * stored in opts->clique_list[] are newly allocated, and can be freed * by set_free(). * * Note: Automatically uses clique_unweighted_find_all if all vertex * weights are the same.
*/ int clique_find_all(graph_t *g, int min_weight, int max_weight,
boolean maximal, clique_options *opts) { int i,n; int *table;
if ((max_weight>0) && (min_weight>max_weight)) { /* state was not changed */
entrance_level--; return 0;
}
#if 0 if (clocks_per_sec==0)
clocks_per_sec=sysconf(_SC_CLK_TCK);
ASSERT(clocks_per_sec>0); #endif
if (!graph_weighted(g)) {
min_weight=DIV_UP(min_weight,g->weights[0]); if (max_weight) {
max_weight=DIV_DOWN(max_weight,g->weights[0]); if (max_weight < min_weight) { /* state was not changed */
entrance_level--; return 0;
}
}
/* First phase */
n=weighted_clique_search_single(table,min_weight,INT_MAX,g,opts); if (n==0) { /* Requested clique has not been found. */ goto cleanreturn;
}
if (min_weight==0) {
min_weight=n;
max_weight=n;
maximal=FALSE; /* They're maximum cliques already. */
} if (max_weight==0)
max_weight=INT_MAX;
for (i=0; i < g->n; i++) if ((clique_size[table[i]] >= min_weight) ||
(clique_size[table[i]] == 0)) break;
/* Second phase */
n=weighted_clique_search_all(table,i,min_weight,max_weight,maximal,
g,opts);
cleanreturn: /* Free resources */ for (i=0; i < temp_count; i++)
free(temp_list[i]);
free(temp_list);
free(table);
set_free(current_clique);
set_free(best_clique);
free(clique_size);
ENTRANCE_RESTORE();
entrance_level--;
return n;
}
/* * clique_print_time() * * Reports current running information every 0.1 seconds or when values * change. * * level - re-entrance level * i - current recursion level * n - maximum recursion level * max - weight of heaviest clique found * cputime - CPU time used in algorithm so far * realtime - real time used in algorithm so far * opts - prints information to (FILE *)opts->output (or stdout if NULL) * * Returns always TRUE (ie. never requests abort).
*/
boolean clique_print_time(int level, int i, int n, int max, double cputime, double realtime,
clique_options *opts) { staticfloat prev_time=100; staticint prev_i=100; staticint prev_max=100; staticint prev_level=0;
FILE *fp=opts->output; int j;
if (fp==NULL)
fp=stdout;
if (ABS(prev_time-realtime)>0.1 || i==n || i<prev_i || max!=prev_max ||
level!=prev_level) { for (j=1; j<level; j++)
fprintf(fp," "); if (realtime-prev_time < 0.01 || i<=prev_i)
fprintf(fp,"%3d/%d (max %2d) %2.2f s " "(0.00 s/round)\n",i,n,max,
realtime); else
fprintf(fp,"%3d/%d (max %2d) %2.2f s " "(%2.2f s/round)\n",
i,n,max,realtime,
(realtime-prev_time)/(i-prev_i));
prev_time=realtime;
prev_i=i;
prev_max=max;
prev_level=level;
} returnTRUE;
}
/* * clique_print_time_always() * * Reports current running information. * * level - re-entrance level * i - current recursion level * n - maximum recursion level * max - largest clique found * cputime - CPU time used in algorithm so far * realtime - real time used in algorithm so far * opts - prints information to (FILE *)opts->output (or stdout if NULL) * * Returns always TRUE (ie. never requests abort).
*/
boolean clique_print_time_always(int level, int i, int n, int max, double cputime, double realtime,
clique_options *opts) { staticfloat prev_time=100; staticint prev_i=100;
FILE *fp=opts->output; int j;
if (fp==NULL)
fp=stdout;
for (j=1; j<level; j++)
fprintf(fp," ");
if (realtime-prev_time < 0.01 || i<=prev_i)
fprintf(fp,"%3d/%d (max %2d) %2.2f s (0.00 s/round)\n",
i,n,max,realtime); else
fprintf(fp,"%3d/%d (max %2d) %2.2f s (%2.2f s/round)\n",
i,n,max,realtime,(realtime-prev_time)/(i-prev_i));
prev_time=realtime;
prev_i=i;
returnTRUE;
}
/* * This file contains the graph handling routines. * * Copyright (C) 2002 Sampo Niskanen, Patric Östergård. * Licensed under the GNU GPL, read the file LICENSE for details.
*/
/* * graph_new() * * Returns a newly allocated graph with n vertices all with weight 1, * and no edges.
*/
graph_t *graph_new(int n) {
graph_t *g; int i;
for (i=0; i < g->n; i++) {
set_free(g->edges[i]);
}
free(g->weights);
free(g->edges);
free(g); return;
}
/* * graph_resize() * * Resizes graph g to given size. If size > g->n, the new vertices are * not connected to any others and their weights are set to 1. * If size < g->n, the last g->n - size vertices are removed.
*/ void graph_resize(graph_t *g, int size) { int i;
/* Free/alloc extra edge-sets */ for (i=size; i < g->n; i++)
set_free(g->edges[i]);
g->edges=realloc(g->edges, size * sizeof(set_t)); for (i=g->n; i < size; i++)
g->edges[i]=set_new(size);
/* Resize original sets */ for (i=0; i < MIN(g->n,size); i++) {
g->edges[i]=set_resize(g->edges[i],size);
}
/* * graph_crop() * * Resizes the graph so as to remove all highest-valued isolated vertices.
*/ void graph_crop(graph_t *g) { int i;
for (i=g->n-1; i>=1; i--) if (set_size(g->edges[i])>0) break;
graph_resize(g,i+1); return;
}
/* * graph_weighted() * * Returns TRUE if all vertex weights of graph g are all the same. * * Note: Does NOT require weights to be 1.
*/
boolean graph_weighted(graph_t *g) { int i,w;
w=g->weights[0]; for (i=1; i < g->n; i++) if (g->weights[i] != w) returnTRUE; returnFALSE;
}
/* * graph_edge_count() * * Returns the number of edges in graph g.
*/ int graph_edge_count(graph_t *g) { int i; int count=0;
for (i=0; i < g->n; i++) {
count += set_size(g->edges[i]);
} return count/2;
}
/* * graph_print() * * Prints a representation of the graph g to stdout (along with any errors * noticed). Mainly useful for debugging purposes and trivial output. * * The output consists of a first line describing the dimensions and then * one line per vertex containing the vertex number (numbered 0,...,n-1), * the vertex weight (if the graph is weighted), "->" and then a list * of all vertices it is adjacent to.
*/ void graph_print(graph_t *g) { int i,j; int asymm=0; int refl=0; int nonpos=0; int extra=0; unsignedint weight=0;
boolean weighted;
ASSERT((sizeof(setelement)*8)==ELEMENTSIZE);
if (g==NULL) {
printf(" WARNING: Graph pointer is NULL!\n"); return;
} if (g->n <= 0) {
printf(" WARNING: Graph has %d vertices " "(should be positive)!\n",g->n); return;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.