/* * reorder_set() * * Reorders the set s with a function i -> order[i]. * * Note: Assumes that order is the same size as SET_MAX_SIZE(s). */ void reorder_set(set_t s,int *order) { set_t tmp; int i,j; setelement e; ASSERT(reorder_is_bijection(order,SET_MAX_SIZE(s))); tmp=set_new(SET_MAX_SIZE(s)); for (i=0; i<(SET_MAX_SIZE(s)/ELEMENTSIZE); i++) { e=s[i]; if (e==0) continue; for (j=0; j<ELEMENTSIZE; j++) { if (e&1) { SET_ADD_ELEMENT(tmp,order[i*ELEMENTSIZE+j]); } e = e>>1; } } if (SET_MAX_SIZE(s)%ELEMENTSIZE) { e=s[i]; for (j=0; j<(SET_MAX_SIZE(s)%ELEMENTSIZE); j++) { if (e&1) { SET_ADD_ELEMENT(tmp,order[i*ELEMENTSIZE+j]); } e = e>>1; } }
/* * 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; ENTRANCE_SAVE(); entrance_level++; if (opts==NULL) opts=clique_default_options; ASSERT((sizeof(setelement)*8)==ELEMENTSIZE); ASSERT(g!=NULL); ASSERT(min_weight>=0); ASSERT(max_weight>=0); ASSERT((max_weight==0) || (min_weight <= max_weight)); ASSERT(!((min_weight==0) && (max_weight>0))); ASSERT((opts->reorder_function==NULL) || (opts->reorder_map==NULL)); if ((max_weight>0) && (min_weight>max_weight)) { /* state was not changed */ entrance_level--; return 0; } if (clocks_per_sec==0) clocks_per_sec=sysconf(_SC_CLK_TCK); ASSERT(clocks_per_sec>0); 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; } } weight_multiplier = g->weights[0]; entrance_level--; i=clique_unweighted_find_all(g,min_weight,max_weight,maximal, opts); ENTRANCE_RESTORE(); return i; } /* Dynamic allocation */ current_clique=set_new(g->n); best_clique=set_new(g->n); clique_size=malloc(g->n * sizeof(int)); memset(clique_size, 0, g->n * sizeof(int)); /* table allocated later */ temp_list=malloc((g->n+2)*sizeof(int *)); temp_count=0; /* "start clock" */ gettimeofday(&realtimer,NULL); times(&cputimer); /* reorder */ if (opts->reorder_function) { table=opts->reorder_function(g,TRUE); } else if (opts->reorder_map) { table=reorder_duplicate(opts->reorder_map,g->n); } else { table=reorder_ident(g->n); } ASSERT(reorder_is_bijection(table,g->n)); /* 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_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; ENTRANCE_SAVE(); entrance_level++; if (opts==NULL) opts=clique_default_options; ASSERT((sizeof(setelement)*8)==ELEMENTSIZE); ASSERT(g!=NULL); ASSERT(min_size>=0); ASSERT(max_size>=0); ASSERT((max_size==0) || (min_size <= max_size)); ASSERT(!((min_size==0) && (max_size>0))); ASSERT((opts->reorder_function==NULL) || (opts->reorder_map==NULL)); if ((max_size>0) && (min_size>max_size)) { /* state was not changed */ entrance_level--; return 0; } if (clocks_per_sec==0) clocks_per_sec=sysconf(_SC_CLK_TCK); ASSERT(clocks_per_sec>0); /* Dynamic allocation */ current_clique=set_new(g->n); clique_size=malloc(g->n * sizeof(int)); /* table allocated later */ temp_list=malloc((g->n+2)*sizeof(int *)); temp_count=0; clique_list_count=0; memset(clique_size,0,g->n * sizeof(int)); /* "start clock" */ gettimeofday(&realtimer,NULL); times(&cputimer); /* reorder */ if (opts->reorder_function) { table=opts->reorder_function(g,FALSE); } else if (opts->reorder_map) { table=reorder_duplicate(opts->reorder_map,g->n); } else { table=reorder_ident(g->n); } ASSERT(reorder_is_bijection(table,g->n)); /* 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); cleanreturn: /* Free resources */ for (i=0; i<temp_count; i++) free(temp_list[i]); free(temp_list); free(table); free(clique_size); set_free(current_clique); ENTRANCE_RESTORE(); entrance_level--; return count; }
/* * 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; ENTRANCE_SAVE(); entrance_level++; if (opts==NULL) opts=clique_default_options; ASSERT((sizeof(setelement)*8)==ELEMENTSIZE); ASSERT(g!=NULL); ASSERT(min_weight>=0); ASSERT(max_weight>=0); ASSERT((max_weight==0) || (min_weight <= max_weight)); ASSERT(!((min_weight==0) && (max_weight>0))); ASSERT((opts->reorder_function==NULL) || (opts->reorder_map==NULL)); if ((max_weight>0) && (min_weight>max_weight)) { /* state was not changed */ entrance_level--; return NULL; } if (clocks_per_sec==0) clocks_per_sec=sysconf(_SC_CLK_TCK); ASSERT(clocks_per_sec>0); /* 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; } } weight_multiplier = g->weights[0]; entrance_level--; s=clique_unweighted_find_single(g,min_weight,max_weight, maximal,opts); ENTRANCE_RESTORE(); return s; } /* Dynamic allocation */ current_clique=set_new(g->n); best_clique=set_new(g->n); clique_size=malloc(g->n * sizeof(int)); memset(clique_size, 0, g->n * sizeof(int)); /* table allocated later */ temp_list=malloc((g->n+2)*sizeof(int *)); temp_count=0; clique_list_count=0; /* "start clock" */ gettimeofday(&realtimer,NULL); times(&cputimer); /* reorder */ if (opts->reorder_function) { table=opts->reorder_function(g,TRUE); } else if (opts->reorder_map) { table=reorder_duplicate(opts->reorder_map,g->n); } else { table=reorder_ident(g->n); } ASSERT(reorder_is_bijection(table,g->n)); if (max_weight==0) max_weight=INT_MAX; 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; localopts.time_function = opts->time_function; localopts.output = opts->output; localopts.user_function = false_function; localopts.clique_list = &best_clique; localopts.clique_list_length = 1; 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_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; ENTRANCE_SAVE(); entrance_level++; if (opts==NULL) opts=clique_default_options; ASSERT((sizeof(setelement)*8)==ELEMENTSIZE); ASSERT(g!=NULL); ASSERT(min_size>=0); ASSERT(max_size>=0); ASSERT((max_size==0) || (min_size <= max_size)); ASSERT(!((min_size==0) && (max_size>0))); ASSERT((opts->reorder_function==NULL) || (opts->reorder_map==NULL)); if ((max_size>0) && (min_size>max_size)) { /* state was not changed */ entrance_level--; return NULL; } if (clocks_per_sec==0) clocks_per_sec=sysconf(_SC_CLK_TCK); ASSERT(clocks_per_sec>0); /* Dynamic allocation */ current_clique=set_new(g->n); clique_size=malloc(g->n * sizeof(int)); /* table allocated later */ temp_list=malloc((g->n+2)*sizeof(int *)); temp_count=0; /* "start clock" */ gettimeofday(&realtimer,NULL); times(&cputimer); /* reorder */ if (opts->reorder_function) { table=opts->reorder_function(g,FALSE); } else if (opts->reorder_map) { table=reorder_duplicate(opts->reorder_map,g->n); } else { table=reorder_ident(g->n); } ASSERT(reorder_is_bijection(table,g->n)); if (unweighted_clique_search_single(table,min_size,g,opts)==0) { set_free(current_clique); current_clique=NULL; goto cleanreturn; } if (maximal && (min_size>0)) { maximalize_clique(current_clique,g); if ((max_size > 0) && (set_size(current_clique) > max_size)) { clique_options localopts; s = set_new(g->n); localopts.time_function = opts->time_function; localopts.output = opts->output; localopts.user_function = false_function; localopts.clique_list = &s; localopts.clique_list_length = 1; 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; }