Exemplo n.º 1
0
/*
 * 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;
                }
        }
Exemplo n.º 2
0
//static void maximalize_clique(set_t s,graph_t *g) {
void 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;
}
Exemplo n.º 3
0
/*
 * 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.
 */
static int 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;
		}

		SET_ADD_ELEMENT(current_clique,v);
		prune_low=sub_weighted_all(newtable,p1-newtable,
					   newweight,
					   current_weight+w,
					   prune_low,prune_high,
					   min_weight,max_weight,maximal,
					   g,opts);
		SET_DEL_ELEMENT(current_clique,v);
		if ((prune_low<0) || (prune_low>=prune_high)) {
			/* Impossible to find larger clique. */
			break;
		}
	}
	temp_list[temp_count++]=newtable;
	return prune_low;
}
Exemplo n.º 4
0
/*
 * 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).
 */
static int weighted_clique_search_all(int *table, int start,
				      int min_weight, int max_weight,
				      boolean maximal, graph_t *g,
				      clique_options *opts) {
	struct timeval timeval;
	struct tms tms;
	int i,j;
	int v;
	int *newtable;
	int newsize;
	int newweight;

	if (temp_count) {
		temp_count--;
		newtable=temp_list[temp_count];
	} else {
		newtable=malloc(g->n * sizeof(int));
	}

	clique_list_count=0;
	set_empty(current_clique);
	for (i=start; i < g->n; i++) {
		v=table[i];
		clique_size[v]=min_weight;   /* Do not prune here. */

		newsize=0;
		newweight=0;
		for (j=0; j<i; j++) {
			if (GRAPH_IS_EDGE(g,v,table[j])) {
				newtable[newsize]=table[j];
				newweight+=g->weights[table[j]];
				newsize++;
			}
		}

		SET_ADD_ELEMENT(current_clique,v);
		j=sub_weighted_all(newtable,newsize,newweight,
				   g->weights[v],min_weight-1,INT_MAX,
				   min_weight,max_weight,maximal,g,opts);
		SET_DEL_ELEMENT(current_clique,v);

		if (j<0) {
			/* Abort. */
			break;
		}

		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;
			}
		}
	}
	temp_list[temp_count++]=newtable;

	return clique_list_count;
}
Exemplo n.º 5
0
/*
 * 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.
 */
static int weighted_clique_search_single(int *table, int min_weight,
					 int max_weight, graph_t *g,
					 clique_options *opts) {
	struct timeval timeval;
	struct tms tms;
	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;
	}
	
	localopts.time_function=NULL;
	localopts.reorder_function=NULL;
	localopts.reorder_map=NULL;
	localopts.user_function=false_function;
	localopts.user_data=NULL;
	localopts.clique_list=&best_clique;
	localopts.clique_list_length=1;
	clique_list_count=0;

	v=table[0];
	set_empty(best_clique);
	SET_ADD_ELEMENT(best_clique,v);
	search_weight=g->weights[v];
	if (min_weight && (search_weight >= min_weight)) {
		if (search_weight <= max_weight) {
			/* Found suitable clique. */
			return search_weight;
		}
		search_weight=min_weight-1;
	}
	clique_size[v]=search_weight;
	set_empty(current_clique);

	if (temp_count) {
		temp_count--;
		newtable=temp_list[temp_count];
	} else {
		newtable=malloc(g->n * sizeof(int));
	}

	for (i = 1; i < g->n; i++) {
		v=table[i];

		newsize=0;
		newweight=0;
		for (j=0; j<i; j++) {
			if (GRAPH_IS_EDGE(g,v,table[j])) {
				newweight += g->weights[table[j]];
				newtable[newsize]=table[j];
				newsize++;
			}
		}


		SET_ADD_ELEMENT(current_clique,v);
		search_weight=sub_weighted_all(newtable,newsize,newweight,
					       g->weights[v],search_weight,
					       clique_size[table[i-1]] +
					       g->weights[v],
					       min_w,max_weight,FALSE,
					       g,&localopts);
		SET_DEL_ELEMENT(current_clique,v);
		if (search_weight < 0) {
			break;
		}

		clique_size[v]=search_weight;

		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;
			}
		}
	}
	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]];
}
Exemplo n.º 6
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.
 */
static int 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++;
			}
		}

		/* Avoid unneccessary loops (next size == p1-newtable) */
		if (p1-newtable < min_size-1) {
			continue;
		}

		SET_ADD_ELEMENT(current_clique,v);
		n=sub_unweighted_all(newtable,p1-newtable,
				     min_size-1,max_size-1,maximal,g,opts);
		SET_DEL_ELEMENT(current_clique,v);
		if (n < 0) {
			/* Abort. */
			count -= n;
			count = -count;
			break;
		}
		count+=n;
	}
	temp_list[temp_count++]=newtable;
	return count;
}
Exemplo n.º 7
0
/*
 * 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]);
			return TRUE;
		}
		if (min_size==0) {
			set_empty(current_clique);
			return TRUE;
		}
		return FALSE;
	}
	if (size < min_size)
		return FALSE;

	/* 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;

		if (sub_unweighted_single(newtable,p1-newtable,
					  min_size-1,g)) {
			/* Clique found. */
			SET_ADD_ELEMENT(current_clique,v);
			temp_list[temp_count++]=newtable;
			return TRUE;
		}
	}
	temp_list[temp_count++]=newtable;
	return FALSE;
}
Exemplo n.º 8
0
/*
 * 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.
 *
 * 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.
 */
static int unweighted_clique_search_single(int *table, int min_size,
					   graph_t *g, clique_options *opts) {
	struct tms tms;
	struct timeval timeval;
	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 (opts && 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)) {
				temp_list[temp_count++]=newtable;
				return 0;
			}
		}

		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];
}