int dfs_d(const igraph_t *graph, igraph_integer_t root, igraph_neimode_t mode, igraph_bool_t unreachable, igraph_vector_t *order, igraph_vector_t *order_out, igraph_vector_t *father, igraph_vector_t *dist, igraph_dfshandler_t *in_callback, igraph_dfshandler_t *out_callback, void *extra) { long int no_of_nodes=igraph_vcount(graph); igraph_lazy_adjlist_t adjlist; igraph_stack_t stack; igraph_vector_char_t added; igraph_vector_long_t nptr; long int actroot; long int act_rank=0; long int rank_out=0; long int act_dist=0; if (root < 0 || root >= no_of_nodes) { IGRAPH_ERROR("Invalid root vertex for DFS", IGRAPH_EINVAL); } if (mode != IGRAPH_OUT && mode != IGRAPH_IN && mode != IGRAPH_ALL) { IGRAPH_ERROR("Invalid mode argument", IGRAPH_EINVMODE); } if (!igraph_is_directed(graph)) { mode=IGRAPH_ALL; } IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_char_destroy, &added); IGRAPH_CHECK(igraph_stack_init(&stack, 100)); IGRAPH_FINALLY(igraph_stack_destroy, &stack); IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adjlist, mode, /*simplify=*/ 0)); IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist); IGRAPH_CHECK(igraph_vector_long_init(&nptr, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_long_destroy, &nptr); # define FREE_ALL() do { \ igraph_vector_long_destroy(&nptr); \ igraph_lazy_adjlist_destroy(&adjlist); \ igraph_stack_destroy(&stack); \ igraph_vector_char_destroy(&added); \ IGRAPH_FINALLY_CLEAN(4); } while (0) /* Resize result vectors and fill them with IGRAPH_NAN */ # define VINIT(v) if (v) { \ igraph_vector_resize(v, no_of_nodes); \ igraph_vector_fill(v, IGRAPH_NAN); } VINIT(order); VINIT(order_out); VINIT(father); VINIT(dist); # undef VINIT IGRAPH_CHECK(igraph_stack_push(&stack, root)); VECTOR(added)[(long int)root] = 1; if (father) { VECTOR(*father)[(long int)root] = -1; } if (order) { VECTOR(*order)[act_rank++] = root; } if (dist) { VECTOR(*dist)[(long int)root] = 0; } if (in_callback) { igraph_bool_t terminate=in_callback(graph, root, 0, extra); if (terminate) { FREE_ALL(); return 0; } } for (actroot=0; actroot<no_of_nodes; actroot++) { /* 'root' first, then all other vertices */ if (igraph_stack_empty(&stack)) { if (!unreachable) { break; } if (VECTOR(added)[actroot]) { continue; } IGRAPH_CHECK(igraph_stack_push(&stack, actroot)); VECTOR(added)[actroot] = 1; if (father) { VECTOR(*father)[actroot] = -1; } if (order) { VECTOR(*order)[act_rank++] = actroot; } if (dist) { VECTOR(*dist)[actroot] = 0; } if (in_callback) { igraph_bool_t terminate=in_callback(graph, (igraph_integer_t) actroot, 0, extra); if (terminate) { FREE_ALL(); return 0; } } } while (!igraph_stack_empty(&stack)) { long int actvect=(long int) igraph_stack_top(&stack); igraph_vector_t *neis=igraph_lazy_adjlist_get(&adjlist, (igraph_integer_t) actvect); long int n=igraph_vector_size(neis); long int *ptr=igraph_vector_long_e_ptr(&nptr, actvect); igraph_vector_shuffle(neis); igraph_vector_print(neis); /* Search for a neighbor that was not yet visited */ igraph_bool_t any=0; long int nei; while (!any && (*ptr) <n) { nei=(long int) VECTOR(*neis)[(*ptr)]; any=!VECTOR(added)[nei]; (*ptr) ++; } if (any) { /* There is such a neighbor, add it */ IGRAPH_CHECK(igraph_stack_push(&stack, nei)); VECTOR(added)[nei] = 1; if (father) { VECTOR(*father)[ nei ] = actvect; } if (order) { VECTOR(*order)[act_rank++] = nei; } act_dist++; if (dist) { VECTOR(*dist)[nei] = act_dist; } if (in_callback) { igraph_bool_t terminate=in_callback(graph, (igraph_integer_t) nei, (igraph_integer_t) act_dist, extra); if (terminate) { FREE_ALL(); return 0; } } } else { /* There is no such neighbor, finished with the subtree */ igraph_stack_pop(&stack); if (order_out) { VECTOR(*order_out)[rank_out++] = actvect; } act_dist--; if (out_callback) { igraph_bool_t terminate=out_callback(graph, (igraph_integer_t) actvect, (igraph_integer_t) act_dist, extra); if (terminate) { FREE_ALL(); return 0; } } } } } FREE_ALL(); # undef FREE_ALL 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_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 main() { igraph_stack_t st; int i; /* igraph_stack_init, igraph_stack_destroy */ igraph_stack_init(&st, 0); igraph_stack_destroy(&st); igraph_stack_init(&st, 10); igraph_stack_destroy(&st); /* igraph_stack_reserve */ igraph_stack_init(&st, 0); igraph_stack_reserve(&st, 10); igraph_stack_reserve(&st, 5); /* igraph_stack_empty */ if (!igraph_stack_empty(&st)) { return 1; } igraph_stack_push(&st, 1); if (igraph_stack_empty(&st)) { return 2; } /* igraph_stack_size */ if (igraph_stack_size(&st) != 1) { return 3; } for (i=0; i<10; i++) { igraph_stack_push(&st, i); } if (igraph_stack_size(&st) != 11) { return 4; } /* igraph_stack_clear */ igraph_stack_clear(&st); if (!igraph_stack_empty(&st)) { return 5; } igraph_stack_push(&st, 100); if (igraph_stack_pop(&st) != 100) { return 6; } igraph_stack_clear(&st); igraph_stack_clear(&st); /* igraph_stack_push, igraph_stack_pop */ for (i=0; i<100; i++) { igraph_stack_push(&st, 100-i); } for (i=0; i<100; i++) { if (igraph_stack_pop(&st) != i+1) { return 7; } } if (!igraph_stack_empty(&st)) { return 8; } igraph_stack_destroy(&st); if (IGRAPH_FINALLY_STACK_SIZE() != 0) return 9; return 0; }
/** * \ingroup structural * \function igraph_betweenness_estimate * \brief Estimated betweenness centrality of some vertices. * * </para><para> * The betweenness centrality of a vertex is the number of geodesics * going through it. If there are more than one geodesic between two * vertices, the value of these geodesics are weighted by one over the * number of geodesics. When estimating betweenness centrality, igraph * takes into consideration only those paths that are shorter than or * equal to a prescribed length. Note that the estimated centrality * will always be less than the real one. * * \param graph The graph object. * \param res The result of the computation, a vector containing the * estimated betweenness scores for the specified vertices. * \param vids The vertices of which the betweenness centrality scores * will be estimated. * \param directed Logical, if true directed paths will be considered * for directed graphs. It is ignored for undirected graphs. * \param cutoff The maximal length of paths that will be considered. * If zero or negative, the exact betweenness will be calculated * (no upper limit on path lengths). * \return Error code: * \c IGRAPH_ENOMEM, not enough memory for * temporary data. * \c IGRAPH_EINVVID, invalid vertex id passed in * \p vids. * * Time complexity: O(|V||E|), * |V| and * |E| are the number of vertices and * edges in the graph. * Note that the time complexity is independent of the number of * vertices for which the score is calculated. * * \sa Other centrality types: \ref igraph_degree(), \ref igraph_closeness(). * See \ref igraph_edge_betweenness() for calculating the betweenness score * of the edges in a graph. */ int igraph_betweenness_estimate(const igraph_t *graph, igraph_vector_t *res, const igraph_vs_t vids, igraph_bool_t directed, igraph_integer_t cutoff) { long int no_of_nodes=igraph_vcount(graph); igraph_dqueue_t q=IGRAPH_DQUEUE_NULL; long int *distance; long int *nrgeo; double *tmpscore; igraph_stack_t stack=IGRAPH_STACK_NULL; long int source; long int j, k; igraph_integer_t modein, modeout; igraph_vit_t vit; igraph_vector_t *neis; igraph_adjlist_t adjlist_out, adjlist_in; igraph_adjlist_t *adjlist_out_p, *adjlist_in_p; IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit)); IGRAPH_FINALLY(igraph_vit_destroy, &vit); directed=directed && igraph_is_directed(graph); if (directed) { modeout=IGRAPH_OUT; modein=IGRAPH_IN; IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist_out, IGRAPH_OUT)); IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist_out); IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist_in, IGRAPH_IN)); IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist_in); adjlist_out_p=&adjlist_out; adjlist_in_p=&adjlist_in; } else { modeout=modein=IGRAPH_ALL; IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist_out, IGRAPH_ALL)); IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist_out); adjlist_out_p=adjlist_in_p=&adjlist_out; } distance=igraph_Calloc(no_of_nodes, long int); if (distance==0) { IGRAPH_ERROR("betweenness failed", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, distance); nrgeo=igraph_Calloc(no_of_nodes, long int); if (nrgeo==0) { IGRAPH_ERROR("betweenness failed", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, nrgeo); tmpscore=igraph_Calloc(no_of_nodes, double); if (tmpscore==0) { IGRAPH_ERROR("betweenness failed", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, tmpscore); IGRAPH_DQUEUE_INIT_FINALLY(&q, 100); igraph_stack_init(&stack, no_of_nodes); IGRAPH_FINALLY(igraph_stack_destroy, &stack); IGRAPH_CHECK(igraph_vector_resize(res, IGRAPH_VIT_SIZE(vit))); igraph_vector_null(res); /* here we go */ for (source=0; source<no_of_nodes; source++) { IGRAPH_PROGRESS("Betweenness centrality: ", 100.0*source/no_of_nodes, 0); IGRAPH_ALLOW_INTERRUPTION(); memset(distance, 0, no_of_nodes*sizeof(long int)); memset(nrgeo, 0, no_of_nodes*sizeof(long int)); memset(tmpscore, 0, no_of_nodes*sizeof(double)); igraph_stack_clear(&stack); /* it should be empty anyway... */ IGRAPH_CHECK(igraph_dqueue_push(&q, source)); nrgeo[source]=1; distance[source]=0; while (!igraph_dqueue_empty(&q)) { long int actnode=igraph_dqueue_pop(&q); if (cutoff > 0 && distance[actnode] >= cutoff) continue; neis = igraph_adjlist_get(adjlist_out_p, actnode); for (j=0; j<igraph_vector_size(neis); j++) { long int neighbor=VECTOR(*neis)[j]; if (nrgeo[neighbor] != 0) { /* we've already seen this node, another shortest path? */ if (distance[neighbor]==distance[actnode]+1) { nrgeo[neighbor]+=nrgeo[actnode]; } } else { /* we haven't seen this node yet */ nrgeo[neighbor]+=nrgeo[actnode]; distance[neighbor]=distance[actnode]+1; IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor)); IGRAPH_CHECK(igraph_stack_push(&stack, neighbor)); } } } /* while !igraph_dqueue_empty */ /* Ok, we've the distance of each node and also the number of shortest paths to them. Now we do an inverse search, starting with the farthest nodes. */ while (!igraph_stack_empty(&stack)) { long int actnode=igraph_stack_pop(&stack); if (distance[actnode]<=1) { continue; } /* skip source node */ /* set the temporary score of the friends */ neis = igraph_adjlist_get(adjlist_in_p, actnode); for (j=0; j<igraph_vector_size(neis); j++) { long int neighbor=VECTOR(*neis)[j]; if (distance[neighbor]==distance[actnode]-1 && nrgeo[neighbor] != 0) { tmpscore[neighbor] += (tmpscore[actnode]+1)*nrgeo[neighbor]/nrgeo[actnode]; } } } /* Ok, we've the scores for this source */ for (k=0, IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), k++) { long int node=IGRAPH_VIT_GET(vit); VECTOR(*res)[k] += tmpscore[node]; tmpscore[node] = 0.0; /* in case a node is in vids multiple times */ } } /* for source < no_of_nodes */ /* divide by 2 for undirected graph */ if (!directed) { for (j=0; j<igraph_vector_size(res); j++) { VECTOR(*res)[j] /= 2.0; } } /* clean */ igraph_Free(distance); igraph_Free(nrgeo); igraph_Free(tmpscore); igraph_dqueue_destroy(&q); igraph_stack_destroy(&stack); igraph_vit_destroy(&vit); IGRAPH_FINALLY_CLEAN(6); if (directed) { igraph_adjlist_destroy(&adjlist_out); igraph_adjlist_destroy(&adjlist_in); IGRAPH_FINALLY_CLEAN(2); } else { igraph_adjlist_destroy(&adjlist_out); IGRAPH_FINALLY_CLEAN(1); } return 0; }
/** * \ingroup structural * \function igraph_edge_betweenness_estimate * \brief Estimated betweenness centrality of the edges. * * </para><para> * The betweenness centrality of an edge is the number of geodesics * going through it. If there are more than one geodesics between two * vertices, the value of these geodesics are weighted by one over the * number of geodesics. When estimating betweenness centrality, igraph * takes into consideration only those paths that are shorter than or * equal to a prescribed length. Note that the estimated centrality * will always be less than the real one. * \param graph The graph object. * \param result The result of the computation, vector containing the * betweenness scores for the edges. * \param directed Logical, if true directed paths will be considered * for directed graphs. It is ignored for undirected graphs. * \param cutoff The maximal length of paths that will be considered. * If zero or negative, the exact betweenness will be calculated * (no upper limit on path lengths). * \return Error code: * \c IGRAPH_ENOMEM, not enough memory for * temporary data. * * Time complexity: O(|V||E|), * |V| and * |E| are the number of vertices and * edges in the graph. * * \sa Other centrality types: \ref igraph_degree(), \ref igraph_closeness(). * See \ref igraph_betweenness() for calculating the betweenness score * of the vertices in a graph. */ int igraph_edge_betweenness_estimate(const igraph_t *graph, igraph_vector_t *result, igraph_bool_t directed, igraph_integer_t cutoff) { long int no_of_nodes=igraph_vcount(graph); long int no_of_edges=igraph_ecount(graph); igraph_dqueue_t q=IGRAPH_DQUEUE_NULL; long int *distance; long int *nrgeo; double *tmpscore; igraph_stack_t stack=IGRAPH_STACK_NULL; long int source; long int j; igraph_adjedgelist_t elist_out, elist_in; igraph_adjedgelist_t *elist_out_p, *elist_in_p; igraph_vector_t *neip; long int neino; long int i; igraph_integer_t modein, modeout; directed=directed && igraph_is_directed(graph); if (directed) { modeout=IGRAPH_OUT; modein=IGRAPH_IN; IGRAPH_CHECK(igraph_adjedgelist_init(graph, &elist_out, IGRAPH_OUT)); IGRAPH_FINALLY(igraph_adjedgelist_destroy, &elist_out); IGRAPH_CHECK(igraph_adjedgelist_init(graph, &elist_in, IGRAPH_IN)); IGRAPH_FINALLY(igraph_adjedgelist_destroy, &elist_in); elist_out_p=&elist_out; elist_in_p=&elist_in; } else { modeout=modein=IGRAPH_ALL; IGRAPH_CHECK(igraph_adjedgelist_init(graph,&elist_out, IGRAPH_ALL)); IGRAPH_FINALLY(igraph_adjedgelist_destroy, &elist_out); elist_out_p=elist_in_p=&elist_out; } distance=igraph_Calloc(no_of_nodes, long int); if (distance==0) { IGRAPH_ERROR("edge betweenness failed", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, distance); nrgeo=igraph_Calloc(no_of_nodes, long int); if (nrgeo==0) { IGRAPH_ERROR("edge betweenness failed", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, nrgeo); tmpscore=igraph_Calloc(no_of_nodes, double); if (tmpscore==0) { IGRAPH_ERROR("edge betweenness failed", IGRAPH_ENOMEM); } IGRAPH_FINALLY(igraph_free, tmpscore); IGRAPH_DQUEUE_INIT_FINALLY(&q, 100); IGRAPH_CHECK(igraph_stack_init(&stack, no_of_nodes)); IGRAPH_FINALLY(igraph_stack_destroy, &stack); IGRAPH_CHECK(igraph_vector_resize(result, no_of_edges)); igraph_vector_null(result); /* here we go */ for (source=0; source<no_of_nodes; source++) { IGRAPH_PROGRESS("Edge betweenness centrality: ", 100.0*source/no_of_nodes, 0); IGRAPH_ALLOW_INTERRUPTION(); memset(distance, 0, no_of_nodes*sizeof(long int)); memset(nrgeo, 0, no_of_nodes*sizeof(long int)); memset(tmpscore, 0, no_of_nodes*sizeof(double)); igraph_stack_clear(&stack); /* it should be empty anyway... */ IGRAPH_CHECK(igraph_dqueue_push(&q, source)); nrgeo[source]=1; distance[source]=0; while (!igraph_dqueue_empty(&q)) { long int actnode=igraph_dqueue_pop(&q); if (cutoff > 0 && distance[actnode] >= cutoff ) continue; neip=igraph_adjedgelist_get(elist_out_p, actnode); neino=igraph_vector_size(neip); for (i=0; i<neino; i++) { igraph_integer_t edge=VECTOR(*neip)[i], from, to; long int neighbor; igraph_edge(graph, edge, &from, &to); neighbor = actnode!=from ? from : to; if (nrgeo[neighbor] != 0) { /* we've already seen this node, another shortest path? */ if (distance[neighbor]==distance[actnode]+1) { nrgeo[neighbor]+=nrgeo[actnode]; } } else { /* we haven't seen this node yet */ nrgeo[neighbor]+=nrgeo[actnode]; distance[neighbor]=distance[actnode]+1; IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor)); IGRAPH_CHECK(igraph_stack_push(&stack, neighbor)); } } } /* while !igraph_dqueue_empty */ /* Ok, we've the distance of each node and also the number of shortest paths to them. Now we do an inverse search, starting with the farthest nodes. */ while (!igraph_stack_empty(&stack)) { long int actnode=igraph_stack_pop(&stack); if (distance[actnode]<1) { continue; } /* skip source node */ /* set the temporary score of the friends */ neip=igraph_adjedgelist_get(elist_in_p, actnode); neino=igraph_vector_size(neip); for (i=0; i<neino; i++) { igraph_integer_t from, to; long int neighbor; long int edgeno=VECTOR(*neip)[i]; igraph_edge(graph, edgeno, &from, &to); neighbor= actnode != from ? from : to; if (distance[neighbor]==distance[actnode]-1 && nrgeo[neighbor] != 0) { tmpscore[neighbor] += (tmpscore[actnode]+1)*nrgeo[neighbor]/nrgeo[actnode]; VECTOR(*result)[edgeno] += (tmpscore[actnode]+1)*nrgeo[neighbor]/nrgeo[actnode]; } } } /* Ok, we've the scores for this source */ } /* for source <= no_of_nodes */ IGRAPH_PROGRESS("Edge betweenness centrality: ", 100.0, 0); /* clean and return */ igraph_Free(distance); igraph_Free(nrgeo); igraph_Free(tmpscore); igraph_dqueue_destroy(&q); igraph_stack_destroy(&stack); IGRAPH_FINALLY_CLEAN(5); if (directed) { igraph_adjedgelist_destroy(&elist_out); igraph_adjedgelist_destroy(&elist_in); IGRAPH_FINALLY_CLEAN(2); } else { igraph_adjedgelist_destroy(&elist_out); IGRAPH_FINALLY_CLEAN(1); } /* divide by 2 for undirected graph */ if (!directed || !igraph_is_directed(graph)) { for (j=0; j<igraph_vector_size(result); j++) { VECTOR(*result)[j] /= 2.0; } } return 0; }