int igraph_adjlist_init_complementer(const igraph_t *graph, igraph_adjlist_t *al, igraph_neimode_t mode, igraph_bool_t loops) { long int i, j, k, n; igraph_bool_t* seen; igraph_vector_t vec; if (mode != IGRAPH_IN && mode != IGRAPH_OUT && mode != IGRAPH_ALL) { IGRAPH_ERROR("Cannot create complementer adjlist view", IGRAPH_EINVMODE); } if (!igraph_is_directed(graph)) { mode=IGRAPH_ALL; } al->length=igraph_vcount(graph); al->adjs=igraph_Calloc(al->length, igraph_vector_t); if (al->adjs == 0) { IGRAPH_ERROR("Cannot create complementer adjlist view", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_adjlist_destroy, al); n=al->length; seen=igraph_Calloc(n, igraph_bool_t); if (seen==0) { IGRAPH_ERROR("Cannot create complementer adjlist view", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, seen); IGRAPH_VECTOR_INIT_FINALLY(&vec, 0); for (i=0; i<al->length; i++) { IGRAPH_ALLOW_INTERRUPTION(); igraph_neighbors(graph, &vec, i, mode); memset(seen, 0, sizeof(igraph_bool_t)*al->length); n=al->length; if (!loops) { seen[i] = 1; n--; } for (j=0; j<igraph_vector_size(&vec); j++) { if (! seen [ (long int) VECTOR(vec)[j] ] ) { n--; seen[ (long int) VECTOR(vec)[j] ] = 1; } } IGRAPH_CHECK(igraph_vector_init(&al->adjs[i], n)); for (j=0, k=0; k<n; j++) { if (!seen[j]) { VECTOR(al->adjs[i])[k++] = j; } } } igraph_Free(seen); igraph_vector_destroy(&vec); IGRAPH_FINALLY_CLEAN(3); return 0; }
int igraph_i_maximal_or_largest_cliques_or_indsets(const igraph_t *graph, igraph_vector_ptr_t *res, igraph_integer_t *clique_number, igraph_bool_t keep_only_largest, igraph_bool_t complementer) { igraph_i_max_ind_vsets_data_t clqdata; long int no_of_nodes = igraph_vcount(graph), i; if (igraph_is_directed(graph)) IGRAPH_WARNING("directionality of edges is ignored for directed graphs"); clqdata.matrix_size=no_of_nodes; clqdata.keep_only_largest=keep_only_largest; if (complementer) IGRAPH_CHECK(igraph_adjlist_init_complementer(graph, &clqdata.adj_list, IGRAPH_ALL, 0)); else IGRAPH_CHECK(igraph_adjlist_init(graph, &clqdata.adj_list, IGRAPH_ALL)); IGRAPH_FINALLY(igraph_adjlist_destroy, &clqdata.adj_list); clqdata.IS = igraph_Calloc(no_of_nodes, igraph_integer_t); if (clqdata.IS == 0) IGRAPH_ERROR("igraph_i_maximal_or_largest_cliques_or_indsets failed", IGRAPH_ENOMEM); IGRAPH_FINALLY(igraph_free, clqdata.IS); IGRAPH_VECTOR_INIT_FINALLY(&clqdata.deg, no_of_nodes); for (i=0; i<no_of_nodes; i++) VECTOR(clqdata.deg)[i] = igraph_vector_size(igraph_adjlist_get(&clqdata.adj_list, i)); clqdata.buckets = igraph_Calloc(no_of_nodes+1, igraph_set_t); if (clqdata.buckets == 0) IGRAPH_ERROR("igraph_maximal_or_largest_cliques_or_indsets failed", IGRAPH_ENOMEM); IGRAPH_FINALLY(igraph_i_free_set_array, clqdata.buckets); for (i=0; i<no_of_nodes; i++) IGRAPH_CHECK(igraph_set_init(&clqdata.buckets[i], 0)); if (res) igraph_vector_ptr_clear(res); /* Do the show */ clqdata.largest_set_size=0; IGRAPH_CHECK(igraph_i_maximal_independent_vertex_sets_backtrack(graph, res, &clqdata, 0)); /* Cleanup */ for (i=0; i<no_of_nodes; i++) igraph_set_destroy(&clqdata.buckets[i]); igraph_adjlist_destroy(&clqdata.adj_list); igraph_vector_destroy(&clqdata.deg); igraph_free(clqdata.IS); igraph_free(clqdata.buckets); IGRAPH_FINALLY_CLEAN(4); if (clique_number) *clique_number = clqdata.largest_set_size; return 0; }
int igraph_adjlist_init(const igraph_t *graph, igraph_adjlist_t *al, igraph_neimode_t mode) { long int i; if (mode != IGRAPH_IN && mode != IGRAPH_OUT && mode != IGRAPH_ALL) { IGRAPH_ERROR("Cannot create adjlist view", IGRAPH_EINVMODE); } if (!igraph_is_directed(graph)) { mode=IGRAPH_ALL; } al->length=igraph_vcount(graph); al->adjs=igraph_Calloc(al->length, igraph_vector_t); if (al->adjs == 0) { IGRAPH_ERROR("Cannot create adjlist view", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_adjlist_destroy, al); for (i=0; i<al->length; i++) { IGRAPH_ALLOW_INTERRUPTION(); IGRAPH_CHECK(igraph_vector_init(&al->adjs[i], 0)); IGRAPH_CHECK(igraph_neighbors(graph, &al->adjs[i], i, mode)); } IGRAPH_FINALLY_CLEAN(1); return 0; }
int igraph_inclist_init(const igraph_t *graph, igraph_inclist_t *il, igraph_neimode_t mode) { long int i; if (mode != IGRAPH_IN && mode != IGRAPH_OUT && mode != IGRAPH_ALL) { IGRAPH_ERROR("Cannot create incidence list view", IGRAPH_EINVMODE); } if (!igraph_is_directed(graph)) { mode=IGRAPH_ALL; } il->length=igraph_vcount(graph); il->incs=igraph_Calloc(il->length, igraph_vector_t); if (il->incs == 0) { IGRAPH_ERROR("Cannot create incidence list view", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_inclist_destroy, il); for (i=0; i<il->length; i++) { IGRAPH_ALLOW_INTERRUPTION(); IGRAPH_CHECK(igraph_vector_init(&il->incs[i], 0)); IGRAPH_CHECK(igraph_incident(graph, &il->incs[i], i, mode)); } IGRAPH_FINALLY_CLEAN(1); return 0; }
igraph_vector_t *igraph_lazy_adjlist_get_real(igraph_lazy_adjlist_t *al, igraph_integer_t pno) { long int no=pno; int ret; if (al->adjs[no] == 0) { al->adjs[no] = igraph_Calloc(1, igraph_vector_t); if (al->adjs[no] == 0) { igraph_error("Lazy adjlist failed", __FILE__, __LINE__, IGRAPH_ENOMEM); } ret=igraph_vector_init(al->adjs[no], 0); if (ret != 0) { igraph_error("", __FILE__, __LINE__, ret); } ret=igraph_neighbors(al->graph, al->adjs[no], no, al->mode); if (ret != 0) { igraph_error("", __FILE__, __LINE__, ret); } if (al->simplify == IGRAPH_SIMPLIFY) { igraph_vector_t *v=al->adjs[no]; long int i, p=0, n=igraph_vector_size(v); for (i=0; i<n; i++) { if (VECTOR(*v)[i] != no && (i==n-1 || VECTOR(*v)[i+1] != VECTOR(*v)[i])) { VECTOR(*v)[p]=VECTOR(*v)[i]; p++; } } igraph_vector_resize(v, p); } } return al->adjs[no]; }
int igraph_i_largest_cliques_store(const igraph_vector_t* clique, void* data, igraph_bool_t* cont) { igraph_vector_ptr_t* result = (igraph_vector_ptr_t*)data; igraph_vector_t* vec; long int i, n; /* Is the current clique at least as large as the others that we have found? */ if (!igraph_vector_ptr_empty(result)) { n = igraph_vector_size(clique); if (n < igraph_vector_size(VECTOR(*result)[0])) return IGRAPH_SUCCESS; if (n > igraph_vector_size(VECTOR(*result)[0])) { for (i = 0; i < igraph_vector_ptr_size(result); i++) igraph_vector_destroy(VECTOR(*result)[i]); igraph_vector_ptr_free_all(result); igraph_vector_ptr_resize(result, 0); } } vec = igraph_Calloc(1, igraph_vector_t); if (vec == 0) IGRAPH_ERROR("cannot allocate memory for storing next clique", IGRAPH_ENOMEM); IGRAPH_CHECK(igraph_vector_copy(vec, clique)); IGRAPH_CHECK(igraph_vector_ptr_push_back(result, vec)); return IGRAPH_SUCCESS; }
/* removes multiple edges and returns new edge id's for each edge in |E|log|E| */ int igraph_i_multilevel_simplify_multiple(igraph_t *graph, igraph_vector_t *eids) { long int ecount = igraph_ecount(graph); long int i, l = -1, last_from = -1, last_to = -1; igraph_bool_t directed = igraph_is_directed(graph); igraph_integer_t from, to; igraph_vector_t edges; igraph_i_multilevel_link *links; /* Make sure there's enough space in eids to store the new edge IDs */ IGRAPH_CHECK(igraph_vector_resize(eids, ecount)); links = igraph_Calloc(ecount, igraph_i_multilevel_link); if (links == 0) { IGRAPH_ERROR("multi-level community structure detection failed", IGRAPH_ENOMEM); } IGRAPH_FINALLY(free, links); for (i = 0; i < ecount; i++) { igraph_edge(graph, (igraph_integer_t) i, &from, &to); links[i].from = from; links[i].to = to; links[i].id = i; } qsort((void*)links, (size_t) ecount, sizeof(igraph_i_multilevel_link), igraph_i_multilevel_link_cmp); IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); for (i = 0; i < ecount; i++) { if (links[i].from == last_from && links[i].to == last_to) { VECTOR(*eids)[links[i].id] = l; continue; } last_from = links[i].from; last_to = links[i].to; igraph_vector_push_back(&edges, last_from); igraph_vector_push_back(&edges, last_to); l++; VECTOR(*eids)[links[i].id] = l; } free(links); IGRAPH_FINALLY_CLEAN(1); igraph_destroy(graph); IGRAPH_CHECK(igraph_create(graph, &edges, igraph_vcount(graph), directed)); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); return 0; }
int igraph_i_separators_store(igraph_vector_ptr_t *separators, const igraph_adjlist_t *adjlist, igraph_vector_t *components, igraph_vector_t *leaveout, unsigned long int *mark, igraph_vector_t *sorter) { /* We need to stote N(C), the neighborhood of C, but only if it is * not already stored among the separators. */ long int cptr=0, next, complen=igraph_vector_size(components); while (cptr < complen) { long int saved=cptr; igraph_vector_clear(sorter); /* Calculate N(C) for the next C */ while ( (next=(long int) VECTOR(*components)[cptr++]) != -1) { VECTOR(*leaveout)[next] = *mark; } cptr=saved; while ( (next=(long int) VECTOR(*components)[cptr++]) != -1) { igraph_vector_int_t *neis=igraph_adjlist_get(adjlist, next); long int j, nn=igraph_vector_int_size(neis); for (j=0; j<nn; j++) { long int nei=(long int) VECTOR(*neis)[j]; if (VECTOR(*leaveout)[nei] != *mark) { igraph_vector_push_back(sorter, nei); VECTOR(*leaveout)[nei] = *mark; } } } igraph_vector_sort(sorter); UPDATEMARK(); /* Add it to the list of separators, if it is new */ if (igraph_i_separators_newsep(separators, sorter)) { igraph_vector_t *newc=igraph_Calloc(1, igraph_vector_t); if (!newc) { IGRAPH_ERROR("Cannot calculate minimal separators", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, newc); igraph_vector_copy(newc, sorter); IGRAPH_FINALLY(igraph_vector_destroy, newc); IGRAPH_CHECK(igraph_vector_ptr_push_back(separators, newc)); IGRAPH_FINALLY_CLEAN(2); } } /* while cptr < complen */ return 0; }
int igraph_i_maximal_cliques_store(const igraph_vector_t* clique, void* data, igraph_bool_t* cont) { igraph_vector_ptr_t* result = (igraph_vector_ptr_t*)data; igraph_vector_t* vec; vec = igraph_Calloc(1, igraph_vector_t); if (vec == 0) IGRAPH_ERROR("cannot allocate memory for storing next clique", IGRAPH_ENOMEM); IGRAPH_CHECK(igraph_vector_copy(vec, clique)); IGRAPH_CHECK(igraph_vector_ptr_push_back(result, vec)); return IGRAPH_SUCCESS; }
int igraph_i_maximal_cliques_store_size_check(const igraph_vector_t* clique, void* data_, igraph_bool_t* cont) { igraph_i_maximal_clique_data_t* data = (igraph_i_maximal_clique_data_t*)data_; igraph_vector_t* vec; igraph_integer_t size = igraph_vector_size(clique); if (size < data->min_size || size > data->max_size) return IGRAPH_SUCCESS; vec = igraph_Calloc(1, igraph_vector_t); if (vec == 0) IGRAPH_ERROR("cannot allocate memory for storing next clique", IGRAPH_ENOMEM); IGRAPH_CHECK(igraph_vector_copy(vec, clique)); IGRAPH_CHECK(igraph_vector_ptr_push_back(data->result, vec)); return IGRAPH_SUCCESS; }
int igraph_inclist_init_empty(igraph_inclist_t *il, igraph_integer_t n) { long int i; il->length=n; il->incs=igraph_Calloc(il->length, igraph_vector_t); if (il->incs == 0) { IGRAPH_ERROR("Cannot create incidence list view", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_inclist_destroy, il); for (i=0; i<n; i++) { IGRAPH_CHECK(igraph_vector_init(&il->incs[i], 0)); } IGRAPH_FINALLY_CLEAN(1); return 0; }
int igraph_adjlist_init_empty(igraph_adjlist_t *al, igraph_integer_t no_of_nodes) { long int i; al->length=no_of_nodes; al->adjs=igraph_Calloc(al->length, igraph_vector_t); if (al->adjs == 0) { IGRAPH_ERROR("Cannot create adjlist view", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_adjlist_destroy, al); for (i=0; i<al->length; i++) { IGRAPH_CHECK(igraph_vector_init(&al->adjs[i], 0)); } IGRAPH_FINALLY_CLEAN(1); return 0; }
int igraph_attribute_combination_add(igraph_attribute_combination_t *comb, const char *name, igraph_attribute_combination_type_t type, void *func) { long int i, n=igraph_vector_ptr_size(&comb->list); /* Search, in case it is already there */ for (i=0; i<n; i++) { igraph_attribute_combination_record_t *r=VECTOR(comb->list)[i]; const char *n=r->name; if ( (!name && !n) || (name && n && !strcmp(n, name)) ) { r->type=type; r->func=func; break; } } if (i==n) { /* This is a new attribute name */ igraph_attribute_combination_record_t *rec= igraph_Calloc(1, igraph_attribute_combination_record_t); if (!rec) { IGRAPH_ERROR("Cannot create attribute combination data", IGRAPH_ENOMEM); } if (!name) { rec->name=0; } else { rec->name=strdup(name); } rec->type=type; rec->func=func; IGRAPH_CHECK(igraph_vector_ptr_push_back(&comb->list, rec)); } return 0; }
igraph_vector_t *igraph_lazy_inclist_get_real(igraph_lazy_inclist_t *il, igraph_integer_t pno) { long int no=pno; int ret; if (il->incs[no] == 0) { il->incs[no] = igraph_Calloc(1, igraph_vector_t); if (il->incs[no] == 0) { igraph_error("Lazy incidence list query failed", __FILE__, __LINE__, IGRAPH_ENOMEM); } ret=igraph_vector_init(il->incs[no], 0); if (ret != 0) { igraph_error("", __FILE__, __LINE__, ret); } ret=igraph_incident(il->graph, il->incs[no], no, il->mode); if (ret != 0) { igraph_error("", __FILE__, __LINE__, ret); } } return il->incs[no]; }
int igraph_get_eids(const igraph_t *graph, igraph_vector_t *eids, const igraph_vector_t *pairs, igraph_bool_t directed) { long int n=igraph_vector_size(pairs); long int no_of_nodes=igraph_vcount(graph); long int no_of_edges=igraph_ecount(graph); igraph_bool_t *seen; long int i; igraph_integer_t eid=-1; if (n % 2 != 0) { IGRAPH_ERROR("Cannot get edge ids, invalid length of edge ids", IGRAPH_EINVAL); } if (!igraph_vector_isininterval(pairs, 0, no_of_nodes-1)) { IGRAPH_ERROR("Cannot get edge ids, invalid vertex id", IGRAPH_EINVVID); } seen=igraph_Calloc(no_of_edges, igraph_bool_t); if (seen==0) { IGRAPH_ERROR("Cannot get edge ids", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, seen); IGRAPH_CHECK(igraph_vector_resize(eids, n/2)); if (igraph_is_directed(graph)) { for (i=0; i<n/2; i++) { long int from=VECTOR(*pairs)[2*i]; long int to=VECTOR(*pairs)[2*i+1]; eid=-1; FIND_DIRECTED_EDGE(graph,from,to,&eid,seen); if (!directed && eid < 0) { FIND_DIRECTED_EDGE(graph,to,from,&eid,seen); } if (eid >= 0) { VECTOR(*eids)[i]=eid; seen[(long int)(eid)]=1; } else { IGRAPH_ERROR("Cannot get edge id, no such edge", IGRAPH_EINVAL); } } } else { for (i=0; i<n/2; i++) { long int from=VECTOR(*pairs)[2*i]; long int to=VECTOR(*pairs)[2*i+1]; eid=-1; FIND_UNDIRECTED_EDGE(graph,from,to,&eid,seen); if (eid >= 0) { VECTOR(*eids)[i]=eid; seen[(long int)(eid)]=1; } else { IGRAPH_ERROR("Cannot get edge id, no such edge", IGRAPH_EINVAL); } } } igraph_Free(seen); IGRAPH_FINALLY_CLEAN(1); return 0; }
/* Internal function for calculating cliques or independent vertex sets. * They are practically the same except that the complementer of the graph * should be used in the latter case. */ int igraph_i_cliques(const igraph_t *graph, igraph_vector_ptr_t *res, igraph_integer_t min_size, igraph_integer_t max_size, igraph_bool_t independent_vertices) { igraph_integer_t no_of_nodes; igraph_vector_t neis; igraph_real_t *member_storage=0, *new_member_storage, *c1; long int i, j, k, clique_count, old_clique_count; if (igraph_is_directed(graph)) IGRAPH_WARNING("directionality of edges is ignored for directed graphs"); no_of_nodes = igraph_vcount(graph); if (min_size < 0) { min_size = 0; } if (max_size > no_of_nodes || max_size <= 0) { max_size = no_of_nodes; } igraph_vector_ptr_clear(res); IGRAPH_VECTOR_INIT_FINALLY(&neis, 0); IGRAPH_FINALLY(igraph_i_cliques_free_res, res); /* Will be resized later, if needed. */ member_storage=igraph_Calloc(1, igraph_real_t); if (member_storage==0) { IGRAPH_ERROR("cliques failed", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, member_storage); /* Find all 1-cliques: every vertex will be a clique */ new_member_storage=igraph_Calloc(no_of_nodes, igraph_real_t); if (new_member_storage==0) { IGRAPH_ERROR("cliques failed", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, new_member_storage); for (i=0; i<no_of_nodes; i++) { new_member_storage[i] = i; } clique_count = no_of_nodes; old_clique_count = 0; /* Add size 1 cliques if requested */ if (min_size <= 1) { IGRAPH_CHECK(igraph_vector_ptr_resize(res, no_of_nodes)); igraph_vector_ptr_null(res); for (i=0; i<no_of_nodes; i++) { igraph_vector_t *p=igraph_Calloc(1, igraph_vector_t); if (p==0) { IGRAPH_ERROR("cliques failed", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, p); IGRAPH_CHECK(igraph_vector_init(p, 1)); VECTOR(*p)[0]=i; VECTOR(*res)[i]=p; IGRAPH_FINALLY_CLEAN(1); } } for (i=2; i<=max_size && clique_count > 1; i++) { /* Here new_member_storage contains the cliques found in the previous iteration. Save this into member_storage, might be needed later */ c1=member_storage; member_storage=new_member_storage; new_member_storage=c1; old_clique_count=clique_count; IGRAPH_ALLOW_INTERRUPTION(); /* Calculate the cliques */ IGRAPH_FINALLY_CLEAN(2); IGRAPH_CHECK(igraph_i_find_k_cliques(graph, i, member_storage, &new_member_storage, old_clique_count, &clique_count, &neis, independent_vertices)); IGRAPH_FINALLY(igraph_free, member_storage); IGRAPH_FINALLY(igraph_free, new_member_storage); /* Add the cliques just found to the result if requested */ if (i>=min_size && i<=max_size) { for (j=0, k=0; j<clique_count; j++, k+=i) { igraph_vector_t *p=igraph_Calloc(1, igraph_vector_t); if (p==0) { IGRAPH_ERROR("cliques failed", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, p); IGRAPH_CHECK(igraph_vector_init_copy(p, &new_member_storage[k], i)); IGRAPH_FINALLY(igraph_vector_destroy, p); IGRAPH_CHECK(igraph_vector_ptr_push_back(res, p)); IGRAPH_FINALLY_CLEAN(2); } } } /* i <= max_size && clique_count != 0 */ igraph_free(member_storage); igraph_free(new_member_storage); igraph_vector_destroy(&neis); IGRAPH_FINALLY_CLEAN(4); /* 3 here, +1 is igraph_i_cliques_free_res */ return 0; }
int igraph_i_maximal_independent_vertex_sets_backtrack(const igraph_t *graph, igraph_vector_ptr_t *res, igraph_i_max_ind_vsets_data_t *clqdata, igraph_integer_t level) { long int v1, v2, v3, c, j, k; igraph_vector_t *neis1, *neis2; igraph_bool_t f; igraph_integer_t j1; long int it_state; IGRAPH_ALLOW_INTERRUPTION(); if (level >= clqdata->matrix_size-1) { igraph_integer_t size=0; if (res) { igraph_vector_t *vec; vec = igraph_Calloc(1, igraph_vector_t); if (vec == 0) IGRAPH_ERROR("igraph_i_maximal_independent_vertex_sets failed", IGRAPH_ENOMEM); IGRAPH_VECTOR_INIT_FINALLY(vec, 0); for (v1=0; v1<clqdata->matrix_size; v1++) if (clqdata->IS[v1] == 0) { IGRAPH_CHECK(igraph_vector_push_back(vec, v1)); } size=igraph_vector_size(vec); if (!clqdata->keep_only_largest) IGRAPH_CHECK(igraph_vector_ptr_push_back(res, vec)); else { if (size > clqdata->largest_set_size) { /* We are keeping only the largest sets, and we've found one that's * larger than all previous sets, so we have to clear the list */ j=igraph_vector_ptr_size(res); for (v1=0; v1<j; v1++) { igraph_vector_destroy(VECTOR(*res)[v1]); free(VECTOR(*res)[v1]); } igraph_vector_ptr_clear(res); IGRAPH_CHECK(igraph_vector_ptr_push_back(res, vec)); } else if (size == clqdata->largest_set_size) { IGRAPH_CHECK(igraph_vector_ptr_push_back(res, vec)); } else { igraph_vector_destroy(vec); free(vec); } } IGRAPH_FINALLY_CLEAN(1); } else { for (v1=0, size=0; v1<clqdata->matrix_size; v1++) if (clqdata->IS[v1] == 0) size++; } if (size>clqdata->largest_set_size) clqdata->largest_set_size=size; } else { v1 = level+1; /* Count the number of vertices with an index less than v1 that have * an IS value of zero */ neis1 = igraph_adjlist_get(&clqdata->adj_list, v1); c = 0; j = 0; while (j<VECTOR(clqdata->deg)[v1] && (v2=VECTOR(*neis1)[j]) <= level) { if (clqdata->IS[v2] == 0) c++; j++; } if (c == 0) { /* If there are no such nodes... */ j = 0; while (j<VECTOR(clqdata->deg)[v1] && (v2=VECTOR(*neis1)[j]) <= level) { clqdata->IS[v2]++; j++; } IGRAPH_CHECK(igraph_i_maximal_independent_vertex_sets_backtrack(graph,res,clqdata,v1)); j = 0; while (j<VECTOR(clqdata->deg)[v1] && (v2=VECTOR(*neis1)[j]) <= level) { clqdata->IS[v2]--; j++; } } else { /* If there are such nodes, store the count in the IS value of v1 */ clqdata->IS[v1] = c; IGRAPH_CHECK(igraph_i_maximal_independent_vertex_sets_backtrack(graph,res,clqdata,v1)); clqdata->IS[v1] = 0; f=1; j=0; while (j<VECTOR(clqdata->deg)[v1] && (v2=VECTOR(*neis1)[j]) <= level) { if (clqdata->IS[v2] == 0) { IGRAPH_CHECK(igraph_set_add(&clqdata->buckets[v1], j)); neis2 = igraph_adjlist_get(&clqdata->adj_list, v2); k = 0; while (k<VECTOR(clqdata->deg)[v2] && (v3=VECTOR(*neis2)[k])<=level) { clqdata->IS[v3]--; if (clqdata->IS[v3] == 0) f=0; k++; } } clqdata->IS[v2]++; j++; } if (f) IGRAPH_CHECK(igraph_i_maximal_independent_vertex_sets_backtrack(graph,res,clqdata,v1)); j=0; while (j<VECTOR(clqdata->deg)[v1] && (v2=VECTOR(*neis1)[j]) <= level) { clqdata->IS[v2]--; j++; } it_state=0; while (igraph_set_iterate(&clqdata->buckets[v1], &it_state, &j1)) { j=(long)j1; v2=VECTOR(*neis1)[j]; neis2 = igraph_adjlist_get(&clqdata->adj_list, v2); k = 0; while (k<VECTOR(clqdata->deg)[v2] && (v3=VECTOR(*neis2)[k])<=level) { clqdata->IS[v3]++; k++; } } igraph_set_clear(&clqdata->buckets[v1]); } } return 0; }
/** * \ingroup nongraph * \function igraph_convex_hull * \brief Determines the convex hull of a given set of points in the 2D plane * * </para><para> * The convex hull is determined by the Graham scan algorithm. * See the following reference for details: * * </para><para> * Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford * Stein. Introduction to Algorithms, Second Edition. MIT Press and * McGraw-Hill, 2001. ISBN 0262032937. Pages 949-955 of section 33.3: * Finding the convex hull. * * \param data vector containing the coordinates. The length of the * vector must be even, since it contains X-Y coordinate pairs. * \param resverts the vector containing the result, e.g. the vector of * vertex indices used as the corners of the convex hull. Supply * \c NULL here if you are only interested in the coordinates of * the convex hull corners. * \param rescoords the matrix containing the coordinates of the selected * corner vertices. Supply \c NULL here if you are only interested in * the vertex indices. * \return Error code: * \c IGRAPH_ENOMEM: not enough memory * * Time complexity: O(n log(n)) where n is the number of vertices */ int igraph_convex_hull(const igraph_matrix_t *data, igraph_vector_t *resverts, igraph_matrix_t *rescoords) { igraph_integer_t no_of_nodes; long int i, pivot_idx=0, last_idx, before_last_idx, next_idx, j; igraph_real_t* angles; igraph_vector_t stack; igraph_indheap_t order; igraph_real_t px, py, cp; no_of_nodes=igraph_matrix_nrow(data); if (igraph_matrix_ncol(data) != 2) { IGRAPH_ERROR("matrix must have 2 columns", IGRAPH_EINVAL); } if (no_of_nodes == 0) { if (resverts != 0) { IGRAPH_CHECK(igraph_vector_resize(resverts, 0)); } if (rescoords != 0) { IGRAPH_CHECK(igraph_matrix_resize(rescoords, 0, 2)); } /**************************** this is an exit here *********/ return 0; } angles=igraph_Calloc(no_of_nodes, igraph_real_t); if (!angles) IGRAPH_ERROR("not enough memory for angle array", IGRAPH_ENOMEM); IGRAPH_FINALLY(free, angles); IGRAPH_VECTOR_INIT_FINALLY(&stack, 0); /* Search for the pivot vertex */ for (i=1; i<no_of_nodes; i++) { if (MATRIX(*data, i, 1)<MATRIX(*data, pivot_idx, 1)) pivot_idx=i; else if (MATRIX(*data, i, 1) == MATRIX(*data, pivot_idx, 1) && MATRIX(*data, i, 0) < MATRIX(*data, pivot_idx, 0)) pivot_idx=i; } px=MATRIX(*data, pivot_idx, 0); py=MATRIX(*data, pivot_idx, 1); /* Create angle array */ for (i=0; i<no_of_nodes; i++) { if (i == pivot_idx) { /* We can't calculate the angle of the pivot point with itself, * so we use 10 here. This way, after sorting the angle vector, * the pivot point will always be the first one, since the range * of atan2 is -3.14..3.14 */ angles[i] = 10; } else { angles[i] = atan2(MATRIX(*data, i, 1)-py, MATRIX(*data, i, 0)-px); } } IGRAPH_CHECK(igraph_indheap_init_array(&order, angles, no_of_nodes)); IGRAPH_FINALLY(igraph_indheap_destroy, &order); igraph_Free(angles); IGRAPH_FINALLY_CLEAN(1); if (no_of_nodes == 1) { IGRAPH_CHECK(igraph_vector_push_back(&stack, 0)); igraph_indheap_delete_max(&order); } else { /* Do the trick */ IGRAPH_CHECK(igraph_vector_push_back(&stack, igraph_indheap_max_index(&order)-1)); igraph_indheap_delete_max(&order); IGRAPH_CHECK(igraph_vector_push_back(&stack, igraph_indheap_max_index(&order)-1)); igraph_indheap_delete_max(&order); j=2; while (!igraph_indheap_empty(&order)) { /* Determine whether we are at a left or right turn */ last_idx=VECTOR(stack)[j-1]; before_last_idx=VECTOR(stack)[j-2]; next_idx=(long)igraph_indheap_max_index(&order)-1; igraph_indheap_delete_max(&order); cp=(MATRIX(*data, last_idx, 0)-MATRIX(*data, before_last_idx, 0))* (MATRIX(*data, next_idx, 1)-MATRIX(*data, before_last_idx, 1))- (MATRIX(*data, next_idx, 0)-MATRIX(*data, before_last_idx, 0))* (MATRIX(*data, last_idx, 1)-MATRIX(*data, before_last_idx, 1)); /* printf("B L N cp: %d, %d, %d, %f [", before_last_idx, last_idx, next_idx, (float)cp); for (k=0; k<j; k++) printf("%ld ", (long)VECTOR(stack)[k]); printf("]\n"); */ if (cp == 0) { /* The last three points are collinear. Replace the last one in * the stack to the newest one */ VECTOR(stack)[j-1]=next_idx; } else if (cp < 0) { /* We are turning into the right direction */ IGRAPH_CHECK(igraph_vector_push_back(&stack, next_idx)); j++; } else { /* No, skip back until we're okay */ while (cp >= 0 && j > 2) { igraph_vector_pop_back(&stack); j--; last_idx=VECTOR(stack)[j-1]; before_last_idx=VECTOR(stack)[j-2]; cp=(MATRIX(*data, last_idx, 0)-MATRIX(*data, before_last_idx, 0))* (MATRIX(*data, next_idx, 1)-MATRIX(*data, before_last_idx, 1))- (MATRIX(*data, next_idx, 0)-MATRIX(*data, before_last_idx, 0))* (MATRIX(*data, last_idx, 1)-MATRIX(*data, before_last_idx, 1)); } IGRAPH_CHECK(igraph_vector_push_back(&stack, next_idx)); j++; } } } /* Create result vector */ if (resverts != 0) { igraph_vector_clear(resverts); IGRAPH_CHECK(igraph_vector_append(resverts, &stack)); } if (rescoords != 0) { igraph_matrix_select_rows(data, rescoords, &stack); } /* Free everything */ igraph_vector_destroy(&stack); igraph_indheap_destroy(&order); IGRAPH_FINALLY_CLEAN(2); return 0; }
int igraph_intersection_many(igraph_t *res, const igraph_vector_ptr_t *graphs, igraph_vector_ptr_t *edgemaps) { long int no_of_graphs=igraph_vector_ptr_size(graphs); long int no_of_nodes=0; igraph_bool_t directed=1; igraph_vector_t edges; igraph_vector_ptr_t edge_vects, order_vects; long int i, j, tailfrom = no_of_graphs > 0 ? 0 : -1, tailto=-1; igraph_vector_long_t no_edges; igraph_bool_t allne= no_of_graphs == 0 ? 0 : 1, allsame=0; long int idx=0; /* Check directedness */ if (no_of_graphs != 0) { directed=igraph_is_directed(VECTOR(*graphs)[0]); } for (i=1; i<no_of_graphs; i++) { if (directed != igraph_is_directed(VECTOR(*graphs)[i])) { IGRAPH_ERROR("Cannot intersect directed and undirected graphs", IGRAPH_EINVAL); } } if (edgemaps) { IGRAPH_CHECK(igraph_vector_ptr_resize(edgemaps, no_of_graphs)); igraph_vector_ptr_null(edgemaps); IGRAPH_FINALLY(igraph_i_union_many_free3, edgemaps); } IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); IGRAPH_CHECK(igraph_vector_long_init(&no_edges, no_of_graphs)); IGRAPH_FINALLY(igraph_vector_long_destroy, &no_edges); /* Calculate number of nodes, query number of edges */ for (i=0; i<no_of_graphs; i++) { long int n=igraph_vcount(VECTOR(*graphs)[i]); if (n > no_of_nodes) { no_of_nodes=n; } VECTOR(no_edges)[i] = igraph_ecount(VECTOR(*graphs)[i]); allne = allne && VECTOR(no_edges)[i] > 0; } if (edgemaps) { for (i=0; i<no_of_graphs; i++) { VECTOR(*edgemaps)[i]=igraph_Calloc(1, igraph_vector_t); if (!VECTOR(*edgemaps)[i]) { IGRAPH_ERROR("Cannot intersect graphs", IGRAPH_ENOMEM); } IGRAPH_CHECK(igraph_vector_init(VECTOR(*edgemaps)[i], VECTOR(no_edges)[i])); igraph_vector_fill(VECTOR(*edgemaps)[i], -1); } } /* Allocate memory for the edge lists and their index vectors */ if (no_of_graphs != 0) { IGRAPH_CHECK(igraph_vector_ptr_init(&edge_vects, no_of_graphs)); IGRAPH_FINALLY(igraph_i_union_many_free, &edge_vects); IGRAPH_CHECK(igraph_vector_ptr_init(&order_vects, no_of_graphs)); IGRAPH_FINALLY(igraph_i_union_many_free2, &order_vects); } for (i=0; i<no_of_graphs; i++) { VECTOR(edge_vects)[i]=igraph_Calloc(1, igraph_vector_t); VECTOR(order_vects)[i]=igraph_Calloc(1, igraph_vector_long_t); if (! VECTOR(edge_vects)[i] || ! VECTOR(order_vects)[i]) { IGRAPH_ERROR("Cannot intersect graphs", IGRAPH_ENOMEM); } IGRAPH_CHECK(igraph_vector_init(VECTOR(edge_vects)[i], 2 * VECTOR(no_edges)[i])); IGRAPH_CHECK(igraph_vector_long_init(VECTOR(order_vects)[i], VECTOR(no_edges)[i])); } /* Query and sort the edge lists */ for (i=0; i<no_of_graphs; i++) { long int k, j, n=VECTOR(no_edges)[i]; igraph_vector_t *edges=VECTOR(edge_vects)[i]; igraph_vector_long_t *order=VECTOR(order_vects)[i]; IGRAPH_CHECK(igraph_get_edgelist(VECTOR(*graphs)[i], edges, /*bycol=*/0)); if (!directed) { for (k=0, j=0; k<n; k++, j+=2) { if (VECTOR(*edges)[j] > VECTOR(*edges)[j+1]) { long int tmp=VECTOR(*edges)[j]; VECTOR(*edges)[j]=VECTOR(*edges)[j+1]; VECTOR(*edges)[j+1]=tmp; } } } for (k=0; k<n; k++) { VECTOR(*order)[k]=k; } igraph_qsort_r(VECTOR(*order), n, sizeof(VECTOR(*order)[0]), edges, igraph_i_order_edgelist_cmp); } /* Do the merge. We work from the end of the edge lists, because then we don't have to keep track of where we are right now in the edge and order lists. We find the "largest" edge, and if it is present in all graphs, then we copy it to the result. We remove all instances of this edge. */ while (allne) { /* Look for the smallest tail element */ for (j=0, tailfrom=LONG_MAX, tailto=LONG_MAX; j<no_of_graphs; j++) { long int edge=igraph_vector_long_tail(VECTOR(order_vects)[j]); igraph_vector_t *ev=VECTOR(edge_vects)[j]; long int from=VECTOR(*ev)[2*edge]; long int to=VECTOR(*ev)[2*edge+1]; if (from < tailfrom || (from == tailfrom && to < tailto)) { tailfrom = from; tailto = to; } } /* OK, now remove all elements from the tail(s) that are bigger than the smallest tail element. */ for (j=0, allsame=1; j<no_of_graphs; j++) { long int from=-1, to=-1; while (1) { long int edge=igraph_vector_long_tail(VECTOR(order_vects)[j]); igraph_vector_t *ev=VECTOR(edge_vects)[j]; from=VECTOR(*ev)[2*edge]; to=VECTOR(*ev)[2*edge+1]; if (from > tailfrom || (from==tailfrom && to > tailto)) { igraph_vector_long_pop_back(VECTOR(order_vects)[j]); if (igraph_vector_long_empty(VECTOR(order_vects)[j])) { allne=0; break; } } else { break; } } if (from != tailfrom || to != tailto) { allsame=0; } } /* Add the edge, if the smallest tail element was present in all graphs. */ if (allsame) { IGRAPH_CHECK(igraph_vector_push_back(&edges, tailfrom)); IGRAPH_CHECK(igraph_vector_push_back(&edges, tailto)); } /* Drop edges matching the smalles tail elements from the order vectors, build edge maps */ if (allne) { for (j=0; j<no_of_graphs; j++) { long int edge=igraph_vector_long_tail(VECTOR(order_vects)[j]); igraph_vector_t *ev=VECTOR(edge_vects)[j]; long int from=VECTOR(*ev)[2*edge]; long int to=VECTOR(*ev)[2*edge+1]; if (from == tailfrom && to == tailto) { igraph_vector_long_pop_back(VECTOR(order_vects)[j]); if (igraph_vector_long_empty(VECTOR(order_vects)[j])) { allne=0; } if (edgemaps && allsame) { igraph_vector_t *map=VECTOR(*edgemaps)[j]; VECTOR(*map)[edge]=idx; } } } if (allsame) { idx++; } } } /* while allne */ if (no_of_graphs > 0) { igraph_i_union_many_free2(&order_vects); igraph_i_union_many_free(&edge_vects); IGRAPH_FINALLY_CLEAN(2); } igraph_vector_long_destroy(&no_edges); IGRAPH_FINALLY_CLEAN(1); IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) no_of_nodes, directed)); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); if (edgemaps) { IGRAPH_FINALLY_CLEAN(1); } return 0; }
int igraph_decompose(const igraph_t *graph, igraph_vector_ptr_t *components, igraph_connectedness_t mode, long int maxcompno, long int minelements) { long int actstart; long int no_of_nodes=igraph_vcount(graph); long int resco=0; /* number of graphs created so far */ char *already_added; igraph_dqueue_t q; igraph_vector_t verts; igraph_vector_t neis; long int i; igraph_t *newg; if (!igraph_is_directed(graph)) { mode=IGRAPH_WEAK; } if (mode != IGRAPH_WEAK) { IGRAPH_ERROR("only 'IGRAPH_WEAK' is implemented", IGRAPH_EINVAL); } if (maxcompno<0) { maxcompno=LONG_MAX; } igraph_vector_ptr_clear(components); IGRAPH_FINALLY(igraph_decompose_destroy, components); already_added=igraph_Calloc(no_of_nodes, char); if (already_added==0) { IGRAPH_ERROR("Cannot decompose graph", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, already_added); IGRAPH_CHECK(igraph_dqueue_init(&q, 100)); IGRAPH_FINALLY(igraph_dqueue_destroy, &q); IGRAPH_VECTOR_INIT_FINALLY(&verts, 0); IGRAPH_VECTOR_INIT_FINALLY(&neis, 0); for(actstart=0; resco<maxcompno && actstart < no_of_nodes; actstart++) { if (already_added[actstart]) { continue; } IGRAPH_ALLOW_INTERRUPTION(); igraph_vector_clear(&verts); already_added[actstart]=1; IGRAPH_CHECK(igraph_vector_push_back(&verts, actstart)); IGRAPH_CHECK(igraph_dqueue_push(&q, actstart)); while (!igraph_dqueue_empty(&q) ) { long int actvert=(long int) igraph_dqueue_pop(&q); IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) actvert, IGRAPH_ALL)); for (i=0; i<igraph_vector_size(&neis); i++) { long int neighbor=(long int) VECTOR(neis)[i]; if (already_added[neighbor]==1) { continue; } IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor)); IGRAPH_CHECK(igraph_vector_push_back(&verts, neighbor)); already_added[neighbor]=1; } } /* ok, we have a component */ if (igraph_vector_size(&verts)<minelements) { continue; } newg=igraph_Calloc(1, igraph_t); if (newg==0) { IGRAPH_ERROR("Cannot decompose graph", IGRAPH_ENOMEM); } IGRAPH_CHECK(igraph_vector_ptr_push_back(components, newg)); IGRAPH_CHECK(igraph_induced_subgraph(graph, newg, igraph_vss_vector(&verts), IGRAPH_SUBGRAPH_AUTO)); resco++; } /* for actstart++ */ igraph_vector_destroy(&neis); igraph_vector_destroy(&verts); igraph_dqueue_destroy(&q); igraph_free(already_added); IGRAPH_FINALLY_CLEAN(5); /* + components */ return 0; }
int igraph_biconnected_components(const igraph_t *graph, igraph_integer_t *no, igraph_vector_ptr_t *tree_edges, igraph_vector_ptr_t *component_edges, igraph_vector_ptr_t *components, igraph_vector_t *articulation_points) { long int no_of_nodes=igraph_vcount(graph); igraph_vector_long_t nextptr; igraph_vector_long_t num, low; igraph_vector_bool_t found; igraph_vector_int_t *adjedges; igraph_stack_t path; igraph_vector_t edgestack; igraph_inclist_t inclist; long int i, counter, rootdfs=0; igraph_vector_long_t vertex_added; long int comps=0; igraph_vector_ptr_t *mycomponents=components, vcomponents; IGRAPH_CHECK(igraph_vector_long_init(&nextptr, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &nextptr); IGRAPH_CHECK(igraph_vector_long_init(&num, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &num); IGRAPH_CHECK(igraph_vector_long_init(&low, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &low); IGRAPH_CHECK(igraph_vector_bool_init(&found, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_bool_destroy, &found); IGRAPH_CHECK(igraph_stack_init(&path, 100)); IGRAPH_FINALLY(igraph_stack_destroy, &path); IGRAPH_VECTOR_INIT_FINALLY(&edgestack, 0); IGRAPH_CHECK(igraph_vector_reserve(&edgestack, 100)); IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, IGRAPH_ALL)); IGRAPH_FINALLY(igraph_inclist_destroy, &inclist); IGRAPH_CHECK(igraph_vector_long_init(&vertex_added, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &vertex_added); if (no) { *no=0; } if (tree_edges) { igraph_vector_ptr_clear(tree_edges); } if (components) { igraph_vector_ptr_clear(components); } if (component_edges) { igraph_vector_ptr_clear(component_edges); } if (articulation_points) { igraph_vector_clear(articulation_points); } if (component_edges && !components) { mycomponents=&vcomponents; IGRAPH_CHECK(igraph_vector_ptr_init(mycomponents, 0)); IGRAPH_FINALLY(igraph_i_free_vectorlist, mycomponents); } for (i=0; i<no_of_nodes; i++) { if (VECTOR(low)[i] != 0) { continue; } /* already visited */ IGRAPH_ALLOW_INTERRUPTION(); IGRAPH_CHECK(igraph_stack_push(&path, i)); counter=1; rootdfs=0; VECTOR(low)[i]=VECTOR(num)[i]=counter++; while (!igraph_stack_empty(&path)) { long int n; long int act=(long int) igraph_stack_top(&path); long int actnext=VECTOR(nextptr)[act]; adjedges=igraph_inclist_get(&inclist, act); n=igraph_vector_int_size(adjedges); if (actnext < n) { /* Step down (maybe) */ long int edge=(long int) VECTOR(*adjedges)[actnext]; long int nei=IGRAPH_OTHER(graph, edge, act); if (VECTOR(low)[nei] == 0) { if (act==i) { rootdfs++; } IGRAPH_CHECK(igraph_vector_push_back(&edgestack, edge)); IGRAPH_CHECK(igraph_stack_push(&path, nei)); VECTOR(low)[nei] = VECTOR(num)[nei]=counter++; } else { /* Update low value if needed */ if (VECTOR(num)[nei] < VECTOR(low)[act]) { VECTOR(low)[act]=VECTOR(num)[nei]; } } VECTOR(nextptr)[act] += 1; } else { /* Step up */ igraph_stack_pop(&path); if (!igraph_stack_empty(&path)) { long int prev=(long int) igraph_stack_top(&path); /* Update LOW value if needed */ if (VECTOR(low)[act] < VECTOR(low)[prev]) { VECTOR(low)[prev] = VECTOR(low)[act]; } /* Check for articulation point */ if (VECTOR(low)[act] >= VECTOR(num)[prev]) { if (articulation_points && !VECTOR(found)[prev] && prev != i /* the root */) { IGRAPH_CHECK(igraph_vector_push_back(articulation_points, prev)); VECTOR(found)[prev] = 1; } if (no) { *no += 1; } /*------------------------------------*/ /* Record the biconnected component just found */ if (tree_edges || mycomponents) { igraph_vector_t *v = 0, *v2 = 0; comps++; if (tree_edges) { v=igraph_Calloc(1, igraph_vector_t); if (!v) { IGRAPH_ERROR("Out of memory", IGRAPH_ENOMEM); } IGRAPH_CHECK(igraph_vector_init(v, 0)); IGRAPH_FINALLY(igraph_vector_destroy, v); } if (mycomponents) { v2=igraph_Calloc(1, igraph_vector_t); if (!v2) { IGRAPH_ERROR("Out of memory", IGRAPH_ENOMEM); } IGRAPH_CHECK(igraph_vector_init(v2, 0)); IGRAPH_FINALLY(igraph_vector_destroy, v2); } while (!igraph_vector_empty(&edgestack)) { long int e=(long int) igraph_vector_pop_back(&edgestack); long int from=IGRAPH_FROM(graph,e); long int to=IGRAPH_TO(graph,e); if (tree_edges) { IGRAPH_CHECK(igraph_vector_push_back(v, e)); } if (mycomponents) { if (VECTOR(vertex_added)[from] != comps) { VECTOR(vertex_added)[from] = comps; IGRAPH_CHECK(igraph_vector_push_back(v2, from)); } if (VECTOR(vertex_added)[to] != comps) { VECTOR(vertex_added)[to] = comps; IGRAPH_CHECK(igraph_vector_push_back(v2, to)); } } if (from==prev || to==prev) { break; } } if (mycomponents) { IGRAPH_CHECK(igraph_vector_ptr_push_back(mycomponents, v2)); IGRAPH_FINALLY_CLEAN(1); } if (tree_edges) { IGRAPH_CHECK(igraph_vector_ptr_push_back(tree_edges, v)); IGRAPH_FINALLY_CLEAN(1); } if (component_edges) { igraph_vector_t *nodes=VECTOR(*mycomponents)[comps-1]; igraph_vector_t *vv=igraph_Calloc(1, igraph_vector_t); long int ii, no_vert=igraph_vector_size(nodes); if (!vv) { IGRAPH_ERROR("Out of memory", IGRAPH_ENOMEM); } IGRAPH_CHECK(igraph_vector_init(vv, 0)); IGRAPH_FINALLY(igraph_vector_destroy, vv); for (ii=0; ii<no_vert; ii++) { long int vert=(long int) VECTOR(*nodes)[ii]; igraph_vector_int_t *edges=igraph_inclist_get(&inclist, vert); long int j, nn=igraph_vector_int_size(edges); for (j=0; j<nn; j++) { long int e=(long int) VECTOR(*edges)[j]; long int nei=IGRAPH_OTHER(graph, e, vert); if (VECTOR(vertex_added)[nei] == comps && nei<vert) { IGRAPH_CHECK(igraph_vector_push_back(vv, e)); } } } IGRAPH_CHECK(igraph_vector_ptr_push_back(component_edges, vv)); IGRAPH_FINALLY_CLEAN(1); } } /* record component if requested */ /*------------------------------------*/ } } /* !igraph_stack_empty(&path) */ } } /* !igraph_stack_empty(&path) */ if (articulation_points && rootdfs >= 2) { IGRAPH_CHECK(igraph_vector_push_back(articulation_points, i)); } } /* i < no_of_nodes */ if (mycomponents != components) { igraph_i_free_vectorlist(mycomponents); IGRAPH_FINALLY_CLEAN(1); } igraph_vector_long_destroy(&vertex_added); igraph_inclist_destroy(&inclist); igraph_vector_destroy(&edgestack); igraph_stack_destroy(&path); igraph_vector_bool_destroy(&found); igraph_vector_long_destroy(&low); igraph_vector_long_destroy(&num); igraph_vector_long_destroy(&nextptr); IGRAPH_FINALLY_CLEAN(8); return 0; }
int igraph_forest_fire_game(igraph_t *graph, igraph_integer_t nodes, igraph_real_t fw_prob, igraph_real_t bw_factor, igraph_integer_t pambs, igraph_bool_t directed) { igraph_vector_long_t visited; long int no_of_nodes=nodes, actnode, i; igraph_vector_t edges; igraph_vector_t *inneis, *outneis; igraph_i_forest_fire_data_t data; igraph_dqueue_t neiq; long int ambs=pambs; igraph_real_t param_geom_out=1-fw_prob; igraph_real_t param_geom_in=1-fw_prob*bw_factor; if (fw_prob < 0) { IGRAPH_ERROR("Forest fire model: 'fw_prob' should be between non-negative", IGRAPH_EINVAL); } if (bw_factor < 0) { IGRAPH_ERROR("Forest fire model: 'bw_factor' should be non-negative", IGRAPH_EINVAL); } if (ambs < 0) { IGRAPH_ERROR("Number of ambassadors ('ambs') should be non-negative", IGRAPH_EINVAL); } if (fw_prob == 0 || ambs == 0) { IGRAPH_WARNING("'fw_prob or ambs is zero, creating empty graph"); IGRAPH_CHECK(igraph_empty(graph, nodes, directed)); return 0; } IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); inneis=igraph_Calloc(no_of_nodes, igraph_vector_t); if (!inneis) { IGRAPH_ERROR("Cannot run forest fire model", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, inneis); outneis=igraph_Calloc(no_of_nodes, igraph_vector_t); if (!outneis) { IGRAPH_ERROR("Cannot run forest fire model", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, outneis); data.inneis=inneis; data.outneis=outneis; data.no_of_nodes=no_of_nodes; IGRAPH_FINALLY(igraph_i_forest_fire_free, &data); for (i=0; i<no_of_nodes; i++) { IGRAPH_CHECK(igraph_vector_init(inneis+i, 0)); IGRAPH_CHECK(igraph_vector_init(outneis+i, 0)); } IGRAPH_CHECK(igraph_vector_long_init(&visited, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &visited); IGRAPH_DQUEUE_INIT_FINALLY(&neiq, 10); RNG_BEGIN(); #define ADD_EDGE_TO(nei) \ if (VECTOR(visited)[(nei)] != actnode+1) { \ VECTOR(visited)[(nei)] = actnode+1; \ IGRAPH_CHECK(igraph_dqueue_push(&neiq, nei)); \ IGRAPH_CHECK(igraph_vector_push_back(&edges, actnode)); \ IGRAPH_CHECK(igraph_vector_push_back(&edges, nei)); \ IGRAPH_CHECK(igraph_vector_push_back(outneis+actnode, nei)); \ IGRAPH_CHECK(igraph_vector_push_back(inneis+nei, actnode)); \ } IGRAPH_PROGRESS("Forest fire: ", 0.0, NULL); for (actnode=1; actnode < no_of_nodes; actnode++) { IGRAPH_PROGRESS("Forest fire: ", 100.0*actnode/no_of_nodes, NULL); IGRAPH_ALLOW_INTERRUPTION(); /* We don't want to visit the current vertex */ VECTOR(visited)[actnode] = actnode+1; /* Choose ambassador(s) */ for (i=0; i<ambs; i++) { long int a=RNG_INTEGER(0, actnode-1); ADD_EDGE_TO(a); } while (!igraph_dqueue_empty(&neiq)) { long int actamb=(long int) igraph_dqueue_pop(&neiq); igraph_vector_t *outv=outneis+actamb; igraph_vector_t *inv=inneis+actamb; long int no_in=igraph_vector_size(inv); long int no_out=igraph_vector_size(outv); long int neis_out=(long int) RNG_GEOM(param_geom_out); long int neis_in=(long int) RNG_GEOM(param_geom_in); /* outgoing neighbors */ if (neis_out >= no_out) { for (i=0; i<no_out; i++) { long int nei=(long int) VECTOR(*outv)[i]; ADD_EDGE_TO(nei); } } else { long int oleft=no_out; for (i=0; i<neis_out && oleft > 0; ) { long int which=RNG_INTEGER(0, oleft-1); long int nei=(long int) VECTOR(*outv)[which]; VECTOR(*outv)[which] = VECTOR(*outv)[oleft-1]; VECTOR(*outv)[oleft-1] = nei; if (VECTOR(visited)[nei] != actnode+1) { ADD_EDGE_TO(nei); i++; } oleft--; } } /* incoming neighbors */ if (neis_in >= no_in) { for (i=0; i<no_in; i++) { long int nei=(long int) VECTOR(*inv)[i]; ADD_EDGE_TO(nei); } } else { long int ileft=no_in; for (i=0; i<neis_in && ileft > 0; ) { long int which=RNG_INTEGER(0, ileft-1); long int nei=(long int) VECTOR(*inv)[which]; VECTOR(*inv)[which] = VECTOR(*inv)[ileft-1]; VECTOR(*inv)[ileft-1] = nei; if (VECTOR(visited)[nei] != actnode+1) { ADD_EDGE_TO(nei); i++; } ileft--; } } } /* while neiq not empty */ } /* actnode < no_of_nodes */ #undef ADD_EDGE_TO RNG_END(); IGRAPH_PROGRESS("Forest fire: ", 100.0, NULL); igraph_dqueue_destroy(&neiq); igraph_vector_long_destroy(&visited); igraph_i_forest_fire_free(&data); igraph_free(outneis); igraph_free(inneis); IGRAPH_FINALLY_CLEAN(5); IGRAPH_CHECK(igraph_create(graph, &edges, nodes, directed)); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); return 0; }
int igraph_union_many(igraph_t *res, const igraph_vector_ptr_t *graphs, igraph_vector_ptr_t *edgemaps) { long int no_of_graphs=igraph_vector_ptr_size(graphs); long int no_of_nodes=0; igraph_bool_t directed=1; igraph_vector_t edges; igraph_vector_ptr_t edge_vects, order_vects; igraph_vector_long_t no_edges; long int i, j, tailfrom= no_of_graphs > 0 ? 0 : -1, tailto=-1; long int idx=0; /* Check directedness */ if (no_of_graphs != 0) { directed=igraph_is_directed(VECTOR(*graphs)[0]); no_of_nodes=igraph_vcount(VECTOR(*graphs)[0]); } for (i=1; i<no_of_graphs; i++) { if (directed != igraph_is_directed(VECTOR(*graphs)[i])) { IGRAPH_ERROR("Cannot union directed and undirected graphs", IGRAPH_EINVAL); } } if (edgemaps) { IGRAPH_CHECK(igraph_vector_ptr_resize(edgemaps, no_of_graphs)); igraph_vector_ptr_null(edgemaps); IGRAPH_FINALLY(igraph_i_union_many_free3, edgemaps); } IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); IGRAPH_CHECK(igraph_vector_long_init(&no_edges, no_of_graphs)); IGRAPH_FINALLY(igraph_vector_long_destroy, &no_edges); /* Calculate number of nodes, query number of edges */ for (i=0; i<no_of_graphs; i++) { long int n=igraph_vcount(VECTOR(*graphs)[i]); if (n > no_of_nodes) { no_of_nodes=n; } VECTOR(no_edges)[i] = igraph_ecount(VECTOR(*graphs)[i]); } if (edgemaps) { for (i=0; i<no_of_graphs; i++) { VECTOR(*edgemaps)[i]=igraph_Calloc(1, igraph_vector_t); if (!VECTOR(*edgemaps)[i]) { IGRAPH_ERROR("Cannot union graphs", IGRAPH_ENOMEM); } IGRAPH_CHECK(igraph_vector_init(VECTOR(*edgemaps)[i], VECTOR(no_edges)[i])); } } /* Allocate memory for the edge lists and their index vectors */ if (no_of_graphs != 0) { IGRAPH_CHECK(igraph_vector_ptr_init(&edge_vects, no_of_graphs)); IGRAPH_FINALLY(igraph_i_union_many_free, &edge_vects); IGRAPH_CHECK(igraph_vector_ptr_init(&order_vects, no_of_graphs)); IGRAPH_FINALLY(igraph_i_union_many_free2, &order_vects); } for (i=0; i<no_of_graphs; i++) { VECTOR(edge_vects)[i]=igraph_Calloc(1, igraph_vector_t); VECTOR(order_vects)[i]=igraph_Calloc(1, igraph_vector_long_t); if (! VECTOR(edge_vects)[i] || ! VECTOR(order_vects)[i]) { IGRAPH_ERROR("Cannot union graphs", IGRAPH_ENOMEM); } IGRAPH_CHECK(igraph_vector_init(VECTOR(edge_vects)[i], 2 * VECTOR(no_edges)[i])); IGRAPH_CHECK(igraph_vector_long_init(VECTOR(order_vects)[i], VECTOR(no_edges)[i])); } /* Query and sort the edge lists */ for (i=0; i<no_of_graphs; i++) { long int k, j, n=VECTOR(no_edges)[i]; igraph_vector_t *edges=VECTOR(edge_vects)[i]; igraph_vector_long_t *order=VECTOR(order_vects)[i]; IGRAPH_CHECK(igraph_get_edgelist(VECTOR(*graphs)[i], edges, /*bycol=*/0)); if (!directed) { for (k=0, j=0; k<n; k++, j+=2) { if (VECTOR(*edges)[j] > VECTOR(*edges)[j+1]) { long int tmp=VECTOR(*edges)[j]; VECTOR(*edges)[j]=VECTOR(*edges)[j+1]; VECTOR(*edges)[j+1]=tmp; } } } for (k=0; k<n; k++) { VECTOR(*order)[k]=k; } igraph_qsort_r(VECTOR(*order), n, sizeof(VECTOR(*order)[0]), edges, igraph_i_order_edgelist_cmp); } while (tailfrom >= 0) { /* Get the largest tail element */ tailfrom = tailto = -1; for (j=0; j<no_of_graphs; j++) { if (!igraph_vector_long_empty(VECTOR(order_vects)[j])) { long int edge=igraph_vector_long_tail(VECTOR(order_vects)[j]); igraph_vector_t *ev=VECTOR(edge_vects)[j]; long int from=VECTOR(*ev)[2*edge]; long int to=VECTOR(*ev)[2*edge+1]; if (from > tailfrom || (from == tailfrom && to > tailto)) { tailfrom = from; tailto = to; } } } if (tailfrom < 0) { continue; } /* add the edge */ IGRAPH_CHECK(igraph_vector_push_back(&edges, tailfrom)); IGRAPH_CHECK(igraph_vector_push_back(&edges, tailto)); /* update edge lists, we just modify the 'order' vectors */ for (j=0; j<no_of_graphs; j++) { if (!igraph_vector_long_empty(VECTOR(order_vects)[j])) { long int edge=igraph_vector_long_tail(VECTOR(order_vects)[j]); igraph_vector_t *ev=VECTOR(edge_vects)[j]; long int from=VECTOR(*ev)[2*edge]; long int to=VECTOR(*ev)[2*edge+1]; if (from == tailfrom && to == tailto) { igraph_vector_long_pop_back(VECTOR(order_vects)[j]); if (edgemaps) { igraph_vector_t *map=VECTOR(*edgemaps)[j]; VECTOR(*map)[edge]=idx; } } } } idx++; } if (no_of_graphs > 0) { igraph_i_union_many_free2(&order_vects); igraph_i_union_many_free(&edge_vects); IGRAPH_FINALLY_CLEAN(2); } igraph_vector_long_destroy(&no_edges); IGRAPH_FINALLY_CLEAN(1); IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) no_of_nodes, directed)); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); if (edgemaps) { IGRAPH_FINALLY_CLEAN(1); } return 0; }
int igraph_biconnected_components(const igraph_t *graph, igraph_integer_t *no, igraph_vector_ptr_t *components, igraph_vector_t *articulation_points) { long int no_of_nodes=igraph_vcount(graph); igraph_vector_long_t nextptr; igraph_vector_long_t num, low; igraph_vector_bool_t found; igraph_vector_t *adjedges; igraph_stack_t path; igraph_vector_t edgestack; igraph_adjedgelist_t adjedgelist; long int i, counter, rootdfs=0; IGRAPH_CHECK(igraph_vector_long_init(&nextptr, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &nextptr); IGRAPH_CHECK(igraph_vector_long_init(&num, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &num); IGRAPH_CHECK(igraph_vector_long_init(&low, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &low); IGRAPH_CHECK(igraph_vector_bool_init(&found, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_bool_destroy, &found); IGRAPH_CHECK(igraph_stack_init(&path, 100)); IGRAPH_FINALLY(igraph_stack_destroy, &path); IGRAPH_VECTOR_INIT_FINALLY(&edgestack, 0); IGRAPH_CHECK(igraph_vector_reserve(&edgestack, 100)); IGRAPH_CHECK(igraph_adjedgelist_init(graph, &adjedgelist, IGRAPH_ALL)); IGRAPH_FINALLY(igraph_adjedgelist_destroy, &adjedgelist); if (no) { *no=0; } if (components) { igraph_vector_ptr_clear(components); } if (articulation_points) { igraph_vector_clear(articulation_points); } for (i=0; i<no_of_nodes; i++) { if (VECTOR(low)[i] != 0) { continue; /* already visited */ } IGRAPH_ALLOW_INTERRUPTION(); IGRAPH_CHECK(igraph_stack_push(&path, i)); counter=1; rootdfs=0; VECTOR(low)[i]=VECTOR(num)[i]=counter++; while (!igraph_stack_empty(&path)) { long int n; long int act=igraph_stack_top(&path); long int actnext=VECTOR(nextptr)[act]; adjedges=igraph_adjedgelist_get(&adjedgelist, act); n=igraph_vector_size(adjedges); if (actnext < n) { /* Step down (maybe) */ long int edge=VECTOR(*adjedges)[actnext]; long int nei=IGRAPH_OTHER(graph, edge, act); if (VECTOR(low)[nei] == 0) { if (act==i) { rootdfs++; } IGRAPH_CHECK(igraph_vector_push_back(&edgestack, edge)); IGRAPH_CHECK(igraph_stack_push(&path, nei)); VECTOR(low)[nei] = VECTOR(num)[nei]=counter++; } else { /* Update low value if needed */ if (VECTOR(num)[nei] < VECTOR(low)[act]) { VECTOR(low)[act]=VECTOR(num)[nei]; } } VECTOR(nextptr)[act] += 1; } else { /* Step up */ igraph_stack_pop(&path); if (!igraph_stack_empty(&path)) { long int prev=igraph_stack_top(&path); /* Update LOW value if needed */ if (VECTOR(low)[act] < VECTOR(low)[prev]) { VECTOR(low)[prev] = VECTOR(low)[act]; } /* Check for articulation point */ if (VECTOR(low)[act] >= VECTOR(num)[prev]) { if (articulation_points && !VECTOR(found)[prev] && prev != i /* the root */) { IGRAPH_CHECK(igraph_vector_push_back(articulation_points, prev)); VECTOR(found)[prev] = 1; } if (no) { *no += 1; } if (components) { igraph_vector_t *v=igraph_Calloc(1, igraph_vector_t); IGRAPH_CHECK(igraph_vector_init(v, 0)); while (!igraph_vector_empty(&edgestack)) { long int e=igraph_vector_pop_back(&edgestack); IGRAPH_CHECK(igraph_vector_push_back(v, e)); if (IGRAPH_FROM(graph,e)==prev || IGRAPH_TO(graph,e)==prev) { break; } } IGRAPH_CHECK(igraph_vector_ptr_push_back(components, v)); } } } /* !igraph_stack_empty(&path) */ } } /* !igraph_stack_empty(&path) */ if (articulation_points && rootdfs >= 2) { IGRAPH_CHECK(igraph_vector_push_back(articulation_points, i)); } } /* i < no_of_nodes */ igraph_adjedgelist_destroy(&adjedgelist); igraph_vector_destroy(&edgestack); igraph_stack_destroy(&path); igraph_vector_bool_destroy(&found); igraph_vector_long_destroy(&low); igraph_vector_long_destroy(&num); igraph_vector_long_destroy(&nextptr); IGRAPH_FINALLY_CLEAN(7); return 0; }
/** * Given a graph, a community structure and a vertex ID, this method * calculates: * * - edges: the list of edge IDs that are incident on the vertex * - weight_all: the total weight of these edges * - weight_inside: the total weight of edges that stay within the same * community where the given vertex is right now, excluding loop edges * - weight_loop: the total weight of loop edges * - links_community and links_weight: together these two vectors list the * communities incident on this vertex and the total weight of edges * pointing to these communities */ int igraph_i_multilevel_community_links(const igraph_t *graph, const igraph_i_multilevel_community_list *communities, igraph_integer_t vertex, igraph_vector_t *edges, igraph_real_t *weight_all, igraph_real_t *weight_inside, igraph_real_t *weight_loop, igraph_vector_t *links_community, igraph_vector_t *links_weight) { long int i, n, last = -1, c = -1; igraph_real_t weight = 1; long int to, to_community; long int community = (long int) VECTOR(*(communities->membership))[(long int)vertex]; igraph_i_multilevel_community_link *links; *weight_all = *weight_inside = *weight_loop = 0; igraph_vector_clear(links_community); igraph_vector_clear(links_weight); /* Get the list of incident edges */ igraph_incident(graph, edges, vertex, IGRAPH_ALL); n = igraph_vector_size(edges); links = igraph_Calloc(n, igraph_i_multilevel_community_link); if (links == 0) { IGRAPH_ERROR("multi-level community structure detection failed", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, links); for (i = 0; i < n; i++) { long int eidx = (long int) VECTOR(*edges)[i]; weight = VECTOR(*communities->weights)[eidx]; to = IGRAPH_OTHER(graph, eidx, vertex); *weight_all += weight; if (to == vertex) { *weight_loop += weight; links[i].community = community; links[i].weight = 0; continue; } to_community = (long int)VECTOR(*(communities->membership))[to]; if (community == to_community) *weight_inside += weight; /* debug("Link %ld (C: %ld) <-> %ld (C: %ld)\n", vertex, community, to, to_community); */ links[i].community = to_community; links[i].weight = weight; } /* Sort links by community ID and merge the same */ qsort((void*)links, (size_t) n, sizeof(igraph_i_multilevel_community_link), igraph_i_multilevel_community_link_cmp); for (i = 0; i < n; i++) { to_community = links[i].community; if (to_community != last) { igraph_vector_push_back(links_community, to_community); igraph_vector_push_back(links_weight, links[i].weight); last = to_community; c++; } else { VECTOR(*links_weight)[c] += links[i].weight; } } igraph_free(links); IGRAPH_FINALLY_CLEAN(1); return 0; }
int igraph_i_maximal_cliques(const igraph_t *graph, igraph_i_maximal_clique_func_t func, void* data) { int directed=igraph_is_directed(graph); long int i, j, k, l; igraph_integer_t no_of_nodes, nodes_to_check, nodes_done; igraph_integer_t best_cand = 0, best_cand_degree = 0, best_fini_cand_degree; igraph_adjlist_t adj_list; igraph_stack_ptr_t stack; igraph_i_maximal_cliques_stack_frame frame, *new_frame_ptr; igraph_vector_t clique, new_cand, new_fini, cn, best_cand_nbrs, best_fini_cand_nbrs; igraph_bool_t cont = 1; int assret; if (directed) IGRAPH_WARNING("directionality of edges is ignored for directed graphs"); no_of_nodes = igraph_vcount(graph); if (no_of_nodes == 0) return IGRAPH_SUCCESS; /* Construct an adjacency list representation */ IGRAPH_CHECK(igraph_adjlist_init(graph, &adj_list, IGRAPH_ALL)); IGRAPH_FINALLY(igraph_adjlist_destroy, &adj_list); IGRAPH_CHECK(igraph_adjlist_simplify(&adj_list)); igraph_adjlist_sort(&adj_list); /* Initialize stack */ IGRAPH_CHECK(igraph_stack_ptr_init(&stack, 0)); IGRAPH_FINALLY(igraph_i_maximal_cliques_stack_destroy, &stack); /* Create the initial (empty) clique */ IGRAPH_VECTOR_INIT_FINALLY(&clique, 0); /* Initialize new_cand, new_fini, cn, best_cand_nbrs and best_fini_cand_nbrs (will be used later) */ IGRAPH_VECTOR_INIT_FINALLY(&new_cand, 0); IGRAPH_VECTOR_INIT_FINALLY(&new_fini, 0); IGRAPH_VECTOR_INIT_FINALLY(&cn, 0); IGRAPH_VECTOR_INIT_FINALLY(&best_cand_nbrs, 0); IGRAPH_VECTOR_INIT_FINALLY(&best_fini_cand_nbrs, 0); /* Find the vertex with the highest degree */ best_cand = 0; best_cand_degree = igraph_vector_size(igraph_adjlist_get(&adj_list, 0)); for (i = 1; i < no_of_nodes; i++) { j = igraph_vector_size(igraph_adjlist_get(&adj_list, i)); if (j > best_cand_degree) { best_cand = i; best_cand_degree = j; } } /* Create the initial stack frame */ IGRAPH_CHECK(igraph_vector_init_seq(&frame.cand, 0, no_of_nodes-1)); IGRAPH_FINALLY(igraph_vector_destroy, &frame.cand); IGRAPH_CHECK(igraph_vector_init(&frame.fini, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &frame.fini); IGRAPH_CHECK(igraph_vector_init(&frame.cand_filtered, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &frame.cand_filtered); IGRAPH_CHECK(igraph_vector_difference_sorted(&frame.cand, igraph_adjlist_get(&adj_list, best_cand), &frame.cand_filtered)); IGRAPH_FINALLY_CLEAN(3); IGRAPH_FINALLY(igraph_i_maximal_cliques_stack_frame_destroy, &frame); /* TODO: frame.cand and frame.fini should be a set instead of a vector */ /* Main loop starts here */ nodes_to_check = igraph_vector_size(&frame.cand_filtered); nodes_done = 0; while (!igraph_vector_empty(&frame.cand_filtered) || !igraph_stack_ptr_empty(&stack)) { if (igraph_vector_empty(&frame.cand_filtered)) { /* No candidates left to check in this stack frame, pop out the previous stack frame */ igraph_i_maximal_cliques_stack_frame *newframe = igraph_stack_ptr_pop(&stack); igraph_i_maximal_cliques_stack_frame_destroy(&frame); frame = *newframe; free(newframe); if (igraph_stack_ptr_size(&stack) == 1) { /* We will be using the next candidate node in the next iteration, so we can increase * nodes_done by 1 */ nodes_done++; } /* For efficiency reasons, we only check for interruption and show progress here */ IGRAPH_PROGRESS("Maximal cliques: ", 100.0 * nodes_done / nodes_to_check, NULL); IGRAPH_ALLOW_INTERRUPTION(); igraph_vector_pop_back(&clique); continue; } /* Try the next node in the clique */ i = igraph_vector_pop_back(&frame.cand_filtered); IGRAPH_CHECK(igraph_vector_push_back(&clique, i)); /* Remove the node from the candidate list */ assret=igraph_vector_binsearch(&frame.cand, i, &j); assert(assret); igraph_vector_remove(&frame.cand, j); /* Add the node to the finished list */ assret = !igraph_vector_binsearch(&frame.fini, i, &j); assert(assret); IGRAPH_CHECK(igraph_vector_insert(&frame.fini, j, i)); /* Create new_cand and new_fini */ IGRAPH_CHECK(igraph_vector_intersect_sorted(&frame.cand, igraph_adjlist_get(&adj_list, i), &new_cand)); IGRAPH_CHECK(igraph_vector_intersect_sorted(&frame.fini, igraph_adjlist_get(&adj_list, i), &new_fini)); /* Do we have anything more to search? */ if (igraph_vector_empty(&new_cand)) { if (igraph_vector_empty(&new_fini)) { /* We have a maximal clique here */ IGRAPH_CHECK(func(&clique, data, &cont)); if (!cont) { /* The callback function requested to stop the search */ break; } } igraph_vector_pop_back(&clique); continue; } if (igraph_vector_empty(&new_fini) && igraph_vector_size(&new_cand) == 1) { /* Shortcut: only one node left */ IGRAPH_CHECK(igraph_vector_push_back(&clique, VECTOR(new_cand)[0])); IGRAPH_CHECK(func(&clique, data, &cont)); if (!cont) { /* The callback function requested to stop the search */ break; } igraph_vector_pop_back(&clique); igraph_vector_pop_back(&clique); continue; } /* Find the next best candidate node in new_fini */ l = igraph_vector_size(&new_cand); best_cand_degree = -1; j = igraph_vector_size(&new_fini); for (i = 0; i < j; i++) { k = (long int)VECTOR(new_fini)[i]; IGRAPH_CHECK(igraph_vector_intersect_sorted(&new_cand, igraph_adjlist_get(&adj_list, k), &cn)); if (igraph_vector_size(&cn) > best_cand_degree) { best_cand_degree = igraph_vector_size(&cn); IGRAPH_CHECK(igraph_vector_update(&best_fini_cand_nbrs, &cn)); if (best_cand_degree == l) { /* Cool, we surely have the best candidate node here as best_cand_degree can't get any better */ break; } } } /* Shortcut here: we don't have to examine new_cand */ if (best_cand_degree == l) { igraph_vector_pop_back(&clique); continue; } /* Still finding best candidate node */ best_fini_cand_degree = best_cand_degree; best_cand_degree = -1; j = igraph_vector_size(&new_cand); l = l - 1; for (i = 0; i < j; i++) { k = (long int)VECTOR(new_cand)[i]; IGRAPH_CHECK(igraph_vector_intersect_sorted(&new_cand, igraph_adjlist_get(&adj_list, k), &cn)); if (igraph_vector_size(&cn) > best_cand_degree) { best_cand_degree = igraph_vector_size(&cn); IGRAPH_CHECK(igraph_vector_update(&best_cand_nbrs, &cn)); if (best_cand_degree == l) { /* Cool, we surely have the best candidate node here as best_cand_degree can't get any better */ break; } } } /* Create a new stack frame in case we back out later */ new_frame_ptr = igraph_Calloc(1, igraph_i_maximal_cliques_stack_frame); if (new_frame_ptr == 0) { IGRAPH_ERROR("cannot allocate new stack frame", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, new_frame_ptr); *new_frame_ptr = frame; memset(&frame, 0, sizeof(frame)); IGRAPH_CHECK(igraph_stack_ptr_push(&stack, new_frame_ptr)); IGRAPH_FINALLY_CLEAN(1); /* ownership of new_frame_ptr taken by the stack */ /* Ownership of the current frame and its vectors (frame.cand, frame.done, frame.cand_filtered) * is taken by the stack from now on. Vectors in frame must be re-initialized with new_cand, * new_fini and stuff. The old frame.cand and frame.fini won't be leaked because they are * managed by the stack now. */ frame.cand = new_cand; frame.fini = new_fini; IGRAPH_CHECK(igraph_vector_init(&new_cand, 0)); IGRAPH_CHECK(igraph_vector_init(&new_fini, 0)); IGRAPH_CHECK(igraph_vector_init(&frame.cand_filtered, 0)); /* Adjust frame.cand_filtered */ if (best_cand_degree < best_fini_cand_degree) { IGRAPH_CHECK(igraph_vector_difference_sorted(&frame.cand, &best_fini_cand_nbrs, &frame.cand_filtered)); } else { IGRAPH_CHECK(igraph_vector_difference_sorted(&frame.cand, &best_cand_nbrs, &frame.cand_filtered)); } } IGRAPH_PROGRESS("Maximal cliques: ", 100.0, NULL); igraph_adjlist_destroy(&adj_list); igraph_vector_destroy(&clique); igraph_vector_destroy(&new_cand); igraph_vector_destroy(&new_fini); igraph_vector_destroy(&cn); igraph_vector_destroy(&best_cand_nbrs); igraph_vector_destroy(&best_fini_cand_nbrs); igraph_i_maximal_cliques_stack_frame_destroy(&frame); igraph_i_maximal_cliques_stack_destroy(&stack); IGRAPH_FINALLY_CLEAN(9); return IGRAPH_SUCCESS; }
/** * \ingroup communities * \function igraph_i_community_multilevel_step * \brief Performs a single step of the multi-level modularity optimization method * * This function implements a single step of the multi-level modularity optimization * algorithm for finding community structure, see VD Blondel, J-L Guillaume, * R Lambiotte and E Lefebvre: Fast unfolding of community hierarchies in large * networks, http://arxiv.org/abs/0803.0476 for the details. * * This function was contributed by Tom Gregorovic. * * \param graph The input graph. It must be an undirected graph. * \param weights Numeric vector containing edge weights. If \c NULL, every edge * has equal weight. The weights are expected to be non-negative. * \param membership The membership vector, the result is returned here. * For each vertex it gives the ID of its community. * \param modularity The modularity of the partition is returned here. * \c NULL means that the modularity is not needed. * \return Error code. * * Time complexity: in average near linear on sparse graphs. */ int igraph_i_community_multilevel_step(igraph_t *graph, igraph_vector_t *weights, igraph_vector_t *membership, igraph_real_t *modularity) { long int i, j; long int vcount = igraph_vcount(graph); long int ecount = igraph_ecount(graph); igraph_integer_t ffrom, fto; igraph_real_t q, pass_q; int pass; igraph_bool_t changed = 0; igraph_vector_t links_community; igraph_vector_t links_weight; igraph_vector_t edges; igraph_vector_t temp_membership; igraph_i_multilevel_community_list communities; /* Initial sanity checks on the input parameters */ if (igraph_is_directed(graph)) { IGRAPH_ERROR("multi-level community detection works for undirected graphs only", IGRAPH_UNIMPLEMENTED); } if (igraph_vector_size(weights) < igraph_ecount(graph)) IGRAPH_ERROR("multi-level community detection: weight vector too short", IGRAPH_EINVAL); if (igraph_vector_any_smaller(weights, 0)) IGRAPH_ERROR("weights must be positive", IGRAPH_EINVAL); /* Initialize data structures */ IGRAPH_VECTOR_INIT_FINALLY(&links_community, 0); IGRAPH_VECTOR_INIT_FINALLY(&links_weight, 0); IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); IGRAPH_VECTOR_INIT_FINALLY(&temp_membership, vcount); IGRAPH_CHECK(igraph_vector_resize(membership, vcount)); /* Initialize list of communities from graph vertices */ communities.vertices_no = vcount; communities.communities_no = vcount; communities.weights = weights; communities.weight_sum = 2 * igraph_vector_sum(weights); communities.membership = membership; communities.item = igraph_Calloc(vcount, igraph_i_multilevel_community); if (communities.item == 0) { IGRAPH_ERROR("multi-level community structure detection failed", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, communities.item); /* Still initializing the communities data structure */ for (i=0; i < vcount; i++) { VECTOR(*communities.membership)[i] = i; communities.item[i].size = 1; communities.item[i].weight_inside = 0; communities.item[i].weight_all = 0; } /* Some more initialization :) */ for (i = 0; i < ecount; i++) { igraph_real_t weight = 1; igraph_edge(graph, (igraph_integer_t) i, &ffrom, &fto); weight = VECTOR(*weights)[i]; communities.item[(long int) ffrom].weight_all += weight; communities.item[(long int) fto].weight_all += weight; if (ffrom == fto) communities.item[(long int) ffrom].weight_inside += 2*weight; } q = igraph_i_multilevel_community_modularity(&communities); pass = 1; do { /* Pass begin */ long int temp_communities_no = communities.communities_no; pass_q = q; changed = 0; /* Save the current membership, it will be restored in case of worse result */ IGRAPH_CHECK(igraph_vector_update(&temp_membership, communities.membership)); for (i = 0; i < vcount; i++) { /* Exclude vertex from its current community */ igraph_real_t weight_all = 0; igraph_real_t weight_inside = 0; igraph_real_t weight_loop = 0; igraph_real_t max_q_gain = 0; igraph_real_t max_weight; long int old_id, new_id, n; igraph_i_multilevel_community_links(graph, &communities, (igraph_integer_t) i, &edges, &weight_all, &weight_inside, &weight_loop, &links_community, &links_weight); old_id = (long int)VECTOR(*(communities.membership))[i]; new_id = old_id; /* Update old community */ igraph_vector_set(communities.membership, i, -1); communities.item[old_id].size--; if (communities.item[old_id].size == 0) {communities.communities_no--;} communities.item[old_id].weight_all -= weight_all; communities.item[old_id].weight_inside -= 2*weight_inside + weight_loop; /* debug("Remove %ld all: %lf Inside: %lf\n", i, -weight_all, -2*weight_inside + weight_loop); */ /* Find new community to join with the best modification gain */ max_q_gain = 0; max_weight = weight_inside; n = igraph_vector_size(&links_community); igraph_vector_sort(&links_community); for (j = 0; j < n; j++) { long int c = (long int) VECTOR(links_community)[j]; igraph_real_t w = VECTOR(links_weight)[j]; igraph_real_t q_gain = igraph_i_multilevel_community_modularity_gain(&communities, (igraph_integer_t) c, (igraph_integer_t) i, weight_all, w); /* debug("Link %ld -> %ld weight: %lf gain: %lf\n", i, c, (double) w, (double) q_gain); */ if (q_gain > max_q_gain) { new_id = c; max_q_gain = q_gain; max_weight = w; } } /* debug("Added vertex %ld to community %ld (gain %lf).\n", i, new_id, (double) max_q_gain); */ /* Add vertex to "new" community and update it */ igraph_vector_set(communities.membership, i, new_id); if (communities.item[new_id].size == 0) {communities.communities_no++;} communities.item[new_id].size++; communities.item[new_id].weight_all += weight_all; communities.item[new_id].weight_inside += 2*max_weight + weight_loop; if (new_id != old_id) { changed++; } } q = igraph_i_multilevel_community_modularity(&communities); if (changed && (q > pass_q)) { /* debug("Pass %d (changed: %d) Communities: %ld Modularity from %lf to %lf\n", pass, changed, communities.communities_no, (double) pass_q, (double) q); */ pass++; } else { /* No changes or the modularity became worse, restore last membership */ IGRAPH_CHECK(igraph_vector_update(communities.membership, &temp_membership)); communities.communities_no = temp_communities_no; break; } IGRAPH_ALLOW_INTERRUPTION(); } while (changed && (q > pass_q)); /* Pass end */ if (modularity) { *modularity = q; } /* debug("Result Communities: %ld Modularity: %lf\n", communities.communities_no, (double) q); */ IGRAPH_CHECK(igraph_reindex_membership(membership, 0)); /* Shrink the nodes of the graph according to the present community structure * and simplify the resulting graph */ /* TODO: check if we really need to copy temp_membership */ IGRAPH_CHECK(igraph_vector_update(&temp_membership, membership)); IGRAPH_CHECK(igraph_i_multilevel_shrink(graph, &temp_membership)); igraph_vector_destroy(&temp_membership); IGRAPH_FINALLY_CLEAN(1); /* Update edge weights after shrinking and simplification */ /* Here we reuse the edges vector as we don't need the previous contents anymore */ /* TODO: can we use igraph_simplify here? */ IGRAPH_CHECK(igraph_i_multilevel_simplify_multiple(graph, &edges)); /* We reuse the links_weight vector to store the old edge weights */ IGRAPH_CHECK(igraph_vector_update(&links_weight, weights)); igraph_vector_fill(weights, 0); for (i = 0; i < ecount; i++) { VECTOR(*weights)[(long int)VECTOR(edges)[i]] += VECTOR(links_weight)[i]; } igraph_free(communities.item); igraph_vector_destroy(&links_community); igraph_vector_destroy(&links_weight); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(4); return 0; }
/** * \ingroup structural * \function igraph_similarity_jaccard_pairs * \brief Jaccard similarity coefficient for given vertex pairs. * * </para><para> * The Jaccard similarity coefficient of two vertices is the number of common * neighbors divided by the number of vertices that are neighbors of at * least one of the two vertices being considered. This function calculates * the pairwise Jaccard similarities for a list of vertex pairs. * * \param graph The graph object to analyze * \param res Pointer to a vector, the result of the calculation will * be stored here. The number of elements is the same as the number * of pairs in \p pairs. * \param pairs A vector that contains the pairs for which the similarity * will be calculated. Each pair is defined by two consecutive elements, * i.e. the first and second element of the vector specifies the first * pair, the third and fourth element specifies the second pair and so on. * \param mode The type of neighbors to be used for the calculation in * directed graphs. Possible values: * \clist * \cli IGRAPH_OUT * the outgoing edges will be considered for each node. * \cli IGRAPH_IN * the incoming edges will be considered for each node. * \cli IGRAPH_ALL * the directed graph is considered as an undirected one for the * computation. * \endclist * \param loops Whether to include the vertices themselves in the neighbor * sets. * \return Error code: * \clist * \cli IGRAPH_ENOMEM * not enough memory for temporary data. * \cli IGRAPH_EINVVID * invalid vertex id passed. * \cli IGRAPH_EINVMODE * invalid mode argument. * \endclist * * Time complexity: O(nd), n is the number of pairs in the given vector, d is * the (maximum) degree of the vertices in the graph. * * \sa \ref igraph_similarity_jaccard() to calculate the Jaccard similarity * between all pairs of a vertex set, or \ref igraph_similarity_dice() and * \ref igraph_similarity_dice_pairs() for a measure very similar to the * Jaccard coefficient * * \example examples/simple/igraph_similarity.c */ int igraph_similarity_jaccard_pairs(const igraph_t *graph, igraph_vector_t *res, const igraph_vector_t *pairs, igraph_neimode_t mode, igraph_bool_t loops) { igraph_lazy_adjlist_t al; long int i, j, k, u, v; long int len_union, len_intersection; igraph_vector_t *v1, *v2; igraph_bool_t *seen; k = igraph_vector_size(pairs); if (k % 2 != 0) IGRAPH_ERROR("number of elements in `pairs' must be even", IGRAPH_EINVAL); IGRAPH_CHECK(igraph_vector_resize(res, k/2)); IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &al, mode, IGRAPH_SIMPLIFY)); IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &al); if (loops) { /* Add the loop edges */ i = igraph_vcount(graph); seen = igraph_Calloc(i, igraph_bool_t); if (seen == 0) IGRAPH_ERROR("cannot calculate Jaccard similarity", IGRAPH_ENOMEM); IGRAPH_FINALLY(free, seen); for (i = 0; i < k; i++) { j = (long int) VECTOR(*pairs)[i]; if (seen[j]) continue; seen[j] = 1; v1=igraph_lazy_adjlist_get(&al, (igraph_integer_t) j); if (!igraph_vector_binsearch(v1, j, &u)) igraph_vector_insert(v1, u, j); } free(seen); IGRAPH_FINALLY_CLEAN(1); } for (i = 0, j = 0; i < k; i += 2, j++) { u = (long int) VECTOR(*pairs)[i]; v = (long int) VECTOR(*pairs)[i+1]; if (u == v) { VECTOR(*res)[j] = 1.0; continue; } v1 = igraph_lazy_adjlist_get(&al, (igraph_integer_t) u); v2 = igraph_lazy_adjlist_get(&al, (igraph_integer_t) v); igraph_i_neisets_intersect(v1, v2, &len_union, &len_intersection); if (len_union > 0) VECTOR(*res)[j] = ((igraph_real_t)len_intersection) / len_union; else VECTOR(*res)[j] = 0.0; } igraph_lazy_adjlist_destroy(&al); IGRAPH_FINALLY_CLEAN(1); return 0; }
int igraph_cohesive_blocks(const igraph_t *graph, igraph_vector_ptr_t *blocks, igraph_vector_t *cohesion, igraph_vector_t *parent, igraph_t *block_tree) { /* Some implementation comments. Everything is relatively straightforward, except, that we need to follow the vertex ids of the various subgraphs, without having to store two-way mappings at each level. The subgraphs can overlap, this complicates things a bit. The 'Q' vector is used as a double ended queue and it contains the subgraphs to work on in the future. Some other vectors are associated with it. 'Qparent' gives the parent graph of a graph in Q. Qmapping gives the mapping of the vertices from the graph to the parent graph. Qcohesion is the vertex connectivity of the graph. Qptr is an integer and points to the next graph to work on. */ igraph_vector_ptr_t Q; igraph_vector_ptr_t Qmapping; igraph_vector_long_t Qparent; igraph_vector_long_t Qcohesion; igraph_vector_bool_t Qcheck; long int Qptr=0; igraph_integer_t conn; igraph_bool_t is_simple; igraph_t *graph_copy; igraph_vector_ptr_t separators; igraph_vector_t compvertices; igraph_vector_long_t components; igraph_vector_bool_t marked; igraph_vector_long_t compid; igraph_dqueue_t bfsQ; igraph_vector_t neis; if (igraph_is_directed(graph)) { IGRAPH_ERROR("Cohesive blocking only works on undirected graphs", IGRAPH_EINVAL); } IGRAPH_CHECK(igraph_is_simple(graph, &is_simple)); if (!is_simple) { IGRAPH_ERROR("Cohesive blocking only works on simple graphs", IGRAPH_EINVAL); } IGRAPH_STATUS("Starting cohesive block calculation.\n", 0); if (blocks) { igraph_vector_ptr_clear(blocks); } if (cohesion) { igraph_vector_clear(cohesion); } if (parent) { igraph_vector_clear(parent); } IGRAPH_CHECK(igraph_vector_ptr_init(&Q, 1)); IGRAPH_FINALLY(igraph_vector_ptr_destroy, &Q); IGRAPH_FINALLY(igraph_i_cohesive_blocks_free, &Q); IGRAPH_CHECK(igraph_vector_ptr_init(&Qmapping, 1)); IGRAPH_FINALLY(igraph_vector_ptr_destroy, &Qmapping); IGRAPH_FINALLY(igraph_i_cohesive_blocks_free2, &Qmapping); IGRAPH_CHECK(igraph_vector_long_init(&Qparent, 1)); IGRAPH_FINALLY(igraph_vector_long_destroy, &Qparent); IGRAPH_CHECK(igraph_vector_long_init(&Qcohesion, 1)); IGRAPH_FINALLY(igraph_vector_long_destroy, &Qcohesion); IGRAPH_CHECK(igraph_vector_bool_init(&Qcheck, 1)); IGRAPH_FINALLY(igraph_vector_bool_destroy, &Qcheck); IGRAPH_CHECK(igraph_vector_ptr_init(&separators, 0)); IGRAPH_FINALLY(igraph_vector_ptr_destroy, &separators); IGRAPH_VECTOR_INIT_FINALLY(&compvertices, 0); IGRAPH_CHECK(igraph_vector_bool_init(&marked, 0)); IGRAPH_FINALLY(igraph_vector_bool_destroy, &marked); IGRAPH_VECTOR_INIT_FINALLY(&neis, 0); IGRAPH_CHECK(igraph_dqueue_init(&bfsQ, 100)); IGRAPH_FINALLY(igraph_dqueue_destroy, &bfsQ); IGRAPH_CHECK(igraph_vector_long_init(&compid, 0)); IGRAPH_FINALLY(igraph_vector_long_destroy, &compid); IGRAPH_CHECK(igraph_vector_long_init(&components, 0)); IGRAPH_FINALLY(igraph_vector_long_destroy, &components); /* Put the input graph in the queue */ graph_copy=igraph_Calloc(1, igraph_t); if (!graph_copy) { IGRAPH_ERROR("Cannot do cohesive blocking", IGRAPH_ENOMEM); } IGRAPH_CHECK(igraph_copy(graph_copy, graph)); VECTOR(Q)[0] = graph_copy; VECTOR(Qmapping)[0] = 0; /* Identity mapping */ VECTOR(Qparent)[0] = -1; /* Has no parent */ IGRAPH_CHECK(igraph_vertex_connectivity(graph, &conn, /*checks=*/ 1)); VECTOR(Qcohesion)[0] = conn; VECTOR(Qcheck)[0] = 0; /* Then work until the queue is empty */ while (Qptr < igraph_vector_ptr_size(&Q)) { igraph_t *mygraph=VECTOR(Q)[Qptr]; igraph_bool_t mycheck=VECTOR(Qcheck)[Qptr]; long int mynodes=igraph_vcount(mygraph); long int i, nsep; long int no, kept=0; long int cptr=0; long int nsepv=0; igraph_bool_t addedsep=0; IGRAPH_STATUSF(("Candidate %li: %li vertices,", 0, Qptr, mynodes)); IGRAPH_ALLOW_INTERRUPTION(); /* Get the separators */ IGRAPH_CHECK(igraph_minimum_size_separators(mygraph, &separators)); IGRAPH_FINALLY(igraph_i_cohesive_blocks_free3, &separators); nsep=igraph_vector_ptr_size(&separators); IGRAPH_STATUSF((" %li separators,", 0, nsep)); /* Remove them from the graph, also mark them */ IGRAPH_CHECK(igraph_vector_bool_resize(&marked, mynodes)); igraph_vector_bool_null(&marked); for (i=0; i<nsep; i++) { igraph_vector_t *v=VECTOR(separators)[i]; long int j, n=igraph_vector_size(v); for (j=0; j<n; j++) { long int vv=(long int) VECTOR(*v)[j]; if (!VECTOR(marked)[vv]) { nsepv++; VECTOR(marked)[vv] = 1; } } } /* Find the connected components, omitting the separator vertices, but including the neighboring separator vertices */ IGRAPH_CHECK(igraph_i_cb_components(mygraph, &marked, &components, &no, &compid, &bfsQ, &neis)); /* Add the separator vertices themselves, as another component, but only if there is at least one vertex not included in any separator. */ if (nsepv != mynodes) { addedsep=1; for (i=0; i<mynodes; i++) { if (VECTOR(marked)[i]) { IGRAPH_CHECK(igraph_vector_long_push_back(&components, i)); } } IGRAPH_CHECK(igraph_vector_long_push_back(&components, -1)); no++; } IGRAPH_STATUSF((" %li new candidates,", 0, no)); for (i=0; i<no; i++) { igraph_vector_t *newmapping; igraph_t *newgraph; igraph_integer_t maxdeg; igraph_vector_clear(&compvertices); while (1) { long int v=VECTOR(components)[cptr++]; if (v < 0) { break; } IGRAPH_CHECK(igraph_vector_push_back(&compvertices, v)); } newmapping=igraph_Calloc(1, igraph_vector_t); if (!newmapping) { IGRAPH_ERROR("Cannot do cohesive blocking", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, newmapping); IGRAPH_VECTOR_INIT_FINALLY(newmapping, 0); newgraph=igraph_Calloc(1, igraph_t); if (!newgraph) { IGRAPH_ERROR("Cannot do cohesive blocking", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, newgraph); IGRAPH_CHECK(igraph_induced_subgraph_map(mygraph, newgraph, igraph_vss_vector(&compvertices), IGRAPH_SUBGRAPH_AUTO, /*map=*/ 0, /*invmap=*/ newmapping)); IGRAPH_FINALLY(igraph_destroy, newgraph); IGRAPH_CHECK(igraph_maxdegree(newgraph, &maxdeg, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS)); if (maxdeg > VECTOR(Qcohesion)[Qptr]) { igraph_integer_t newconn; kept++; IGRAPH_CHECK(igraph_vector_ptr_push_back(&Q, newgraph)); IGRAPH_FINALLY_CLEAN(2); IGRAPH_CHECK(igraph_vector_ptr_push_back(&Qmapping, newmapping)); IGRAPH_FINALLY_CLEAN(2); IGRAPH_CHECK(igraph_vertex_connectivity(newgraph, &newconn, /*checks=*/ 1)); IGRAPH_CHECK(igraph_vector_long_push_back(&Qcohesion, newconn)); IGRAPH_CHECK(igraph_vector_long_push_back(&Qparent, Qptr)); IGRAPH_CHECK(igraph_vector_bool_push_back(&Qcheck, mycheck || addedsep)); } else { igraph_destroy(newgraph); igraph_free(newgraph); igraph_vector_destroy(newmapping); igraph_free(newmapping); IGRAPH_FINALLY_CLEAN(4); } } IGRAPH_STATUSF((" keeping %li.\n", 0, kept)); igraph_destroy(mygraph); igraph_free(mygraph); VECTOR(Q)[Qptr] = 0; igraph_i_cohesive_blocks_free3(&separators); IGRAPH_FINALLY_CLEAN(1); Qptr++; } igraph_vector_long_destroy(&components); igraph_vector_long_destroy(&compid); igraph_dqueue_destroy(&bfsQ); igraph_vector_destroy(&neis); igraph_vector_bool_destroy(&marked); igraph_vector_destroy(&compvertices); igraph_vector_ptr_destroy(&separators); IGRAPH_FINALLY_CLEAN(7); if (blocks || cohesion || parent || block_tree) { igraph_integer_t noblocks=(igraph_integer_t) Qptr, badblocks=0; igraph_vector_bool_t removed; long int i, resptr=0; igraph_vector_long_t rewritemap; IGRAPH_CHECK(igraph_vector_bool_init(&removed, noblocks)); IGRAPH_FINALLY(igraph_vector_bool_destroy, &removed); IGRAPH_CHECK(igraph_vector_long_init(&rewritemap, noblocks)); IGRAPH_FINALLY(igraph_vector_long_destroy, &rewritemap); for (i=1; i<noblocks; i++) { long int p=VECTOR(Qparent)[i]; while (VECTOR(removed)[p]) { p=VECTOR(Qparent)[p]; } if (VECTOR(Qcohesion)[p] >= VECTOR(Qcohesion)[i]) { VECTOR(removed)[i]=1; badblocks++; } } /* Rewrite the mappings */ for (i=1; i<Qptr; i++) { long int p=VECTOR(Qparent)[i]; igraph_vector_t *mapping=VECTOR(Qmapping)[i]; igraph_vector_t *pmapping=VECTOR(Qmapping)[p]; long int j, n=igraph_vector_size(mapping); if (!pmapping) { continue; } for (j=0; j<n; j++) { long int v=(long int) VECTOR(*mapping)[j]; VECTOR(*mapping)[j] = VECTOR(*pmapping)[v]; } } /* Because we also put the separator vertices in the queue, it is not ensured that the found blocks are not subsets of each other. We check this now. */ for (i=1; i<noblocks; i++) { long int j, ic; igraph_vector_t *ivec; if (!VECTOR(Qcheck)[i] || VECTOR(removed)[i]) { continue; } ivec=VECTOR(Qmapping)[i]; ic=VECTOR(Qcohesion)[i]; for (j=1; j<noblocks; j++) { igraph_vector_t *jvec; long int jc; if (j==i || !VECTOR(Qcheck)[j] || VECTOR(removed)[j]) { continue; } jvec=VECTOR(Qmapping)[j]; jc=VECTOR(Qcohesion)[j]; if (igraph_i_cb_isin(ivec, jvec) && jc >= ic) { badblocks++; VECTOR(removed)[i]=1; break; } } } noblocks -= badblocks; if (blocks) { IGRAPH_CHECK(igraph_vector_ptr_resize(blocks, noblocks)); } if (cohesion) { IGRAPH_CHECK(igraph_vector_resize(cohesion, noblocks)); } if (parent) { IGRAPH_CHECK(igraph_vector_resize(parent, noblocks)); } for (i=0; i<Qptr; i++) { if (VECTOR(removed)[i]) { IGRAPH_STATUSF(("Candidate %li ignored.\n", 0, i)); continue; } else { IGRAPH_STATUSF(("Candidate %li is a cohesive (sub)block\n", 0, i)); } VECTOR(rewritemap)[i] = resptr; if (cohesion) { VECTOR(*cohesion)[resptr]=VECTOR(Qcohesion)[i]; } if (parent || block_tree) { long int p=VECTOR(Qparent)[i]; while (p>=0 && VECTOR(removed)[p]) { p=VECTOR(Qparent)[p]; } if (p>=0) { p=VECTOR(rewritemap)[p]; } VECTOR(Qparent)[i]=p; if (parent) { VECTOR(*parent)[resptr]=p; } } if (blocks) { VECTOR(*blocks)[resptr]=VECTOR(Qmapping)[i]; VECTOR(Qmapping)[i]=0; } resptr++; } /* Plus the original graph */ if (blocks) { igraph_vector_t *orig=igraph_Calloc(1, igraph_vector_t); if (!orig) { IGRAPH_ERROR("Cannot do cohesive blocking", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, orig); IGRAPH_CHECK(igraph_vector_init_seq(orig, 0, igraph_vcount(graph)-1)); VECTOR(*blocks)[0]=orig; IGRAPH_FINALLY_CLEAN(1); } if (block_tree) { igraph_vector_t edges; long int eptr=0; IGRAPH_VECTOR_INIT_FINALLY(&edges, noblocks*2-2); for (i=1; i<Qptr; i++) { if (VECTOR(removed)[i]) { continue; } VECTOR(edges)[eptr++] = VECTOR(Qparent)[i]; VECTOR(edges)[eptr++] = VECTOR(rewritemap)[i]; } IGRAPH_CHECK(igraph_create(block_tree, &edges, noblocks, IGRAPH_DIRECTED)); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); } igraph_vector_long_destroy(&rewritemap); igraph_vector_bool_destroy(&removed); IGRAPH_FINALLY_CLEAN(2); } igraph_vector_bool_destroy(&Qcheck); igraph_vector_long_destroy(&Qcohesion); igraph_vector_long_destroy(&Qparent); igraph_i_cohesive_blocks_free2(&Qmapping); IGRAPH_FINALLY_CLEAN(4); igraph_vector_ptr_destroy(&Qmapping); igraph_vector_ptr_destroy(&Q); IGRAPH_FINALLY_CLEAN(3); /* + the elements of Q, they were already destroyed */ IGRAPH_STATUS("Cohesive blocking done.\n", 0); return 0; }
void igraph_i_graphml_add_attribute_key(const xmlChar** attrs, struct igraph_i_graphml_parser_state *state) { xmlChar **it; igraph_trie_t *trie=0; igraph_vector_ptr_t *ptrvector=0; long int id; int ret; igraph_i_graphml_attribute_record_t *rec= igraph_Calloc(1, igraph_i_graphml_attribute_record_t); if (!state->successful) return; if (rec==0) { igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, IGRAPH_ENOMEM); igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file"); return; } IGRAPH_FINALLY(igraph_free, rec); for (it=(xmlChar**)attrs; *it; it+=2) { if (xmlStrEqual(*it, toXmlChar("id"))) { const char *id=(const char*)(*(it+1)); rec->id=strdup(id); } else if (xmlStrEqual(*it, toXmlChar("attr.name"))) { const char *name=fromXmlChar(*(it+1)); rec->record.name=strdup(name); } else if (xmlStrEqual(*it, toXmlChar("attr.type"))) { if (xmlStrEqual(*(it+1), (xmlChar*)"boolean")) { rec->type=I_GRAPHML_BOOLEAN; rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC; } else if (xmlStrEqual(*(it+1), toXmlChar("string"))) { rec->type=I_GRAPHML_STRING; rec->record.type=IGRAPH_ATTRIBUTE_STRING; } else if (xmlStrEqual(*(it+1), toXmlChar("float"))) { rec->type=I_GRAPHML_FLOAT; rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC; } else if (xmlStrEqual(*(it+1), toXmlChar("double"))) { rec->type=I_GRAPHML_DOUBLE; rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC; } else if (xmlStrEqual(*(it+1), toXmlChar("int"))) { rec->type=I_GRAPHML_INTEGER; rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC; } else if (xmlStrEqual(*(it+1), toXmlChar("long"))) { rec->type=I_GRAPHML_LONG; rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC; } else { igraph_error("Cannot parse GraphML file, unknown attribute type", __FILE__, __LINE__, IGRAPH_PARSEERROR); igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file, unknown attribute type"); return; } } else if (xmlStrEqual(*it, toXmlChar("for"))) { /* graph, vertex or edge attribute? */ if (xmlStrEqual(*(it+1), toXmlChar("graph"))) { trie=&state->g_names; ptrvector=&state->g_attrs; } else if (xmlStrEqual(*(it+1), toXmlChar("node"))) { trie=&state->v_names; ptrvector=&state->v_attrs; } else if (xmlStrEqual(*(it+1), toXmlChar("edge"))) { trie=&state->e_names; ptrvector=&state->e_attrs; } else { igraph_error("Cannot parse GraphML file, unknown attribute type", __FILE__, __LINE__, IGRAPH_PARSEERROR); igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file, unknown attribute type"); return; } } } if (trie == 0 && state->successful) { igraph_error("Cannot parse GraphML file, missing 'for' attribute", __FILE__, __LINE__, IGRAPH_PARSEERROR); igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file, missing 'for' attribute"); return; } /* add to trie, attribues */ igraph_trie_get(trie, rec->id, &id); if (id != igraph_trie_size(trie)-1) { igraph_error("Cannot parse GraphML file, duplicate attribute", __FILE__, __LINE__, IGRAPH_PARSEERROR); igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file, duplicate attribute"); return; } ret=igraph_vector_ptr_push_back(ptrvector, rec); if (ret) { igraph_error("Cannot read GraphML file", __FILE__, __LINE__, ret); igraph_i_graphml_sax_handler_error(state, "Cannot read GraphML file"); return; } /* create the attribute values */ switch (rec->record.type) { igraph_vector_t *vec; igraph_strvector_t *strvec; case IGRAPH_ATTRIBUTE_NUMERIC: vec=igraph_Calloc(1, igraph_vector_t); if (vec==0) { igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, IGRAPH_ENOMEM); igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file"); return; } rec->record.value=vec; igraph_vector_init(vec, 0); break; case IGRAPH_ATTRIBUTE_STRING: strvec=igraph_Calloc(1, igraph_strvector_t); if (strvec==0) { igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, IGRAPH_ENOMEM); igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file"); return; } rec->record.value=strvec; igraph_strvector_init(strvec, 0); break; default: break; } IGRAPH_FINALLY_CLEAN(1); /* rec */ }