int igraph_i_is_separator(const igraph_t *graph, igraph_vit_t *vit, long int except, igraph_bool_t *res, igraph_vector_bool_t *removed, igraph_dqueue_t *Q, igraph_vector_t *neis, long int no_of_nodes) { long int start=0; if (IGRAPH_VIT_SIZE(*vit) >= no_of_nodes-1) { /* Just need to check that we really have at least n-1 vertices in it */ igraph_vector_bool_t hit; long int nohit=0; IGRAPH_CHECK(igraph_vector_bool_init(&hit, no_of_nodes)); IGRAPH_FINALLY(igraph_vector_bool_destroy, &hit); for (IGRAPH_VIT_RESET(*vit); !IGRAPH_VIT_END(*vit); IGRAPH_VIT_NEXT(*vit)) { long int v=IGRAPH_VIT_GET(*vit); if (!VECTOR(hit)[v]) { nohit++; VECTOR(hit)[v] = 1; } } igraph_vector_bool_destroy(&hit); IGRAPH_FINALLY_CLEAN(1); if (nohit >= no_of_nodes-1) { *res = 0; return 0; } } /* Remove the given vertices from the graph, do a breadth-first search and check the number of components */ if (except < 0) { for (IGRAPH_VIT_RESET(*vit); !IGRAPH_VIT_END(*vit); IGRAPH_VIT_NEXT(*vit)) { VECTOR(*removed)[ (long int) IGRAPH_VIT_GET(*vit) ] = 1; } } else { /* There is an exception */ long int i; for (i=0, IGRAPH_VIT_RESET(*vit); i<except; i++, IGRAPH_VIT_NEXT(*vit)) { VECTOR(*removed)[ (long int) IGRAPH_VIT_GET(*vit) ] = 1; } for (IGRAPH_VIT_NEXT(*vit); !IGRAPH_VIT_END(*vit); IGRAPH_VIT_NEXT(*vit)) { VECTOR(*removed)[ (long int) IGRAPH_VIT_GET(*vit) ] = 1; } } /* Look for the first node that is not removed */ while (start < no_of_nodes && VECTOR(*removed)[start]) start++; if (start==no_of_nodes) { IGRAPH_ERROR("All vertices are included in the separator", IGRAPH_EINVAL); } igraph_dqueue_push(Q, start); VECTOR(*removed)[start]=1; while (!igraph_dqueue_empty(Q)) { long int node=(long int) igraph_dqueue_pop(Q); long int j, n; igraph_neighbors(graph, neis, (igraph_integer_t) node, IGRAPH_ALL); n=igraph_vector_size(neis); for (j=0; j<n; j++) { long int nei=(long int) VECTOR(*neis)[j]; if (!VECTOR(*removed)[nei]) { IGRAPH_CHECK(igraph_dqueue_push(Q, nei)); VECTOR(*removed)[nei]=1; } } } /* Look for the next node that was neighter removed, not visited */ while (start < no_of_nodes && VECTOR(*removed)[start]) start++; /* If there is another component, then we have a separator */ *res = (start < no_of_nodes); return 0; }
int igraph_pagerank(const igraph_t *graph, igraph_vector_t *vector, igraph_real_t *value, const igraph_vs_t vids, igraph_bool_t directed, igraph_real_t damping, const igraph_vector_t *weights, igraph_arpack_options_t *options) { igraph_matrix_t values; igraph_matrix_t vectors; igraph_integer_t dirmode; igraph_vector_t outdegree; igraph_vector_t tmp; long int i; long int no_of_nodes=igraph_vcount(graph); long int no_of_edges=igraph_ecount(graph); options->n = igraph_vcount(graph); options->nev = 1; options->ncv = 3; options->which[0]='L'; options->which[1]='M'; options->start=1; /* no random start vector */ directed = directed && igraph_is_directed(graph); if (weights && igraph_vector_size(weights) != igraph_ecount(graph)) { IGRAPH_ERROR("Invalid length of weights vector when calculating " "PageRank scores", IGRAPH_EINVAL); } IGRAPH_MATRIX_INIT_FINALLY(&values, 0, 0); IGRAPH_MATRIX_INIT_FINALLY(&vectors, options->n, 1); if (directed) { dirmode=IGRAPH_IN; } else { dirmode=IGRAPH_ALL; } IGRAPH_VECTOR_INIT_FINALLY(&outdegree, options->n); IGRAPH_VECTOR_INIT_FINALLY(&tmp, options->n); RNG_BEGIN(); if (!weights) { igraph_adjlist_t adjlist; igraph_i_pagerank_data_t data = { graph, &adjlist, damping, &outdegree, &tmp }; IGRAPH_CHECK(igraph_degree(graph, &outdegree, igraph_vss_all(), directed ? IGRAPH_OUT : IGRAPH_ALL, /*loops=*/ 0)); /* Avoid division by zero */ for (i=0; i<options->n; i++) { if (VECTOR(outdegree)[i]==0) { VECTOR(outdegree)[i]=1; } MATRIX(vectors, i, 0) = VECTOR(outdegree)[i]; } IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, dirmode)); IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist); IGRAPH_CHECK(igraph_arpack_rnsolve(igraph_i_pagerank, &data, options, 0, &values, &vectors)); igraph_adjlist_destroy(&adjlist); IGRAPH_FINALLY_CLEAN(1); } else { igraph_adjedgelist_t adjedgelist; igraph_i_pagerank_data2_t data = { graph, &adjedgelist, weights, damping, &outdegree, &tmp }; IGRAPH_CHECK(igraph_adjedgelist_init(graph, &adjedgelist, dirmode)); IGRAPH_FINALLY(igraph_adjedgelist_destroy, &adjedgelist); /* Weighted degree */ for (i=0; i<no_of_edges; i++) { long int from=IGRAPH_FROM(graph, i); long int to=IGRAPH_TO(graph, i); igraph_real_t weight=VECTOR(*weights)[i]; VECTOR(outdegree)[from] += weight; if (!directed) { VECTOR(outdegree)[to] += weight; } } /* Avoid division by zero */ for (i=0; i<options->n; i++) { if (VECTOR(outdegree)[i]==0) { VECTOR(outdegree)[i]=1; } MATRIX(vectors, i, 0) = VECTOR(outdegree)[i]; } IGRAPH_CHECK(igraph_arpack_rnsolve(igraph_i_pagerank2, &data, options, 0, &values, &vectors)); igraph_adjedgelist_destroy(&adjedgelist); IGRAPH_FINALLY_CLEAN(1); } RNG_END(); igraph_vector_destroy(&tmp); igraph_vector_destroy(&outdegree); IGRAPH_FINALLY_CLEAN(2); if (value) { *value=MATRIX(values, 0, 0); } if (vector) { long int i; igraph_vit_t vit; long int nodes_to_calc; igraph_real_t sum=0; for (i=0; i<no_of_nodes; i++) { sum += MATRIX(vectors, i, 0); } IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit)); IGRAPH_FINALLY(igraph_vit_destroy, &vit); nodes_to_calc=IGRAPH_VIT_SIZE(vit); IGRAPH_CHECK(igraph_vector_resize(vector, nodes_to_calc)); for (IGRAPH_VIT_RESET(vit), i=0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { VECTOR(*vector)[i] = MATRIX(vectors, (long int)IGRAPH_VIT_GET(vit), 0); VECTOR(*vector)[i] /= sum; } igraph_vit_destroy(&vit); IGRAPH_FINALLY_CLEAN(1); } if (options->info) { IGRAPH_WARNING("Non-zero return code from ARPACK routine!"); } igraph_matrix_destroy(&vectors); igraph_matrix_destroy(&values); IGRAPH_FINALLY_CLEAN(2); 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_closeness_estimate * \brief Closeness centrality estimations for some vertices. * * </para><para> * The closeness centrality of a vertex measures how easily other * vertices can be reached from it (or the other way: how easily it * can be reached from the other vertices). It is defined as the * number of the number of vertices minus one divided by the sum of the * lengths of all geodesics from/to the given vertex. When estimating * closeness centrality, igraph considers paths having a length less than * or equal to a prescribed cutoff value. * * </para><para> * If the graph is not connected, and there is no such path between two * vertices, the number of vertices is used instead the length of the * geodesic. This is always longer than the longest possible geodesic. * * </para><para> * Since the estimation considers vertex pairs with a distance greater than * the given value as disconnected, the resulting estimation will always be * lower than the actual closeness centrality. * * \param graph The graph object. * \param res The result of the computation, a vector containing the * closeness centrality scores for the given vertices. * \param vids Vector giving the vertices for which the closeness * centrality scores will be computed. * \param mode The type of shortest paths to be used for the * calculation in directed graphs. Possible values: * \clist * \cli IGRAPH_OUT * the lengths of the outgoing paths are calculated. * \cli IGRAPH_IN * the lengths of the incoming paths are calculated. * \cli IGRAPH_ALL * the directed graph is considered as an * undirected one for the computation. * \endclist * \param cutoff The maximal length of paths that will be considered. * If zero or negative, the exact closeness will be calculated * (no upper limit on path lengths). * \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(n|E|), * n is the number * of vertices for which the calculation is done and * |E| is the number * of edges in the graph. * * \sa Other centrality types: \ref igraph_degree(), \ref igraph_betweenness(). */ int igraph_closeness_estimate(const igraph_t *graph, igraph_vector_t *res, const igraph_vs_t vids, igraph_neimode_t mode, igraph_integer_t cutoff) { long int no_of_nodes=igraph_vcount(graph); igraph_vector_t already_counted, *neis; long int i, j; long int nodes_reached; igraph_adjlist_t allneis; igraph_dqueue_t q; long int nodes_to_calc; igraph_vit_t vit; IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit)); IGRAPH_FINALLY(igraph_vit_destroy, &vit); nodes_to_calc=IGRAPH_VIT_SIZE(vit); if (mode != IGRAPH_OUT && mode != IGRAPH_IN && mode != IGRAPH_ALL) { IGRAPH_ERROR("calculating closeness", IGRAPH_EINVMODE); } IGRAPH_VECTOR_INIT_FINALLY(&already_counted, no_of_nodes); IGRAPH_DQUEUE_INIT_FINALLY(&q, 100); IGRAPH_CHECK(igraph_adjlist_init(graph, &allneis, mode)); IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis); IGRAPH_CHECK(igraph_vector_resize(res, nodes_to_calc)); igraph_vector_null(res); for (IGRAPH_VIT_RESET(vit), i=0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) { IGRAPH_CHECK(igraph_dqueue_push(&q, IGRAPH_VIT_GET(vit))); IGRAPH_CHECK(igraph_dqueue_push(&q, 0)); nodes_reached=1; VECTOR(already_counted)[(long int)IGRAPH_VIT_GET(vit)]=i+1; IGRAPH_PROGRESS("Closeness: ", 100.0*i/no_of_nodes, NULL); IGRAPH_ALLOW_INTERRUPTION(); while (!igraph_dqueue_empty(&q)) { long int act=igraph_dqueue_pop(&q); long int actdist=igraph_dqueue_pop(&q); VECTOR(*res)[i] += actdist; if (cutoff>0 && actdist>=cutoff) continue; neis=igraph_adjlist_get(&allneis, act); for (j=0; j<igraph_vector_size(neis); j++) { long int neighbor=VECTOR(*neis)[j]; if (VECTOR(already_counted)[neighbor] == i+1) { continue; } VECTOR(already_counted)[neighbor] = i+1; nodes_reached++; IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor)); IGRAPH_CHECK(igraph_dqueue_push(&q, actdist+1)); } } VECTOR(*res)[i] += ((igraph_integer_t)no_of_nodes * (no_of_nodes-nodes_reached)); VECTOR(*res)[i] = (no_of_nodes-1) / VECTOR(*res)[i]; } IGRAPH_PROGRESS("Closeness: ", 100.0, NULL); /* Clean */ igraph_dqueue_destroy(&q); igraph_vector_destroy(&already_counted); igraph_vit_destroy(&vit); igraph_adjlist_destroy(&allneis); IGRAPH_FINALLY_CLEAN(4); return 0; }