/** * \ingroup interface * \function igraph_add_vertices * \brief Adds vertices to a graph. * * </para><para> * This function invalidates all iterators. * * \param graph The graph object to extend. * \param nv Non-negative integer giving the number of * vertices to add. * \param attr The attributes of the new vertices, only used by * high level interfaces, you can supply 0 here. * \return Error code: * \c IGRAPH_EINVAL: invalid number of new * vertices. * * Time complexity: O(|V|) where * |V| is * the number of vertices in the \em new, extended graph. */ int igraph_add_vertices(igraph_t *graph, igraph_integer_t nv, void *attr) { long int ec=igraph_ecount(graph); long int i; if (nv < 0) { IGRAPH_ERROR("cannot add negative number of vertices", IGRAPH_EINVAL); } IGRAPH_CHECK(igraph_vector_reserve(&graph->os, graph->n+nv+1)); IGRAPH_CHECK(igraph_vector_reserve(&graph->is, graph->n+nv+1)); igraph_vector_resize(&graph->os, graph->n+nv+1); /* reserved */ igraph_vector_resize(&graph->is, graph->n+nv+1); /* reserved */ for (i=graph->n+1; i<graph->n+nv+1; i++) { VECTOR(graph->os)[i]=ec; VECTOR(graph->is)[i]=ec; } graph->n += nv; if (graph->attr) { IGRAPH_CHECK(igraph_i_attribute_add_vertices(graph, nv, attr)); } return 0; }
int igraph_disjoint_union_many(igraph_t *res, const igraph_vector_ptr_t *graphs) { long int no_of_graphs=igraph_vector_ptr_size(graphs); igraph_bool_t directed=1; igraph_vector_t edges; long int no_of_edges=0; long int shift=0; igraph_t *graph; long int i, j; igraph_integer_t from, to; if (no_of_graphs != 0) { graph=VECTOR(*graphs)[0]; directed=igraph_is_directed(graph); for (i=0; i<no_of_graphs; i++) { graph=VECTOR(*graphs)[i]; no_of_edges += igraph_ecount(graph); if (directed != igraph_is_directed(graph)) { IGRAPH_ERROR("Cannot union directed and undirected graphs", IGRAPH_EINVAL); } } } IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); IGRAPH_CHECK(igraph_vector_reserve(&edges, 2*no_of_edges)); for (i=0; i<no_of_graphs; i++) { long int ec; graph=VECTOR(*graphs)[i]; ec=igraph_ecount(graph); for (j=0; j<ec; j++) { igraph_edge(graph, (igraph_integer_t) j, &from, &to); igraph_vector_push_back(&edges, from+shift); igraph_vector_push_back(&edges, to+shift); } shift += igraph_vcount(graph); } IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) shift, directed)); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); return 0; }
int igraph_disjoint_union(igraph_t *res, const igraph_t *left, const igraph_t *right) { long int no_of_nodes_left=igraph_vcount(left); long int no_of_nodes_right=igraph_vcount(right); long int no_of_edges_left=igraph_ecount(left); long int no_of_edges_right=igraph_ecount(right); igraph_vector_t edges; igraph_bool_t directed_left=igraph_is_directed(left); igraph_integer_t from, to; long int i; if (directed_left != igraph_is_directed(right)) { IGRAPH_ERROR("Cannot union directed and undirected graphs", IGRAPH_EINVAL); } IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); IGRAPH_CHECK(igraph_vector_reserve(&edges, 2*(no_of_edges_left+no_of_edges_right))); for (i=0; i<no_of_edges_left; i++) { igraph_edge(left, (igraph_integer_t) i, &from, &to); igraph_vector_push_back(&edges, from); igraph_vector_push_back(&edges, to); } for (i=0; i<no_of_edges_right; i++) { igraph_edge(right, (igraph_integer_t) i, &from, &to); igraph_vector_push_back(&edges, from+no_of_nodes_left); igraph_vector_push_back(&edges, to+no_of_nodes_left); } IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) (no_of_nodes_left+no_of_nodes_right), directed_left)); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); return 0; }
int igraph_random_sample(igraph_vector_t *res, igraph_integer_t l, igraph_integer_t h, igraph_integer_t length) { igraph_real_t N=h-l+1; igraph_real_t n=length; int retval; igraph_real_t nreal=length; igraph_real_t ninv=1.0/nreal; igraph_real_t Nreal=N; igraph_real_t Vprime; igraph_real_t qu1=-n+1+N; igraph_real_t qu1real=-nreal+1.0+Nreal; igraph_real_t negalphainv=-13; igraph_real_t threshold=-negalphainv*n; igraph_real_t S; igraph_vector_clear(res); IGRAPH_CHECK(igraph_vector_reserve(res, length)); RNG_BEGIN(); Vprime=exp(log(RNG_UNIF01())*ninv); while (n>1 && threshold < N) { igraph_real_t X, U; igraph_real_t limit, t; igraph_real_t negSreal, y1, y2, top, bottom; igraph_real_t nmin1inv=1.0/(-1.0+nreal); while (1) { while(1) { X=Nreal*(-Vprime+1.0); S=floor(X); if (S==0) { S=1; } if (S <qu1) { break; } Vprime = exp(log(RNG_UNIF01())*ninv); } U=RNG_UNIF01(); negSreal=-S; y1=exp(log(U*Nreal/qu1real)*nmin1inv); Vprime=y1*(-X/Nreal+1.0)*(qu1real/(negSreal+qu1real)); if (Vprime <= 1.0) { break; } y2=1.0; top=-1.0+Nreal; if (-1+n > S) { bottom=-nreal+Nreal; limit=-S+N; } else { bottom=-1.0+negSreal+Nreal; limit=qu1; } for (t=-1+N; t>=limit; t--) { y2=(y2*top)/bottom; top=-1.0+top; bottom=-1.0+bottom; } if (Nreal/(-X+Nreal) >= y1*exp(log(y2)*nmin1inv)) { Vprime=exp(log(RNG_UNIF01())*nmin1inv); break; } Vprime=exp(log(RNG_UNIF01())*ninv); } l+=S; igraph_vector_push_back(res, l); /* allocated */ N=-S+(-1+N); Nreal=negSreal+(-1.0+Nreal); n=-1+n; nreal=-1.0+nreal; ninv=nmin1inv; qu1=-S+qu1; qu1real=negSreal+qu1real; threshold=threshold+negalphainv; } if (n>1) { retval=igraph_random_sample_alga(res, l, h, n); } else { retval=0; S=floor(N*Vprime); l+=S; igraph_vector_push_back(res, l); /* allocated */ } RNG_END(); return retval; }
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_clusters_strong(const igraph_t *graph, igraph_vector_t *membership, igraph_vector_t *csize, igraph_integer_t *no) { long int no_of_nodes=igraph_vcount(graph); igraph_vector_t next_nei=IGRAPH_VECTOR_NULL; long int i; igraph_dqueue_t q=IGRAPH_DQUEUE_NULL; long int no_of_clusters=1; long int act_cluster_size; igraph_vector_t out=IGRAPH_VECTOR_NULL; igraph_vector_t tmp=IGRAPH_VECTOR_NULL; /* The result */ IGRAPH_VECTOR_INIT_FINALLY(&next_nei, no_of_nodes); IGRAPH_VECTOR_INIT_FINALLY(&out, 0); IGRAPH_DQUEUE_INIT_FINALLY(&q, 100); IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0); if (membership) { IGRAPH_CHECK(igraph_vector_resize(membership, no_of_nodes)); } IGRAPH_CHECK(igraph_vector_reserve(&out, no_of_nodes)); igraph_vector_null(&out); if (csize) { igraph_vector_clear(csize); } for (i=0; i<no_of_nodes; i++) { IGRAPH_ALLOW_INTERRUPTION(); IGRAPH_CHECK(igraph_neighbors(graph, &tmp, (igraph_integer_t) i, IGRAPH_OUT)); if (VECTOR(next_nei)[i] > igraph_vector_size(&tmp)) { continue; } IGRAPH_CHECK(igraph_dqueue_push(&q, i)); while (!igraph_dqueue_empty(&q)) { long int act_node=(long int) igraph_dqueue_back(&q); IGRAPH_CHECK(igraph_neighbors(graph, &tmp, (igraph_integer_t) act_node, IGRAPH_OUT)); if (VECTOR(next_nei)[act_node]==0) { /* this is the first time we've met this vertex */ VECTOR(next_nei)[act_node]++; } else if (VECTOR(next_nei)[act_node] <= igraph_vector_size(&tmp)) { /* we've already met this vertex but it has more children */ long int neighbor=(long int) VECTOR(tmp)[(long int) VECTOR(next_nei)[act_node]-1]; if (VECTOR(next_nei)[neighbor] == 0) { IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor)); } VECTOR(next_nei)[act_node]++; } else { /* we've met this vertex and it has no more children */ IGRAPH_CHECK(igraph_vector_push_back(&out, act_node)); igraph_dqueue_pop_back(&q); } } /* while q */ } /* for */ /* OK, we've the 'out' values for the nodes, let's use them in decreasing order with the help of a heap */ igraph_vector_null(&next_nei); /* mark already added vertices */ while (!igraph_vector_empty(&out)) { long int grandfather=(long int) igraph_vector_pop_back(&out); IGRAPH_ALLOW_INTERRUPTION(); if (VECTOR(next_nei)[grandfather] != 0) { continue; } VECTOR(next_nei)[grandfather]=1; act_cluster_size=1; if (membership) { VECTOR(*membership)[grandfather]=no_of_clusters-1; } IGRAPH_CHECK(igraph_dqueue_push(&q, grandfather)); while (!igraph_dqueue_empty(&q)) { long int act_node=(long int) igraph_dqueue_pop_back(&q); IGRAPH_CHECK(igraph_neighbors(graph, &tmp, (igraph_integer_t) act_node, IGRAPH_IN)); for (i=0; i<igraph_vector_size(&tmp); i++) { long int neighbor=(long int) VECTOR(tmp)[i]; if (VECTOR(next_nei)[neighbor] != 0) { continue; } IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor)); VECTOR(next_nei)[neighbor]=1; act_cluster_size++; if (membership) { VECTOR(*membership)[neighbor]=no_of_clusters-1; } } } no_of_clusters++; if (csize) { IGRAPH_CHECK(igraph_vector_push_back(csize, act_cluster_size)); } } if (no) { *no=(igraph_integer_t) no_of_clusters-1; } /* Clean up, return */ igraph_vector_destroy(&out); igraph_vector_destroy(&tmp); igraph_dqueue_destroy(&q); igraph_vector_destroy(&next_nei); IGRAPH_FINALLY_CLEAN(4); return 0; }
/** * \ingroup interface * \function igraph_add_edges * \brief Adds edges to a graph object. * * </para><para> * The edges are given in a vector, the * first two elements define the first edge (the order is * <code>from</code>, <code>to</code> for directed * graphs). The vector * should contain even number of integer numbers between zero and the * number of vertices in the graph minus one (inclusive). If you also * want to add new vertices, call igraph_add_vertices() first. * \param graph The graph to which the edges will be added. * \param edges The edges themselves. * \param attr The attributes of the new edges, only used by high level * interfaces currently, you can supply 0 here. * \return Error code: * \c IGRAPH_EINVEVECTOR: invalid (odd) * edges vector length, \c IGRAPH_EINVVID: * invalid vertex id in edges vector. * * This function invalidates all iterators. * * </para><para> * Time complexity: O(|V|+|E|) where * |V| is the number of vertices and * |E| is the number of * edges in the \em new, extended graph. */ int igraph_add_edges(igraph_t *graph, const igraph_vector_t *edges, void *attr) { long int no_of_edges=igraph_vector_size(&graph->from); long int edges_to_add=igraph_vector_size(edges)/2; long int i=0; igraph_error_handler_t *oldhandler; int ret1, ret2; igraph_vector_t newoi, newii; igraph_bool_t directed=igraph_is_directed(graph); if (igraph_vector_size(edges) % 2 != 0) { IGRAPH_ERROR("invalid (odd) length of edges vector", IGRAPH_EINVEVECTOR); } if (!igraph_vector_isininterval(edges, 0, igraph_vcount(graph)-1)) { IGRAPH_ERROR("cannot add edges", IGRAPH_EINVVID); } /* from & to */ IGRAPH_CHECK(igraph_vector_reserve(&graph->from, no_of_edges+edges_to_add)); IGRAPH_CHECK(igraph_vector_reserve(&graph->to , no_of_edges+edges_to_add)); while (i<edges_to_add*2) { if (directed || VECTOR(*edges)[i] > VECTOR(*edges)[i+1]) { igraph_vector_push_back(&graph->from, VECTOR(*edges)[i++]); /* reserved */ igraph_vector_push_back(&graph->to, VECTOR(*edges)[i++]); /* reserved */ } else { igraph_vector_push_back(&graph->to, VECTOR(*edges)[i++]); /* reserved */ igraph_vector_push_back(&graph->from, VECTOR(*edges)[i++]); /* reserved */ } } /* disable the error handler temporarily */ oldhandler=igraph_set_error_handler(igraph_error_handler_ignore); /* oi & ii */ ret1=igraph_vector_init(&newoi, no_of_edges); ret2=igraph_vector_init(&newii, no_of_edges); if (ret1 != 0 || ret2 != 0) { igraph_vector_resize(&graph->from, no_of_edges); /* gets smaller */ igraph_vector_resize(&graph->to, no_of_edges); /* gets smaller */ igraph_set_error_handler(oldhandler); IGRAPH_ERROR("cannot add edges", IGRAPH_ERROR_SELECT_2(ret1, ret2)); } ret1=igraph_vector_order(&graph->from, &graph->to, &newoi, graph->n); ret2=igraph_vector_order(&graph->to , &graph->from, &newii, graph->n); if (ret1 != 0 || ret2 != 0) { igraph_vector_resize(&graph->from, no_of_edges); igraph_vector_resize(&graph->to, no_of_edges); igraph_vector_destroy(&newoi); igraph_vector_destroy(&newii); igraph_set_error_handler(oldhandler); IGRAPH_ERROR("cannot add edges", IGRAPH_ERROR_SELECT_2(ret1, ret2)); } /* Attributes */ if (graph->attr) { ret1=igraph_i_attribute_add_edges(graph, edges, attr); if (ret1 != 0) { igraph_vector_resize(&graph->from, no_of_edges); igraph_vector_resize(&graph->to, no_of_edges); igraph_vector_destroy(&newoi); igraph_vector_destroy(&newii); igraph_set_error_handler(oldhandler); IGRAPH_ERROR("cannot add edges", ret1); } } /* os & is, its length does not change, error safe */ igraph_i_create_start(&graph->os, &graph->from, &newoi, graph->n); igraph_i_create_start(&graph->is, &graph->to , &newii, graph->n); /* everything went fine */ igraph_vector_destroy(&graph->oi); igraph_vector_destroy(&graph->ii); graph->oi=newoi; graph->ii=newii; igraph_set_error_handler(oldhandler); 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; }
int igraph_bipartite_game_gnp(igraph_t *graph, igraph_vector_bool_t *types, igraph_integer_t n1, igraph_integer_t n2, igraph_real_t p, igraph_bool_t directed, igraph_neimode_t mode) { int retval=0; igraph_vector_t edges, s; int i; if (p < 0.0 || p > 1.0) { IGRAPH_ERROR("Invalid connection probability", IGRAPH_EINVAL); } if (types) { IGRAPH_CHECK(igraph_vector_bool_resize(types, n1 + n2)); igraph_vector_bool_null(types); for (i=n1; i<n1+n2; i++) { VECTOR(*types)[i] = 1; } } if (p == 0 || n1 * n2 < 1) { IGRAPH_CHECK(retval=igraph_empty(graph, n1 + n2, directed)); } else if (p == 1.0) { IGRAPH_CHECK(retval=igraph_full_bipartite(graph, types, n1, n2, directed, mode)); } else { long int to, from, slen; double maxedges, last; if (!directed || mode != IGRAPH_ALL) { maxedges = n1 * n2; } else { maxedges = 2 * n1 * n2; } IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); IGRAPH_VECTOR_INIT_FINALLY(&s, 0); IGRAPH_CHECK(igraph_vector_reserve(&s, (long) (maxedges*p*1.1))); RNG_BEGIN(); last=RNG_GEOM(p); while (last < maxedges) { IGRAPH_CHECK(igraph_vector_push_back(&s, last)); last += RNG_GEOM(p); last += 1; } RNG_END(); slen=igraph_vector_size(&s); IGRAPH_CHECK(igraph_vector_reserve(&edges, slen * 2)); for (i=0; i<slen; i++) { if (!directed || mode != IGRAPH_ALL) { to=(long) floor(VECTOR(s)[i]/n1); from=(long) (VECTOR(s)[i] - ((igraph_real_t) to) * n1); to += n1; } else { long int n1n2 = n1 * n2; if (VECTOR(s)[i] < n1n2) { to=(long) floor(VECTOR(s)[i]/n1); from=(long) (VECTOR(s)[i] - ((igraph_real_t) to) * n1); to += n1; } else { to=(long) floor( (VECTOR(s)[i]-n1n2) /n2); from=(long) (VECTOR(s)[i] - n1n2 - ((igraph_real_t) to) * n2); from += n1; } } if (mode != IGRAPH_IN) { igraph_vector_push_back(&edges, from); igraph_vector_push_back(&edges, to); } else { igraph_vector_push_back(&edges, to); igraph_vector_push_back(&edges, from); } } igraph_vector_destroy(&s); IGRAPH_FINALLY_CLEAN(1); IGRAPH_CHECK(retval=igraph_create(graph, &edges, n1+n2, directed)); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); } return retval; }
int igraph_bipartite_game_gnm(igraph_t *graph, igraph_vector_bool_t *types, igraph_integer_t n1, igraph_integer_t n2, igraph_integer_t m, igraph_bool_t directed, igraph_neimode_t mode) { igraph_vector_t edges; igraph_vector_t s; int retval=0; if (n1 < 0 || n2 < 0) { IGRAPH_ERROR("Invalid number of vertices", IGRAPH_EINVAL); } if (m < 0) { IGRAPH_ERROR("Invalid number of edges", IGRAPH_EINVAL); } if (types) { long int i; IGRAPH_CHECK(igraph_vector_bool_resize(types, n1 + n2)); igraph_vector_bool_null(types); for (i=n1; i<n1+n2; i++) { VECTOR(*types)[i] = 1; } } if (m == 0 || n1 * n2 == 0) { IGRAPH_CHECK(retval=igraph_empty(graph, n1 + n2, directed)); } else { long int i; double maxedges; if (!directed || mode != IGRAPH_ALL) { maxedges = n1 * n2; } else { maxedges = 2 * n1 * n2; } if (m > maxedges) { IGRAPH_ERROR("Invalid number (too large) of edges", IGRAPH_EINVAL); } if (maxedges == m) { IGRAPH_CHECK(retval=igraph_full_bipartite(graph, types, n1, n2, directed, mode)); } else { long int to, from; IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); IGRAPH_VECTOR_INIT_FINALLY(&s, 0); IGRAPH_CHECK(igraph_random_sample(&s, 0, maxedges-1, m)); IGRAPH_CHECK(igraph_vector_reserve(&edges, igraph_vector_size(&s)*2)); for (i=0; i<m; i++) { if (!directed || mode != IGRAPH_ALL) { to=(long) floor(VECTOR(s)[i]/n1); from=(long) (VECTOR(s)[i] - ((igraph_real_t) to) * n1); to += n1; } else { long int n1n2 = n1 * n2; if (VECTOR(s)[i] < n1n2) { to=(long) floor(VECTOR(s)[i]/n1); from=(long) (VECTOR(s)[i] - ((igraph_real_t) to) * n1); to += n1; } else { to=(long) floor( (VECTOR(s)[i]-n1n2) /n2); from=(long) (VECTOR(s)[i] - n1n2 - ((igraph_real_t) to) * n2); from += n1; } } if (mode != IGRAPH_IN) { igraph_vector_push_back(&edges, from); igraph_vector_push_back(&edges, to); } else { igraph_vector_push_back(&edges, to); igraph_vector_push_back(&edges, from); } } igraph_vector_destroy(&s); IGRAPH_FINALLY_CLEAN(1); IGRAPH_CHECK(retval=igraph_create(graph, &edges, n1+n2, directed)); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); } } return retval; }
int igraph_i_bipartite_projection(const igraph_t *graph, const igraph_vector_bool_t *types, igraph_t *proj, int which, igraph_vector_t *multiplicity) { long int no_of_nodes=igraph_vcount(graph); long int i, j, k; igraph_integer_t remaining_nodes=0; igraph_vector_t vertex_perm, vertex_index; igraph_vector_t edges; igraph_adjlist_t adjlist; igraph_vector_int_t *neis1, *neis2; long int neilen1, neilen2; igraph_vector_long_t added; igraph_vector_t mult; if (which < 0) { return 0; } IGRAPH_VECTOR_INIT_FINALLY(&vertex_perm, 0); IGRAPH_CHECK(igraph_vector_reserve(&vertex_perm, no_of_nodes)); IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); IGRAPH_VECTOR_INIT_FINALLY(&vertex_index, no_of_nodes); IGRAPH_CHECK(igraph_vector_long_init(&added, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &added); IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL)); IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist); if (multiplicity) { IGRAPH_VECTOR_INIT_FINALLY(&mult, no_of_nodes); igraph_vector_clear(multiplicity); } for (i=0; i<no_of_nodes; i++) { if (VECTOR(*types)[i] == which) { VECTOR(vertex_index)[i] = ++remaining_nodes; igraph_vector_push_back(&vertex_perm, i); } } for (i=0; i<no_of_nodes; i++) { if (VECTOR(*types)[i] == which) { long int new_i=(long int) VECTOR(vertex_index)[i]-1; long int iedges=0; neis1=igraph_adjlist_get(&adjlist, i); neilen1=igraph_vector_int_size(neis1); for (j=0; j<neilen1; j++) { long int nei=(long int) VECTOR(*neis1)[j]; if (IGRAPH_UNLIKELY(VECTOR(*types)[i] == VECTOR(*types)[nei])) { IGRAPH_ERROR("Non-bipartite edge found in bipartite projection", IGRAPH_EINVAL); } neis2=igraph_adjlist_get(&adjlist, nei); neilen2=igraph_vector_int_size(neis2); for (k=0; k<neilen2; k++) { long int nei2=(long int) VECTOR(*neis2)[k], new_nei2; if (nei2 <= i) { continue; } if (VECTOR(added)[nei2] == i+1) { if (multiplicity) { VECTOR(mult)[nei2]+=1; } continue; } VECTOR(added)[nei2] = i+1; if (multiplicity) { VECTOR(mult)[nei2]=1; } iedges++; IGRAPH_CHECK(igraph_vector_push_back(&edges, new_i)); if (multiplicity) { /* If we need the multiplicity as well, then we put in the old vertex ids here and rewrite it later */ IGRAPH_CHECK(igraph_vector_push_back(&edges, nei2)); } else { new_nei2=(long int) VECTOR(vertex_index)[nei2]-1; IGRAPH_CHECK(igraph_vector_push_back(&edges, new_nei2)); } } } if (multiplicity) { /* OK, we need to go through all the edges added for vertex new_i and check their multiplicity */ long int now=igraph_vector_size(&edges); long int from=now-iedges*2; for (j=from; j<now; j+=2) { long int nei2=(long int) VECTOR(edges)[j+1]; long int new_nei2=(long int) VECTOR(vertex_index)[nei2]-1; long int m=(long int) VECTOR(mult)[nei2]; VECTOR(edges)[j+1]=new_nei2; IGRAPH_CHECK(igraph_vector_push_back(multiplicity, m)); } } } /* if VECTOR(*type)[i] == which */ } if (multiplicity) { igraph_vector_destroy(&mult); IGRAPH_FINALLY_CLEAN(1); } igraph_adjlist_destroy(&adjlist); igraph_vector_long_destroy(&added); igraph_vector_destroy(&vertex_index); IGRAPH_FINALLY_CLEAN(3); IGRAPH_CHECK(igraph_create(proj, &edges, remaining_nodes, /*directed=*/ 0)); igraph_vector_destroy(&edges); IGRAPH_FINALLY_CLEAN(1); IGRAPH_FINALLY(igraph_destroy, proj); IGRAPH_I_ATTRIBUTE_DESTROY(proj); IGRAPH_I_ATTRIBUTE_COPY(proj, graph, 1, 0, 0); IGRAPH_CHECK(igraph_i_attribute_permute_vertices(graph, proj, &vertex_perm)); igraph_vector_destroy(&vertex_perm); IGRAPH_FINALLY_CLEAN(2); return 0; }
int igraph_to_undirected(igraph_t *graph, igraph_to_undirected_t mode) { long int no_of_nodes=igraph_vcount(graph); long int no_of_edges=igraph_ecount(graph); igraph_vector_t edges; igraph_t newgraph; if (mode != IGRAPH_TO_UNDIRECTED_EACH && mode != IGRAPH_TO_UNDIRECTED_COLLAPSE) { IGRAPH_ERROR("Cannot undirect graph, invalid mode", IGRAPH_EINVAL); } if (!igraph_is_directed(graph)) { return 0; } IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); if (mode==IGRAPH_TO_UNDIRECTED_EACH) { igraph_es_t es; igraph_eit_t eit; IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2)); IGRAPH_CHECK(igraph_es_all(&es, IGRAPH_EDGEORDER_ID)); IGRAPH_FINALLY(igraph_es_destroy, &es); IGRAPH_CHECK(igraph_eit_create(graph, es, &eit)); IGRAPH_FINALLY(igraph_eit_destroy, &eit); while (!IGRAPH_EIT_END(eit)) { long int edge=IGRAPH_EIT_GET(eit); igraph_integer_t from, to; igraph_edge(graph, edge, &from, &to); IGRAPH_CHECK(igraph_vector_push_back(&edges, from)); IGRAPH_CHECK(igraph_vector_push_back(&edges, to)); IGRAPH_EIT_NEXT(eit); } igraph_eit_destroy(&eit); igraph_es_destroy(&es); IGRAPH_FINALLY_CLEAN(2); IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes, IGRAPH_UNDIRECTED)); IGRAPH_FINALLY(igraph_destroy, &newgraph); igraph_vector_destroy(&edges); IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph); IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,1); IGRAPH_FINALLY_CLEAN(2); igraph_destroy(graph); *graph=newgraph; } else if (mode==IGRAPH_TO_UNDIRECTED_COLLAPSE) { igraph_vector_t seen, nei; long int i,j; IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2)); IGRAPH_VECTOR_INIT_FINALLY(&seen, no_of_nodes); IGRAPH_VECTOR_INIT_FINALLY(&nei, 0); for (i=0; i<no_of_nodes; i++) { IGRAPH_CHECK(igraph_neighbors(graph, &nei, i, IGRAPH_ALL)); for (j=0; j<igraph_vector_size(&nei); j++) { long int node=VECTOR(nei)[j]; if (VECTOR(seen)[node] != i+1 && node >= i) { IGRAPH_CHECK(igraph_vector_push_back(&edges, i)); IGRAPH_CHECK(igraph_vector_push_back(&edges, node)); VECTOR(seen)[node]=i+1; } } } igraph_vector_destroy(&nei); igraph_vector_destroy(&seen); IGRAPH_FINALLY_CLEAN(2); IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes, IGRAPH_UNDIRECTED)); IGRAPH_FINALLY(igraph_destroy, &newgraph); igraph_vector_destroy(&edges); IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph); IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,0); /* no edge attributes */ IGRAPH_FINALLY_CLEAN(2); igraph_destroy(graph); *graph=newgraph; } return 0; }
int igraph_to_directed(igraph_t *graph, igraph_to_directed_t mode) { if (mode != IGRAPH_TO_DIRECTED_ARBITRARY && mode != IGRAPH_TO_DIRECTED_MUTUAL) { IGRAPH_ERROR("Cannot directed graph, invalid mode", IGRAPH_EINVAL); } if (igraph_is_directed(graph)) { return 0; } if (mode==IGRAPH_TO_DIRECTED_ARBITRARY) { igraph_t newgraph; igraph_vector_t edges; long int no_of_edges=igraph_ecount(graph); long int no_of_nodes=igraph_vcount(graph); long int size=no_of_edges*2; IGRAPH_VECTOR_INIT_FINALLY(&edges, size); IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0)); IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes, IGRAPH_DIRECTED)); IGRAPH_FINALLY(igraph_destroy, &newgraph); igraph_vector_destroy(&edges); IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph); IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,1); IGRAPH_FINALLY_CLEAN(2); igraph_destroy(graph); *graph=newgraph; } else if (mode==IGRAPH_TO_DIRECTED_MUTUAL) { igraph_t newgraph; igraph_vector_t edges; igraph_vector_t index; long int no_of_edges=igraph_ecount(graph); long int no_of_nodes=igraph_vcount(graph); long int size=no_of_edges*4; long int i; IGRAPH_VECTOR_INIT_FINALLY(&edges, 0); IGRAPH_CHECK(igraph_vector_reserve(&edges, size)); IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0)); IGRAPH_CHECK(igraph_vector_resize(&edges, no_of_edges*4)); IGRAPH_VECTOR_INIT_FINALLY(&index, no_of_edges*2); for (i=0; i<no_of_edges; i++) { VECTOR(edges)[no_of_edges*2+i*2] =VECTOR(edges)[i*2+1]; VECTOR(edges)[no_of_edges*2+i*2+1]=VECTOR(edges)[i*2]; VECTOR(index)[i] = VECTOR(index)[no_of_edges+i] = i+1; } IGRAPH_CHECK(igraph_create(&newgraph, &edges, no_of_nodes, IGRAPH_DIRECTED)); IGRAPH_FINALLY(igraph_destroy, &newgraph); IGRAPH_I_ATTRIBUTE_DESTROY(&newgraph); IGRAPH_I_ATTRIBUTE_COPY(&newgraph, graph, 1,1,1); IGRAPH_CHECK(igraph_i_attribute_permute_edges(&newgraph, &index)); igraph_vector_destroy(&index); igraph_vector_destroy(&edges); igraph_destroy(graph); IGRAPH_FINALLY_CLEAN(3); *graph=newgraph; } return 0; }
int igraph_all_minimal_st_separators(const igraph_t *graph, igraph_vector_ptr_t *separators) { /* * Some notes about the tricks used here. For finding the components * of the graph after removing some vertices, we do the * following. First we mark the vertices with the actual mark stamp * (mark), then run breadth-first search on the graph, but not * considering the marked vertices. Then we increase the mark. If * there is integer overflow here, then we zero out the mark and set * it to one. (We might as well just always zero it out.) * * For each separator the vertices are stored in vertex id order. * This facilitates the comparison of the separators when we find a * potential new candidate. * * To keep track of which separator we already used as a basis, we * keep a boolean vector (already_tried). The try_next pointer show * the next separator to try as a basis. */ long int no_of_nodes=igraph_vcount(graph); igraph_vector_t leaveout; igraph_vector_bool_t already_tried; long int try_next=0; unsigned long int mark=1; long int v; igraph_adjlist_t adjlist; igraph_vector_t components; igraph_dqueue_t Q; igraph_vector_t sorter; igraph_vector_ptr_clear(separators); IGRAPH_FINALLY(igraph_i_separators_free, separators); IGRAPH_CHECK(igraph_vector_init(&leaveout, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_destroy, &leaveout); IGRAPH_CHECK(igraph_vector_bool_init(&already_tried, 0)); IGRAPH_FINALLY(igraph_vector_bool_destroy, &already_tried); IGRAPH_CHECK(igraph_vector_init(&components, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &components); IGRAPH_CHECK(igraph_vector_reserve(&components, no_of_nodes*2)); IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL)); IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist); IGRAPH_CHECK(igraph_dqueue_init(&Q, 100)); IGRAPH_FINALLY(igraph_dqueue_destroy, &Q); IGRAPH_CHECK(igraph_vector_init(&sorter, 0)); IGRAPH_FINALLY(igraph_vector_destroy, &sorter); IGRAPH_CHECK(igraph_vector_reserve(&sorter, no_of_nodes)); /* --------------------------------------------------------------- * INITIALIZATION, we check whether the neighborhoods of the * vertices separate the graph. The ones that do will form the * initial basis. */ for (v=0; v<no_of_nodes; v++) { /* Mark v and its neighbors */ igraph_vector_int_t *neis=igraph_adjlist_get(&adjlist, v); long int i, n=igraph_vector_int_size(neis); VECTOR(leaveout)[v]=mark; for (i=0; i<n; i++) { long int nei=(long int) VECTOR(*neis)[i]; VECTOR(leaveout)[nei]=mark; } /* Find the components */ IGRAPH_CHECK(igraph_i_clusters_leaveout(&adjlist, &components, &leaveout, &mark, &Q)); /* Store the corresponding separators, N(C) for each component C */ IGRAPH_CHECK(igraph_i_separators_store(separators, &adjlist, &components, &leaveout, &mark, &sorter)); } /* --------------------------------------------------------------- * GENERATION, we need to use all already found separators as * basis and see if they generate more separators */ while (try_next < igraph_vector_ptr_size(separators)) { igraph_vector_t *basis=VECTOR(*separators)[try_next]; long int b, basislen=igraph_vector_size(basis); for (b=0; b<basislen; b++) { /* Remove N(x) U basis */ long int x=(long int) VECTOR(*basis)[b]; igraph_vector_int_t *neis=igraph_adjlist_get(&adjlist, x); long int i, n=igraph_vector_int_size(neis); for (i=0; i<basislen; i++) { long int sn=(long int) VECTOR(*basis)[i]; VECTOR(leaveout)[sn]=mark; } for (i=0; i<n; i++) { long int nei=(long int) VECTOR(*neis)[i]; VECTOR(leaveout)[nei]=mark; } /* Find the components */ IGRAPH_CHECK(igraph_i_clusters_leaveout(&adjlist, &components, &leaveout, &mark, &Q)); /* Store the corresponding separators, N(C) for each component C */ IGRAPH_CHECK(igraph_i_separators_store(separators, &adjlist, &components, &leaveout, &mark, &sorter)); } try_next++; } /* --------------------------------------------------------------- */ igraph_vector_destroy(&sorter); igraph_dqueue_destroy(&Q); igraph_adjlist_destroy(&adjlist); igraph_vector_destroy(&components); igraph_vector_bool_destroy(&already_tried); igraph_vector_destroy(&leaveout); IGRAPH_FINALLY_CLEAN(7); /* +1 for separators */ return 0; }
int igraph_clusters_strong(const igraph_t *graph, igraph_vector_t *membership, igraph_vector_t *csize, igraph_integer_t *no) { long int no_of_nodes=igraph_vcount(graph); igraph_vector_t next_nei=IGRAPH_VECTOR_NULL; long int i, n, num_seen; igraph_dqueue_t q=IGRAPH_DQUEUE_NULL; long int no_of_clusters=1; long int act_cluster_size; igraph_vector_t out=IGRAPH_VECTOR_NULL; const igraph_vector_int_t* tmp; igraph_adjlist_t adjlist; /* The result */ IGRAPH_VECTOR_INIT_FINALLY(&next_nei, no_of_nodes); IGRAPH_VECTOR_INIT_FINALLY(&out, 0); IGRAPH_DQUEUE_INIT_FINALLY(&q, 100); if (membership) { IGRAPH_CHECK(igraph_vector_resize(membership, no_of_nodes)); } IGRAPH_CHECK(igraph_vector_reserve(&out, no_of_nodes)); igraph_vector_null(&out); if (csize) { igraph_vector_clear(csize); } IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_OUT)); IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist); num_seen = 0; for (i=0; i<no_of_nodes; i++) { IGRAPH_ALLOW_INTERRUPTION(); tmp = igraph_adjlist_get(&adjlist, i); if (VECTOR(next_nei)[i] > igraph_vector_int_size(tmp)) { continue; } IGRAPH_CHECK(igraph_dqueue_push(&q, i)); while (!igraph_dqueue_empty(&q)) { long int act_node=(long int) igraph_dqueue_back(&q); tmp = igraph_adjlist_get(&adjlist, act_node); if (VECTOR(next_nei)[act_node]==0) { /* this is the first time we've met this vertex */ VECTOR(next_nei)[act_node]++; } else if (VECTOR(next_nei)[act_node] <= igraph_vector_int_size(tmp)) { /* we've already met this vertex but it has more children */ long int neighbor=(long int) VECTOR(*tmp)[(long int) VECTOR(next_nei)[act_node]-1]; if (VECTOR(next_nei)[neighbor] == 0) { IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor)); } VECTOR(next_nei)[act_node]++; } else { /* we've met this vertex and it has no more children */ IGRAPH_CHECK(igraph_vector_push_back(&out, act_node)); igraph_dqueue_pop_back(&q); num_seen++; if (num_seen % 10000 == 0) { /* time to report progress and allow the user to interrupt */ IGRAPH_PROGRESS("Strongly connected components: ", num_seen * 50.0 / no_of_nodes, NULL); IGRAPH_ALLOW_INTERRUPTION(); } } } /* while q */ } /* for */ IGRAPH_PROGRESS("Strongly connected components: ", 50.0, NULL); igraph_adjlist_destroy(&adjlist); IGRAPH_FINALLY_CLEAN(1); IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_IN)); IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist); /* OK, we've the 'out' values for the nodes, let's use them in decreasing order with the help of a heap */ igraph_vector_null(&next_nei); /* mark already added vertices */ num_seen = 0; while (!igraph_vector_empty(&out)) { long int grandfather=(long int) igraph_vector_pop_back(&out); if (VECTOR(next_nei)[grandfather] != 0) { continue; } VECTOR(next_nei)[grandfather]=1; act_cluster_size=1; if (membership) { VECTOR(*membership)[grandfather]=no_of_clusters-1; } IGRAPH_CHECK(igraph_dqueue_push(&q, grandfather)); num_seen++; if (num_seen % 10000 == 0) { /* time to report progress and allow the user to interrupt */ IGRAPH_PROGRESS("Strongly connected components: ", 50.0 + num_seen * 50.0 / no_of_nodes, NULL); IGRAPH_ALLOW_INTERRUPTION(); } while (!igraph_dqueue_empty(&q)) { long int act_node=(long int) igraph_dqueue_pop_back(&q); tmp = igraph_adjlist_get(&adjlist, act_node); n = igraph_vector_int_size(tmp); for (i=0; i<n; i++) { long int neighbor=(long int) VECTOR(*tmp)[i]; if (VECTOR(next_nei)[neighbor] != 0) { continue; } IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor)); VECTOR(next_nei)[neighbor]=1; act_cluster_size++; if (membership) { VECTOR(*membership)[neighbor]=no_of_clusters-1; } num_seen++; if (num_seen % 10000 == 0) { /* time to report progress and allow the user to interrupt */ IGRAPH_PROGRESS("Strongly connected components: ", 50.0 + num_seen * 50.0 / no_of_nodes, NULL); IGRAPH_ALLOW_INTERRUPTION(); } } } no_of_clusters++; if (csize) { IGRAPH_CHECK(igraph_vector_push_back(csize, act_cluster_size)); } } IGRAPH_PROGRESS("Strongly connected components: ", 100.0, NULL); if (no) { *no=(igraph_integer_t) no_of_clusters-1; } /* Clean up, return */ igraph_adjlist_destroy(&adjlist); igraph_vector_destroy(&out); igraph_dqueue_destroy(&q); igraph_vector_destroy(&next_nei); IGRAPH_FINALLY_CLEAN(4); return 0; }