Exemple #1
0
static int igraph_i_bridges_rec(const igraph_t *graph, const igraph_inclist_t *il, igraph_integer_t u, igraph_integer_t *time, igraph_vector_t *bridges, igraph_vector_bool_t *visited, igraph_vector_int_t *disc, igraph_vector_int_t *low, igraph_vector_int_t *parent) {
    igraph_vector_int_t *incedges;
    long nc; /* neighbour count */
    long i;

    VECTOR(*visited)[u] = 1;

    *time += 1;

    VECTOR(*disc)[u] = *time;
    VECTOR(*low)[u] = *time;

    incedges = igraph_inclist_get(il, u);
    nc = igraph_vector_int_size(incedges);
    for (i=0; i < nc; ++i) {
        long edge = (long) VECTOR(*incedges)[i];
        igraph_integer_t v = IGRAPH_TO(graph, edge) == u ? IGRAPH_FROM(graph, edge) : IGRAPH_TO(graph, edge);

        if (! VECTOR(*visited)[v]) {
            VECTOR(*parent)[v] = u;
            IGRAPH_CHECK(igraph_i_bridges_rec(graph, il, v, time, bridges, visited, disc, low, parent));

            VECTOR(*low)[u] = VECTOR(*low)[u] < VECTOR(*low)[v] ? VECTOR(*low)[u] : VECTOR(*low)[v];

            if (VECTOR(*low)[v] > VECTOR(*disc)[u])
                IGRAPH_CHECK(igraph_vector_push_back(bridges, edge));
        }
        else if (v != VECTOR(*parent)[u]) {
            VECTOR(*low)[u] = VECTOR(*low)[u] < VECTOR(*disc)[v] ? VECTOR(*low)[u] : VECTOR(*disc)[v];
        }
    }

    return IGRAPH_SUCCESS;
}
Exemple #2
0
/**
 * \ingroup structural
 * \function igraph_similarity_jaccard_es
 * \brief Jaccard similarity coefficient for a given edge selector.
 *
 * </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 the endpoints of edges in a given edge
 * selector.
 *
 * \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 edges in \p es.
 * \param es An edge selector that specifies the edges to be included in the
 *        result.
 * \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 edges in the edge selector, d is
 * the (maximum) degree of the vertices in the graph.
 *
 * \sa \ref igraph_similarity_jaccard() and \ref igraph_similarity_jaccard_pairs()
 *   to calculate the Jaccard similarity between all pairs of a vertex set or
 *   some selected vertex pairs, or \ref igraph_similarity_dice(),
 *   \ref igraph_similarity_dice_pairs() and \ref igraph_similarity_dice_es() for a
 *   measure very similar to the Jaccard coefficient
 * 
 * \example examples/simple/igraph_similarity.c
 */
int igraph_similarity_jaccard_es(const igraph_t *graph, igraph_vector_t *res,
	const igraph_es_t es, igraph_neimode_t mode, igraph_bool_t loops) {
  igraph_vector_t v;
  igraph_eit_t eit;

  IGRAPH_VECTOR_INIT_FINALLY(&v, 0);

  IGRAPH_CHECK(igraph_eit_create(graph, es, &eit));
  IGRAPH_FINALLY(igraph_eit_destroy, &eit);

  while (!IGRAPH_EIT_END(eit)) {
    long int eid = IGRAPH_EIT_GET(eit);
    igraph_vector_push_back(&v, IGRAPH_FROM(graph, eid));
    igraph_vector_push_back(&v, IGRAPH_TO(graph, eid));
    IGRAPH_EIT_NEXT(eit);
  }

  igraph_eit_destroy(&eit);
  IGRAPH_FINALLY_CLEAN(1);

  IGRAPH_CHECK(igraph_similarity_jaccard_pairs(graph, res, &v, mode, loops));
  igraph_vector_destroy(&v);
  IGRAPH_FINALLY_CLEAN(1);

  return IGRAPH_SUCCESS;
}
Exemple #3
0
void print_edges(const igraph_t *graph) {
    long ecount = igraph_ecount(graph);
    long i;

    for (i=0; i < ecount; ++i)
        printf("%d %d\n", IGRAPH_FROM(graph, i), IGRAPH_TO(graph, i));
    printf("\n");
}
int check_evecs(const igraph_t *graph, const igraph_vector_ptr_t *vecs,
		const igraph_vector_ptr_t *evecs, int error_code) {

  igraph_bool_t directed=igraph_is_directed(graph);
  long int i, n=igraph_vector_ptr_size(vecs);
  if (igraph_vector_ptr_size(evecs) != n) { exit(error_code+1); }
  
  for (i=0; i<n; i++) {
    igraph_vector_t *vvec=VECTOR(*vecs)[i];
    igraph_vector_t *evec=VECTOR(*evecs)[i];
    long int j, n2=igraph_vector_size(evec);
    if (igraph_vector_size(vvec) == 0 && n2==0) { continue; }
    if (igraph_vector_size(vvec) != n2+1) { exit(error_code+2); }
    for (j=0; j<n2; j++) {
      long int edge=VECTOR(*evec)[j];
      long int from=VECTOR(*vvec)[j];
      long int to=VECTOR(*vvec)[j+1];
      if (directed) {
	if (from != IGRAPH_FROM(graph, edge) ||
	    to   != IGRAPH_TO  (graph, edge)) {
	  exit(error_code);
	}
      } else {
	long int from2=IGRAPH_FROM(graph, edge);
	long int to2=IGRAPH_TO(graph, edge);
	long int min1= from < to ? from : to;
	long int max1= from < to ? to : from;
	long int min2= from2 < to2 ? from2 : to2;
	long int max2= from2 < to2 ? to2 : from2;
	if (min1 != min2 || max1 != max2) { exit(error_code+3); }
      }
    }
  }

  return 0;
}
Exemple #5
0
/* Convert an igraph graph to a Cliquer graph */
static void igraph_to_cliquer(const igraph_t *ig, graph_t **cg) {
    igraph_integer_t vcount, ecount;
    int i;

    if (igraph_is_directed(ig))
      IGRAPH_WARNING("Edge directions are ignored for clique calculations");

    vcount = igraph_vcount(ig);
    ecount = igraph_ecount(ig);

    *cg = graph_new(vcount);

    for (i=0; i < ecount; ++i) {
        long s, t;
        s = IGRAPH_FROM(ig, i);
        t = IGRAPH_TO(ig, i);
        if (s != t)
            GRAPH_ADD_EDGE(*cg, s, t);
    }
}
int igraph_edges(const igraph_t *graph, igraph_es_t eids,
		 igraph_vector_t *edges) {
  
  igraph_eit_t eit;
  long int n, ptr=0;

  IGRAPH_CHECK(igraph_eit_create(graph, eids, &eit));
  IGRAPH_FINALLY(igraph_eit_destroy, &eit);
  n=IGRAPH_EIT_SIZE(eit);
  IGRAPH_CHECK(igraph_vector_resize(edges, n*2));
  for (; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) {
    long int e=IGRAPH_EIT_GET(eit);
    VECTOR(*edges)[ptr++]=IGRAPH_FROM(graph, e);
    VECTOR(*edges)[ptr++]=IGRAPH_TO(graph, e);
  }
  
  igraph_eit_destroy(&eit);
  IGRAPH_FINALLY_CLEAN(1);
  return 0;
}
Exemple #7
0
int igraph_inclist_remove_duplicate(const igraph_t *graph, 
					igraph_inclist_t *al) {
  long int i;
  long int n=al->length;
  for (i=0; i<n; i++) {
    igraph_vector_t *v=&al->incs[i];
    long int j, p=1, l=igraph_vector_size(v);
    for (j=1; j<l; j++) {
      long int e=VECTOR(*v)[j];
      /* Non-loop edges and one end of loop edges are fine. */
      /* We use here, that the vector is sorted and we also keep it sorted */
      if (IGRAPH_FROM(graph, e) != IGRAPH_TO(graph, e) ||
	  VECTOR(*v)[j-1] != e) {
	VECTOR(*v)[p++] = e;
      }
    }
    igraph_vector_resize(v, p);
  }
  
  return 0;
}
int igraph_revolver_mes_p_p(const igraph_t *graph,
                            igraph_lazy_inclist_t *inclist,
                            igraph_matrix_t *kernel,
                            igraph_matrix_t *sd,
                            igraph_matrix_t *norm,
                            igraph_matrix_t *cites,
                            const igraph_matrix_t *debug,
                            igraph_vector_ptr_t *debugres,
                            const igraph_vector_t *st,
                            const igraph_vector_t *vtime,
                            const igraph_vector_t *vtimeidx,
                            const igraph_vector_t *etime,
                            const igraph_vector_t *etimeidx,
                            igraph_integer_t pno_of_events,
                            const igraph_vector_t *authors,
                            const igraph_vector_t *eventsizes,
                            igraph_integer_t pmaxpapers) {

    long int no_of_nodes=igraph_vcount(graph);
    long int no_of_edges=igraph_ecount(graph);
    long int no_of_events=pno_of_events;
    long int maxpapers=pmaxpapers;

    igraph_vector_long_t papers;
    igraph_vector_char_t added;

    igraph_matrix_t v_normfact, *normfact, v_notnull, *notnull;
    igraph_matrix_t ch;

    igraph_vector_long_t ntk;
    igraph_matrix_t ntkk;

    igraph_vector_t *adjedges;

    long int timestep, i;
    long int nptr=0, eptr=0, aptr=0;
    long int nptr_save, eptr_save, eptr_new;

    IGRAPH_CHECK(igraph_vector_long_init(&papers, no_of_nodes));
    IGRAPH_FINALLY(&igraph_vector_long_destroy, &papers);

    IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_edges));
    IGRAPH_FINALLY(igraph_vector_char_destroy, &added);

    IGRAPH_CHECK(igraph_vector_long_init(&ntk, maxpapers+1));
    IGRAPH_FINALLY(igraph_vector_long_destroy, &ntk);
    IGRAPH_MATRIX_INIT_FINALLY(&ntkk, maxpapers+1, maxpapers+1);
    IGRAPH_MATRIX_INIT_FINALLY(&ch, maxpapers+1, maxpapers+1);

    if (norm) {
        normfact=norm;
        IGRAPH_CHECK(igraph_matrix_resize(normfact, maxpapers+1, maxpapers+1));
        igraph_matrix_null(normfact);
    } else {
        normfact=&v_normfact;
        IGRAPH_MATRIX_INIT_FINALLY(normfact, maxpapers+1, maxpapers+1);
    }

    if (cites) {
        notnull=cites;
        IGRAPH_CHECK(igraph_matrix_resize(notnull, maxpapers+1, maxpapers+1));
        igraph_matrix_null(notnull);
    } else {
        notnull=&v_notnull;
        IGRAPH_MATRIX_INIT_FINALLY(notnull, maxpapers+1, maxpapers+1);
    }

    IGRAPH_CHECK(igraph_matrix_resize(kernel, maxpapers+1, maxpapers+1));
    igraph_matrix_null(kernel);
    if (sd) {
        IGRAPH_CHECK(igraph_matrix_resize(sd, maxpapers+1, maxpapers+1));
        igraph_matrix_null(sd);
    }

    for (timestep=0; timestep<no_of_events; timestep++) {

        IGRAPH_ALLOW_INTERRUPTION();

        nptr_save=nptr;
        while (nptr < no_of_nodes &&
                VECTOR(*vtime)[(long int)VECTOR(*vtimeidx)[nptr]]==timestep) {
            nptr++;
        }
        /* If it is a new author then she has no papers yet */
        VECTOR(ntk)[0] += (nptr-nptr_save);

        /* Update ch accordingly, could be done later as well */
        if (VECTOR(ntk)[0] == nptr-nptr_save && nptr!=nptr_save) {
            if (nptr-nptr_save >= 2) {
                MATRIX(ch, 0, 0) = eptr;
            }
            for (i=1; i<maxpapers+1; i++) {
                if (NTKK(0,i) == (nptr-nptr_save)*VECTOR(ntk)[i]) {
                    MATRIX(ch, 0, i) = MATRIX(ch, i, 0) = eptr;
                }
            }
        }

        /*     print_ntkk(&ntkk, &ntk); */

        /* Estimate Akk */
        eptr_save=eptr;
        while (eptr < no_of_edges &&
                VECTOR(*etime)[(long int)VECTOR(*etimeidx)[eptr] ] == timestep) {
            long int edge=(long int) VECTOR(*etimeidx)[eptr];
            long int from=IGRAPH_FROM(graph, edge), to=IGRAPH_TO(graph, edge);
            long int xidx=VECTOR(papers)[from];
            long int yidx=VECTOR(papers)[to];
            double xk, oldakk;

            MATRIX(*notnull, xidx, yidx) += 1;
            MATRIX(*notnull, yidx, xidx) = MATRIX(*notnull, xidx, yidx);

            xk=VECTOR(*st)[timestep]/NTKK(xidx, yidx);
            oldakk=MATRIX(*kernel, xidx, yidx);
            MATRIX(*kernel, xidx, yidx) +=  (xk-oldakk)/MATRIX(*notnull, xidx, yidx);
            MATRIX(*kernel, yidx, xidx) = MATRIX(*kernel, xidx, yidx);
            if (sd) {
                MATRIX(*sd, xidx, yidx) += (xk-oldakk)*(xk-MATRIX(*kernel, xidx, yidx));
                MATRIX(*sd, yidx, xidx) = MATRIX(*sd, xidx, yidx);
            }
            /* TODO: debug */

            eptr++;
        }

        /* update ntkk, the new papers change the type of their authors */
        eptr_new=eptr;
        for (i=aptr; i<aptr+VECTOR(*eventsizes)[timestep]; i++) {
            long int aut=(long int) VECTOR(*authors)[i];
            long int pap=VECTOR(papers)[aut];
            long int j, n;

            adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) aut);
            n=igraph_vector_size(adjedges);
            for (j=0; j<n; j++) {
                long int edge=(long int) VECTOR(*adjedges)[j];
                if (VECTOR(added)[edge]) {
                    long int otherv=IGRAPH_OTHER(graph, edge, aut);
                    long int otherpap=VECTOR(papers)[otherv];
                    MATRIX(ntkk, pap, otherpap) -= 1;
                    MATRIX(ntkk, otherpap, pap) = MATRIX(ntkk, pap, otherpap);
                    if (NTKK(pap, otherpap)==1) {
                        MATRIX(ch, pap, otherpap) = eptr_new;
                        MATRIX(ch, otherpap, pap) = MATRIX(ch, pap, otherpap);
                    }
                    MATRIX(ntkk, pap+1, otherpap) += 1;
                    MATRIX(ntkk, otherpap, pap+1) = MATRIX(ntkk, pap+1, otherpap);
                    if (NTKK(pap+1, otherpap)==0) {
                        MATRIX(*normfact, pap+1, otherpap) +=
                            eptr_new-MATRIX(ch, pap+1, otherpap);
                        MATRIX(*normfact, otherpap, pap+1) =
                            MATRIX(*normfact, pap+1, otherpap);
                    }
                }
            }

            /* update ntk too */
            for (j=0; j<maxpapers+1; j++) {
                long int before, after;
                before=(long int) NTKK(pap, j);
                VECTOR(ntk)[pap]-=1;
                after=(long int) NTKK(pap, j);
                VECTOR(ntk)[pap]+=1;
                if (before > 0 && after==0) {
                    MATRIX(*normfact, pap, j) += eptr_new-MATRIX(ch, pap, j);
                    MATRIX(*normfact, j, pap) = MATRIX(*normfact, pap, j);
                }
            }
            VECTOR(ntk)[pap]-=1;

            for (j=0; j<maxpapers+1; j++) {
                long int before, after;
                before=(long int) NTKK(pap+1, j);
                VECTOR(ntk)[pap+1] += 1;
                after=(long int) NTKK(pap+1, j);
                VECTOR(ntk)[pap+1] -= 1;
                if (before == 0 && after > 0) {
                    MATRIX(ch, pap+1, j) = eptr_new;
                    MATRIX(ch, j, pap+1) = MATRIX(ch, pap+1, j);
                }
            }
            VECTOR(ntk)[pap+1]+=1;

            VECTOR(papers)[aut] += 1;
        }
        aptr += VECTOR(*eventsizes)[timestep];

        /* For every new edge, we lose one connection possibility, also add the edges*/
        eptr=eptr_save;
        while (eptr < no_of_edges &&
                VECTOR(*etime)[(long int) VECTOR(*etimeidx)[eptr] ] == timestep) {
            long int edge=(long int) VECTOR(*etimeidx)[eptr];
            long int from=IGRAPH_FROM(graph, edge), to=IGRAPH_TO(graph, edge);
            long int xidx=VECTOR(papers)[from];
            long int yidx=VECTOR(papers)[to];

            MATRIX(ntkk, xidx, yidx) += 1;
            MATRIX(ntkk, yidx, xidx) = MATRIX(ntkk, xidx, yidx);
            if (NTKK(xidx, yidx)==0) {
                MATRIX(*normfact, xidx, yidx) += eptr_new-MATRIX(ch, xidx, yidx);
                MATRIX(*normfact, yidx, xidx) = MATRIX(*normfact, xidx, yidx);
            }

            VECTOR(added)[edge]=1;
            eptr++;
        }
    }

    for (i=0; i<maxpapers+1; i++) {
        igraph_real_t oldakk;
        long int j;
        for (j=0; j<=i; j++) {
            if (NTKK(i, j) != 0) {
                MATRIX(*normfact, i, j) += (eptr-MATRIX(ch, i, j));
                MATRIX(*normfact, j, i) = MATRIX(*normfact, i, j);
            }
            if (MATRIX(*normfact, i, j)==0) {
                MATRIX(*kernel, i, j)=MATRIX(*kernel, j, i)=0;
                MATRIX(*normfact, i, j)=MATRIX(*normfact, j, i)=1;
            }
            oldakk=MATRIX(*kernel, i, j);
            MATRIX(*kernel, i, j) *= MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j);
            MATRIX(*kernel, j, i) = MATRIX(*kernel, i, j);
            if (sd) {
                MATRIX(*sd, i, j) += oldakk * oldakk * MATRIX(*notnull, i, j) *
                                     (1-MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j));
                MATRIX(*sd, i, j) = sqrt(MATRIX(*sd, i, j)/(MATRIX(*normfact, i, j)-1));
                MATRIX(*sd, j, i) = MATRIX(*sd, i, j);
            }
        }
    }

    if (!cites) {
        igraph_matrix_destroy(notnull);
        IGRAPH_FINALLY_CLEAN(1);
    }
    if (!norm) {
        igraph_matrix_destroy(normfact);
        IGRAPH_FINALLY_CLEAN(1);
    }

    igraph_matrix_destroy(&ch);
    igraph_matrix_destroy(&ntkk);
    igraph_vector_long_destroy(&ntk);
    igraph_vector_char_destroy(&added);
    igraph_vector_long_destroy(&papers);
    IGRAPH_FINALLY_CLEAN(5);

    return 0;
}
Exemple #9
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_revolver_st_d_d(const igraph_t *graph,
                           igraph_lazy_inclist_t *inclist,
                           igraph_vector_t *st,
                           const igraph_matrix_t *kernel,
                           const igraph_vector_t *vtime,
                           const igraph_vector_t *vtimeidx,
                           const igraph_vector_t *etime,
                           const igraph_vector_t *etimeidx,
                           igraph_integer_t pno_of_events) {

    long int no_of_events=pno_of_events;
    long int maxdegree=igraph_matrix_nrow(kernel)-1;
    long int no_of_nodes=igraph_vcount(graph);
    long int no_of_edges=igraph_ecount(graph);
    long int timestep=0;

    igraph_vector_long_t degree;
    igraph_vector_long_t ntk;
    igraph_vector_char_t added;

    igraph_vector_t *adjedges;

    long int i;
    long int nptr=0, eptr=0;

    IGRAPH_CHECK(igraph_vector_long_init(&ntk, maxdegree+1));
    IGRAPH_FINALLY(igraph_vector_long_destroy, &ntk);
    IGRAPH_CHECK(igraph_vector_long_init(&degree, no_of_nodes));
    IGRAPH_FINALLY(igraph_vector_long_destroy, &degree);
    IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_edges));
    IGRAPH_FINALLY(igraph_vector_char_destroy, &added);

    IGRAPH_CHECK(igraph_vector_resize(st, no_of_events));
    VECTOR(*st)[0]=0;

    for (timestep=0; timestep<no_of_events-1; timestep++) {

        IGRAPH_ALLOW_INTERRUPTION();

        /* add the new nodes */
        while (nptr < no_of_nodes &&
                VECTOR(*vtime)[ (long int) VECTOR(*vtimeidx)[nptr] ] == timestep) {
            for (i=0; i<maxdegree+1; i++) {
                VECTOR(*st)[timestep] += VECTOR(ntk)[i]*MATRIX(*kernel, i, 0);
            }
            VECTOR(ntk)[0]++;
            nptr++;
        }

        /* add the new edges as well, but this is for the next timestep
           already */
        VECTOR(*st)[timestep+1] = VECTOR(*st)[timestep];
        while (eptr < no_of_edges &&
                VECTOR(*etime)[ (long int) VECTOR(*etimeidx)[eptr] ] == timestep) {
            long int edge=(long int) VECTOR(*etimeidx)[eptr];
            long int from=IGRAPH_FROM(graph, edge);
            long int to=IGRAPH_TO(graph, edge);
            long int xidx=VECTOR(degree)[from];
            long int yidx=VECTOR(degree)[to];
            igraph_real_t inc=0;
            long int n;

            inc -= MATRIX(*kernel, xidx, yidx);

            for (i=0; i<maxdegree+1; i++) {
                inc += VECTOR(ntk)[i] * (MATRIX(*kernel, i, xidx+1) -
                                         MATRIX(*kernel, i, xidx)   +
                                         MATRIX(*kernel, i, yidx+1) -
                                         MATRIX(*kernel, i, yidx));
            }
            inc -= MATRIX(*kernel, xidx+1, xidx+1);
            inc -= MATRIX(*kernel, yidx+1, yidx+1);
            inc += MATRIX(*kernel, xidx, xidx);
            inc += MATRIX(*kernel, yidx, yidx);

            VECTOR(ntk)[xidx]--;
            VECTOR(ntk)[yidx]--;
            VECTOR(ntk)[xidx+1]++;
            VECTOR(ntk)[yidx+1]++;

            adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) from);
            n=igraph_vector_size(adjedges);
            for (i=0; i<n; i++) {
                long int edge=(long int) VECTOR(*adjedges)[i];
                if (VECTOR(added)[edge]) {
                    long int otherv=IGRAPH_OTHER(graph, edge, from);
                    long int deg=VECTOR(degree)[otherv];
                    inc += MATRIX(*kernel, xidx, deg);
                    inc -= MATRIX(*kernel, xidx+1, deg);
                }
            }
            adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) to);
            n=igraph_vector_size(adjedges);
            for (i=0; i<n; i++) {
                long int edge=(long int) VECTOR(*adjedges)[i];
                if (VECTOR(added)[edge]) {
                    long int otherv=IGRAPH_OTHER(graph, edge, to);
                    long int deg=VECTOR(degree)[otherv];
                    inc += MATRIX(*kernel, yidx, deg);
                    inc -= MATRIX(*kernel, yidx+1, deg);
                }
            }

            VECTOR(degree)[from] += 1;
            VECTOR(degree)[to] += 1;
            VECTOR(added)[edge]=1;

            VECTOR(*st)[timestep+1] += inc;

            eptr++;
        }
    }

    igraph_vector_char_destroy(&added);
    igraph_vector_long_destroy(&degree);
    igraph_vector_long_destroy(&ntk);
    IGRAPH_FINALLY_CLEAN(3);

    return 0;
}
int igraph_revolver_error_d_d(const igraph_t *graph,
                              igraph_lazy_inclist_t *inclist,
                              const igraph_matrix_t *kernel,
                              const igraph_vector_t *st,
                              const igraph_vector_t *vtime,
                              const igraph_vector_t *vtimeidx,
                              const igraph_vector_t *etime,
                              const igraph_vector_t *etimeidx,
                              igraph_integer_t pno_of_events,
                              igraph_integer_t pmaxdegree,
                              igraph_real_t *logprob,
                              igraph_real_t *lognull) {

    long int no_of_events=pno_of_events;
    long int no_of_nodes=igraph_vcount(graph);
    long int no_of_edges=igraph_ecount(graph);

    igraph_vector_long_t degree;

    long int timestep, nptr=0, eptr=0, eptr_save;
    long int edges=0, vertices=0;

    igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull;

    IGRAPH_CHECK(igraph_vector_long_init(&degree, no_of_nodes));
    IGRAPH_FINALLY(igraph_vector_long_destroy, &degree);

    if (!logprob) {
        mylogprob=&rlogprob;
    }
    if (!lognull) {
        mylognull=&rlognull;
    }

    *mylogprob=0;
    *mylognull=0;

    for (timestep=0; timestep<no_of_events; timestep++) {

        IGRAPH_ALLOW_INTERRUPTION();

        while (nptr < no_of_nodes &&
                VECTOR(*vtime)[ (long int) VECTOR(*vtimeidx)[nptr] ] == timestep) {
            vertices++;
            nptr++;
        }

        eptr_save=eptr;
        while (eptr < no_of_edges &&
                VECTOR(*etime)[ (long int) VECTOR(*etimeidx)[eptr] ] == timestep) {
            long int edge=(long int) VECTOR(*etimeidx)[eptr];
            long int from=IGRAPH_FROM(graph, edge);
            long int to=IGRAPH_TO(graph, edge);
            long int xidx=VECTOR(degree)[from];
            long int yidx=VECTOR(degree)[to];

            igraph_real_t prob=MATRIX(*kernel, xidx, yidx)/VECTOR(*st)[timestep];
            igraph_real_t nullprob=1.0/(vertices*(vertices-1)/2-eptr_save);

            *mylogprob += log(prob);
            *mylognull += log(nullprob);

            edges++;
            eptr++;
        }

        eptr=eptr_save;
        while (eptr < no_of_edges &&
                VECTOR(*etime)[ (long int) VECTOR(*etimeidx)[eptr] ] == timestep) {
            long int edge=(long int) VECTOR(*etimeidx)[eptr];
            long int from=IGRAPH_FROM(graph, edge);
            long int to=IGRAPH_TO(graph, edge);
            VECTOR(degree)[from] += 1;
            VECTOR(degree)[to] += 1;
            eptr++;
        }
    }

    igraph_vector_long_destroy(&degree);
    IGRAPH_FINALLY_CLEAN(1);

    return 0;
}
int igraph_revolver_st_p_p(const igraph_t *graph,
                           igraph_lazy_inclist_t *inclist,
                           igraph_vector_t *st,
                           const igraph_matrix_t *kernel,
                           const igraph_vector_t *vtime,
                           const igraph_vector_t *vtimeidx,
                           const igraph_vector_t *etime,
                           const igraph_vector_t *etimeidx,
                           igraph_integer_t pno_of_events,
                           const igraph_vector_t *authors,
                           const igraph_vector_t *eventsizes,
                           igraph_integer_t pmaxpapers) {

    long int no_of_events=pno_of_events;
    long int maxpapers=igraph_matrix_nrow(kernel)-1;
    long int no_of_nodes=igraph_vcount(graph);
    long int no_of_edges=igraph_ecount(graph);
    long int timestep=0;

    igraph_vector_long_t papers;
    igraph_vector_long_t ntk;
    igraph_vector_char_t added;

    igraph_vector_t *adjedges;

    long int i;
    long int nptr=0, eptr=0, aptr=0, nptr_save;

    IGRAPH_CHECK(igraph_vector_long_init(&ntk, maxpapers+1));
    IGRAPH_FINALLY(igraph_vector_long_destroy, &ntk);
    IGRAPH_CHECK(igraph_vector_long_init(&papers, no_of_nodes));
    IGRAPH_FINALLY(igraph_vector_long_destroy, &papers);
    IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_edges));
    IGRAPH_FINALLY(igraph_vector_char_destroy, &added);

    IGRAPH_CHECK(igraph_vector_resize(st, no_of_events));
    VECTOR(*st)[0]=0;

    for (timestep=0; timestep<no_of_events-1; timestep++) {

        IGRAPH_ALLOW_INTERRUPTION();

        /* add the new nodes */
        nptr_save=nptr;
        while (nptr < no_of_nodes &&
                VECTOR(*vtime)[ (long int) VECTOR(*vtimeidx)[nptr] ] == timestep) {
            nptr++;
        }
        nptr_save=nptr-nptr_save;
        if (nptr_save != 0) {
            for (i=0; i<maxpapers+1; i++) {
                VECTOR(*st)[timestep] += VECTOR(ntk)[i]*MATRIX(*kernel, i, 0)*nptr_save;
            }
            VECTOR(*st)[timestep] += nptr_save*(nptr_save-1)/2 * MATRIX(*kernel, 0, 0);
            VECTOR(ntk)[0]+=nptr_save;
        }

        VECTOR(*st)[timestep+1] = VECTOR(*st)[timestep];

        for (i=aptr; i<aptr+VECTOR(*eventsizes)[timestep]; i++) {
            long int aut=(long int) VECTOR(*authors)[i];
            long int pap=VECTOR(papers)[aut];
            long int j, n;

            for (j=0; j<maxpapers+1; j++) {
                VECTOR(*st)[timestep+1] += VECTOR(ntk)[j] * (MATRIX(*kernel, j, pap+1)-
                                           MATRIX(*kernel, j, pap));
            }

            VECTOR(*st)[timestep+1] += MATRIX(*kernel, pap, pap);
            VECTOR(*st)[timestep+1] -= MATRIX(*kernel, pap+1, pap+1);

            VECTOR(ntk)[pap]--;
            VECTOR(ntk)[pap+1]++;

            adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) aut);
            n=igraph_vector_size(adjedges);
            for (j=0; j<n; j++) {
                long int edge=(long int) VECTOR(*adjedges)[j];
                if (VECTOR(added)[edge]) {
                    long int otherv=IGRAPH_OTHER(graph, edge, aut);
                    long int otherpap=VECTOR(papers)[otherv];
                    VECTOR(*st)[timestep+1] += MATRIX(*kernel, pap, otherpap);
                    VECTOR(*st)[timestep+1] -= MATRIX(*kernel, pap+1, otherpap);
                }
            }

            VECTOR(papers)[aut] += 1;
        }
        aptr += VECTOR(*eventsizes)[timestep];

        while (eptr < no_of_edges &&
                VECTOR(*etime)[ (long int) VECTOR(*etimeidx)[eptr] ] == timestep) {
            long int edge=(long int) VECTOR(*etimeidx)[eptr];
            long int from=IGRAPH_FROM(graph, edge);
            long int to=IGRAPH_TO(graph, edge);
            long int xidx=VECTOR(papers)[from];
            long int yidx=VECTOR(papers)[to];
            VECTOR(*st)[timestep+1] -= MATRIX(*kernel, xidx, yidx);
            VECTOR(added)[edge]=1;
            eptr++;
        }

    }

    igraph_vector_char_destroy(&added);
    igraph_vector_long_destroy(&papers);
    igraph_vector_long_destroy(&ntk);
    IGRAPH_FINALLY_CLEAN(3);

    return 0;
}
int igraph_revolver_mes_d_d(const igraph_t *graph,
                            igraph_lazy_inclist_t *inclist,
                            igraph_matrix_t *kernel,
                            igraph_matrix_t *sd,
                            igraph_matrix_t *norm,
                            igraph_matrix_t *cites,
                            const igraph_matrix_t *debug,
                            igraph_vector_ptr_t *debugres,
                            const igraph_vector_t *st,
                            const igraph_vector_t *vtime,
                            const igraph_vector_t *vtimeidx,
                            const igraph_vector_t *etime,
                            const igraph_vector_t *etimeidx,
                            igraph_integer_t pno_of_events,
                            igraph_integer_t pmaxdegree) {

    long int no_of_nodes=igraph_vcount(graph);
    long int no_of_edges=igraph_ecount(graph);
    long int no_of_events=pno_of_events;
    long int maxdegree=pmaxdegree;

    igraph_vector_long_t degree;
    igraph_vector_char_t added;	/* is this edge already in the network? */

    igraph_matrix_t v_normfact, *normfact, v_notnull, *notnull;
    igraph_matrix_t ch;

    igraph_vector_long_t ntk;	/* # of type x vertices */
    igraph_matrix_t ntkk;	        /* # of connections between type x1, x2 vert. */

    igraph_vector_t *adjedges;

    long int timestep, i;
    long int nptr=0, eptr=0;
    long int nptr_save, eptr_save, eptr_new;

    IGRAPH_CHECK(igraph_vector_long_init(&degree, no_of_nodes));
    IGRAPH_FINALLY(&igraph_vector_long_destroy, &degree);

    IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_edges));
    IGRAPH_FINALLY(igraph_vector_char_destroy, &added);

    IGRAPH_CHECK(igraph_vector_long_init(&ntk, maxdegree+1));
    IGRAPH_FINALLY(igraph_vector_long_destroy, &ntk);
    IGRAPH_MATRIX_INIT_FINALLY(&ntkk, maxdegree+1, maxdegree+1);
    IGRAPH_MATRIX_INIT_FINALLY(&ch, maxdegree+1, maxdegree+1);

    if (norm) {
        normfact=norm;
        IGRAPH_CHECK(igraph_matrix_resize(normfact, maxdegree+1, maxdegree+1));
        igraph_matrix_null(normfact);
    } else {
        normfact=&v_normfact;
        IGRAPH_MATRIX_INIT_FINALLY(normfact, maxdegree+1, maxdegree+1);
    }

    if (cites) {
        notnull=cites;
        IGRAPH_CHECK(igraph_matrix_resize(notnull, maxdegree+1, maxdegree+1));
        igraph_matrix_null(notnull);
    } else {
        notnull=&v_notnull;
        IGRAPH_MATRIX_INIT_FINALLY(notnull, maxdegree+1, maxdegree+1);
    }

    IGRAPH_CHECK(igraph_matrix_resize(kernel, maxdegree+1, maxdegree+1));
    igraph_matrix_null(kernel);
    if (sd) {
        IGRAPH_CHECK(igraph_matrix_resize(sd, maxdegree+1, maxdegree+1));
        igraph_matrix_null(sd);
    }

    for (timestep=0; timestep<no_of_events; timestep++) {

        IGRAPH_ALLOW_INTERRUPTION();

        /* Add the vertices in the first */
        nptr_save=nptr;
        while (nptr < no_of_nodes &&
                VECTOR(*vtime)[(long int)VECTOR(*vtimeidx)[nptr]]==timestep) {
            nptr++;
        }
        VECTOR(ntk)[0] += (nptr-nptr_save);

        /* Update ch accordingly, could be done later as well */
        if (VECTOR(ntk)[0] == nptr-nptr_save && nptr!=nptr_save) {
            if (nptr-nptr_save >= 2) {
                MATRIX(ch, 0, 0) = eptr;
            }
            for (i=1; i<maxdegree+1; i++) {
                if (NTKK(0,i) == (nptr-nptr_save)*VECTOR(ntk)[i]) {
                    MATRIX(ch, 0, i) = MATRIX(ch, i, 0) = eptr;
                }
            }
        }

        /* Estimate Akk */
        eptr_save=eptr;
        while (eptr < no_of_edges &&
                VECTOR(*etime)[(long int)VECTOR(*etimeidx)[eptr] ] == timestep) {
            long int edge=(long int) VECTOR(*etimeidx)[eptr];
            long int from=IGRAPH_FROM(graph, edge), to=IGRAPH_TO(graph, edge);
            long int xidx=VECTOR(degree)[from];
            long int yidx=VECTOR(degree)[to];
            double xk, oldakk;

            MATRIX(*notnull, xidx, yidx) += 1;
            MATRIX(*notnull, yidx, xidx) = MATRIX(*notnull, xidx, yidx);

            xk=VECTOR(*st)[timestep]/NTKK(xidx, yidx);
            oldakk=MATRIX(*kernel, xidx, yidx);
            MATRIX(*kernel, xidx, yidx) +=  (xk-oldakk)/MATRIX(*notnull, xidx, yidx);
            MATRIX(*kernel, yidx, xidx) = MATRIX(*kernel, xidx, yidx);
            if (sd) {
                MATRIX(*sd, xidx, yidx) += (xk-oldakk)*(xk-MATRIX(*kernel, xidx, yidx));
                MATRIX(*sd, yidx, xidx) = MATRIX(*sd, xidx, yidx);
            }
            /* TODO: debug */

            eptr++;
        }

        /* Update ntkk, ntk, ch, normfact, add the edges */
        eptr_new=eptr;
        eptr=eptr_save;
        while (eptr < no_of_edges &&
                VECTOR(*etime)[(long int) VECTOR(*etimeidx)[eptr] ] == timestep) {
            long int edge=(long int) VECTOR(*etimeidx)[eptr];
            long int from=IGRAPH_FROM(graph, edge);
            long int to=IGRAPH_TO(graph, edge);
            long int xidx=VECTOR(degree)[from];
            long int yidx=VECTOR(degree)[to];
            long int n;

            adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) from);
            n=igraph_vector_size(adjedges);
            for (i=0; i<n; i++) {
                long int edge=(long int) VECTOR(*adjedges)[i];
                if (VECTOR(added)[edge]) {
                    long int otherv=IGRAPH_OTHER(graph, edge, from); /* other than from */
                    long int deg=VECTOR(degree)[otherv];
                    MATRIX(ntkk, xidx, deg) -= 1;
                    MATRIX(ntkk, deg, xidx) = MATRIX(ntkk, xidx, deg);
                    if (NTKK(xidx, deg)==1) {
                        MATRIX(ch, deg, xidx) = eptr_new;
                        MATRIX(ch, xidx, deg) = MATRIX(ch, deg, xidx);
                    }
                    MATRIX(ntkk, xidx+1, deg) += 1;
                    MATRIX(ntkk, deg, xidx+1) = MATRIX(ntkk, xidx+1, deg);
                    if (NTKK(xidx+1, deg)==0) {
                        MATRIX(*normfact, xidx+1, deg) += eptr_new-MATRIX(ch, xidx+1, deg);
                        MATRIX(*normfact, deg, xidx+1) = MATRIX(*normfact, xidx+1, deg);
                    }
                }
            }
            adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) to);
            n=igraph_vector_size(adjedges);
            for (i=0; i<n; i++) {
                long int edge=(long int) VECTOR(*adjedges)[i];
                if (VECTOR(added)[edge]) {
                    long int otherv=IGRAPH_OTHER(graph, edge, to); /* other than to */
                    long int deg=VECTOR(degree)[otherv];
                    MATRIX(ntkk, yidx, deg) -= 1;
                    MATRIX(ntkk, deg, yidx) = MATRIX(ntkk, yidx, deg);
                    if (NTKK(yidx, deg)==1) {
                        MATRIX(ch, deg, yidx) = eptr_new;
                        MATRIX(ch, yidx, deg) = MATRIX(ch, deg, yidx);
                    }
                    MATRIX(ntkk, yidx+1, deg) += 1;
                    MATRIX(ntkk, deg, yidx+1) = MATRIX(ntkk, yidx+1, deg);
                    if (NTKK(yidx+1, deg)==0) {
                        MATRIX(*normfact, yidx+1, deg) += eptr_new-MATRIX(ch, yidx+1, deg);
                        MATRIX(*normfact, deg, yidx+1) = MATRIX(*normfact, yidx+1, deg);
                    }
                }
            }

            VECTOR(added)[edge]=1;

            MATRIX(ntkk, xidx+1, yidx+1) += 1;
            MATRIX(ntkk, yidx+1, xidx+1) = MATRIX(ntkk, xidx+1, yidx+1);
            if (NTKK(xidx+1, yidx+1)==0) {
                MATRIX(*normfact, xidx+1, yidx+1) = eptr_new-MATRIX(ch, xidx+1, yidx+1);
                MATRIX(*normfact, yidx+1, xidx+1) = MATRIX(*normfact, xidx+1, yidx+1);
            }

            for (i=0; i<maxdegree+1; i++) {
                long int before, after;
                before=(long int) NTKK(xidx,i);
                VECTOR(ntk)[xidx] -= 1;
                after=(long int) NTKK(xidx,i);
                VECTOR(ntk)[xidx] += 1;
                if (before > 0 && after==0) {
                    MATRIX(*normfact, xidx, i) += eptr_new-MATRIX(ch, xidx, i);
                    MATRIX(*normfact, i, xidx) = MATRIX(*normfact, xidx, i);
                }
            }
            VECTOR(ntk)[xidx]--;

            for (i=0; i<maxdegree+1; i++) {
                long int before, after;
                before=(long int) NTKK(yidx, i);
                VECTOR(ntk)[yidx] -= 1;
                after=(long int) NTKK(yidx, i);
                VECTOR(ntk)[yidx] += 1;
                if (before > 0 && after==0) {
                    MATRIX(*normfact, yidx, i) += eptr_new-MATRIX(ch, yidx, i);
                    MATRIX(*normfact, i, yidx) = MATRIX(*normfact, yidx, i);
                }
            }
            VECTOR(ntk)[yidx]--;

            for (i=0; i<maxdegree+1; i++) {
                long int before, after;
                before=(long int) NTKK(xidx+1, i);
                VECTOR(ntk)[xidx+1] += 1;
                after=(long int) NTKK(xidx+1, i);
                VECTOR(ntk)[xidx+1] -= 1;
                if (before==0 && after > 0) {
                    MATRIX(ch, xidx+1, i) = eptr_new;
                    MATRIX(ch, i, xidx+1) = MATRIX(ch, xidx+1, i);
                }
            }
            VECTOR(ntk)[xidx+1]++;

            for (i=0; i<maxdegree+1; i++) {
                long int before, after;
                before=(long int) NTKK(yidx+1, i);
                VECTOR(ntk)[yidx+1] += 1;
                after=(long int) NTKK(yidx+1, i);
                VECTOR(ntk)[yidx+1] -= 1;
                if (before == 0 && after == 0) {
                    MATRIX(ch, yidx+1, i) = eptr_new;
                    MATRIX(ch, i, yidx+1) = MATRIX(ch, yidx+1, i);
                }
            }
            VECTOR(ntk)[yidx+1]++;

            VECTOR(degree)[from]++;
            VECTOR(degree)[to]++;

            eptr++;
        }

    }

    for (i=0; i<maxdegree+1; i++) {
        igraph_real_t oldakk;
        long int j;
        for (j=0; j<=i; j++) {
            if (NTKK(i, j) != 0) {
                MATRIX(*normfact, i, j) += (eptr-MATRIX(ch, i, j));
                MATRIX(*normfact, j, i) = MATRIX(*normfact, i, j);
            }
            if (MATRIX(*normfact, i, j)==0) {
                MATRIX(*kernel, i, j)=MATRIX(*kernel, j, i)=0;
                MATRIX(*normfact, i, j)=MATRIX(*normfact, j, i)=1;
            }
            oldakk=MATRIX(*kernel, i, j);
            MATRIX(*kernel, i, j) *= MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j);
            MATRIX(*kernel, j, i) = MATRIX(*kernel, i, j);
            if (sd) {
                MATRIX(*sd, i, j) += oldakk * oldakk * MATRIX(*notnull, i, j) *
                                     (1-MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j));
                MATRIX(*sd, i, j) = sqrt(MATRIX(*sd, i, j)/(MATRIX(*normfact, i, j)-1));
                MATRIX(*sd, j, i) = MATRIX(*sd, i, j);
            }
        }
    }

    if (!cites) {
        igraph_matrix_destroy(notnull);
        IGRAPH_FINALLY_CLEAN(1);
    }
    if (!norm) {
        igraph_matrix_destroy(normfact);
        IGRAPH_FINALLY_CLEAN(1);
    }

    igraph_matrix_destroy(&ch);
    igraph_matrix_destroy(&ntkk);
    igraph_vector_long_destroy(&ntk);
    igraph_vector_char_destroy(&added);
    igraph_vector_long_destroy(&degree);
    IGRAPH_FINALLY_CLEAN(5);

    return 0;
}
Exemple #14
0
int check_multi() {

  igraph_t g;
  igraph_vector_t vec;
  igraph_vector_t eids, eids2;
  int ret;
  long int i;

  igraph_real_t q1[] = { 0,1, 0,1 };
  igraph_real_t q2[] = { 0,1, 0,1, 0,1 };
  igraph_real_t q3[] = { 1,0, 3,4, 1,0, 0,1, 3,4, 0,1 };

  igraph_vector_init(&eids, 0);

  /*********************************/
  igraph_small(&g, /*n=*/ 10, /*directed=*/ 1, 
	       0,1, 0,1, 1,0, 1,2, 3,4, 3,4, 3,4, 3,5, 3,7, 
	       9,8,
	       -1);

  igraph_vector_view(&vec, q1, sizeof(q1) / sizeof(igraph_real_t));
  igraph_get_eids_multi(&g, &eids, &vec, 0, /*directed=*/ 1, /*error=*/ 1);
  igraph_vector_sort(&eids);
  print_vector(&eids, stdout);

  igraph_vector_view(&vec, q2, sizeof(q2) / sizeof(igraph_real_t));
  igraph_get_eids_multi(&g, &eids, &vec, 0, /*directed=*/ 0, /*error=*/ 1);
  igraph_vector_sort(&eids);
  print_vector(&eids, stdout);

  igraph_vector_view(&vec, q2, sizeof(q2) / sizeof(igraph_real_t));
  igraph_set_error_handler(igraph_error_handler_ignore);
  ret=igraph_get_eids_multi(&g, &eids, &vec, 0, /*directed=*/ 1, /*error=*/1);
  if (ret != IGRAPH_EINVAL) { return 1; } 
  igraph_set_error_handler(igraph_error_handler_abort);

  igraph_destroy(&g);
  /*********************************/

  /*********************************/
  igraph_small(&g, /*n=*/10, /*directed=*/0, 
	       0,1, 1,0, 0,1, 3,4, 3,4, 5,4, 9,8, 
	       -1);
  
  igraph_vector_view(&vec, q1, sizeof(q1) / sizeof(igraph_real_t));
  igraph_get_eids_multi(&g, &eids, &vec, 0, /*directed=*/1, /*error=*/ 1);
  igraph_vector_sort(&eids);
  print_vector(&eids, stdout);

  igraph_vector_view(&vec, q3, sizeof(q3) / sizeof(igraph_real_t));
  igraph_set_error_handler(igraph_error_handler_ignore);
  ret=igraph_get_eids_multi(&g, &eids, &vec, 0, /*directed=*/0, /*error=*/ 1);
  if (ret != IGRAPH_EINVAL) { return 2; }
  igraph_set_error_handler(igraph_error_handler_abort);
  
  igraph_destroy(&g);

  /*********************************/

  igraph_vector_destroy(&eids);

  /*********************************/
  /* Speed tests */

#define NODES 10000
  igraph_barabasi_game(&g, /*n=*/ NODES, /*power=*/ 1.0, /*m=*/ 3, 
		       /*outseq=*/ 0, /*outpref=*/ 0, /*A=*/ 1,
		       /*directed=*/ 1, IGRAPH_BARABASI_BAG,
		       /*start_from=*/ 0);
  igraph_simplify(&g, /*multiple=*/ 1, /*loops=*/ 0, /*edge_comb=*/ 0);

  igraph_vector_init(&eids, NODES/2);
  igraph_random_sample(&eids, 0, igraph_ecount(&g)-1, NODES/2);
  igraph_vector_init(&vec, NODES);
  for (i=0; i<NODES/2; i++) {
    VECTOR(vec)[2*i]   = IGRAPH_FROM(&g, VECTOR(eids)[i]);
    VECTOR(vec)[2*i+1] = IGRAPH_TO(&g, VECTOR(eids)[i]);
  }
  igraph_vector_init(&eids2, 0);
  igraph_get_eids_multi(&g, &eids2, &vec, 0, /*directed=*/ 1, /*error=*/ 1);
  if (!igraph_vector_all_e(&eids, &eids2)) {
    return 3;
  }

  /**/

  for (i=0; i<NODES/2; i++) {
    VECTOR(vec)[2*i]   = IGRAPH_TO(&g, VECTOR(eids)[i]);
    VECTOR(vec)[2*i+1] = IGRAPH_FROM(&g, VECTOR(eids)[i]);
  }
  igraph_get_eids_multi(&g, &eids2, &vec, 0, /*directed=*/ 0, /*error=*/ 1);
  if (!igraph_vector_all_e(&eids, &eids2)) {
    return 4;
  }

  igraph_vector_destroy(&eids);
  igraph_vector_destroy(&eids2);
  igraph_vector_destroy(&vec);
  igraph_destroy(&g);
		  
  /*********************************/

  return 0;
}
/**
 * \function igraph_community_fastgreedy
 * \brief Finding community structure by greedy optimization of modularity
 * 
 * This function implements the fast greedy modularity optimization
 * algorithm for finding community structure, see 
 * A Clauset, MEJ Newman, C Moore: Finding community structure in very
 * large networks, http://www.arxiv.org/abs/cond-mat/0408187 for the
 * details.
 *
 * </para><para>
 * Some improvements proposed in K Wakita, T Tsurumi: Finding community
 * structure in mega-scale social networks,
 * http://www.arxiv.org/abs/cs.CY/0702048v1 have also been implemented.
 *
 * \param graph The input graph. It must be a simple graph, i.e. a graph 
 *    without multiple and without loop edges. This is checked and an
 *    error message is given for non-simple graphs.
 * \param weights Potentially a numeric vector containing edge
 *    weights. Supply a null pointer here for unweighted graphs. The
 *    weights are expected to be non-negative.
 * \param merges Pointer to an initialized matrix or NULL, the result of the
 *    computation is stored here. The matrix has two columns and each
 *    merge corresponds to one merge, the ids of the two merged
 *    components are stored. The component ids are numbered from zero and 
 *    the first \c n components are the individual vertices, \c n is
 *    the number of vertices in the graph. Component \c n is created
 *    in the first merge, component \c n+1 in the second merge, etc.
 *    The matrix will be resized as needed. If this argument is NULL
 *    then it is ignored completely.
 * \param modularity Pointer to an initialized matrix or NULL pointer,
 *    in the former case the modularity scores along the stages of the
 *    computation are recorded here. The vector will be resized as
 *    needed.
 * \return Error code.
 *
 * \sa \ref igraph_community_walktrap(), \ref
 * igraph_community_edge_betweenness() for other community detection
 * algorithms, \ref igraph_community_to_membership() to convert the
 * dendrogram to a membership vector.
 *
 * Time complexity: O(|E||V|log|V|) in the worst case,
 * O(|E|+|V|log^2|V|) typically, |V| is the number of vertices, |E| is
 * the number of edges.
 */
int igraph_community_fastgreedy(const igraph_t *graph,
  const igraph_vector_t *weights,
  igraph_matrix_t *merges, igraph_vector_t *modularity) {
  long int no_of_edges, no_of_nodes, no_of_joins, total_joins;
  long int i, j, k, n, m, from, to, dummy;
  igraph_integer_t ffrom, fto;
  igraph_eit_t edgeit;
  igraph_i_fastgreedy_commpair *pairs, *p1, *p2;
  igraph_i_fastgreedy_community_list communities;
  igraph_vector_t a;
  igraph_real_t q, maxq, *dq, weight_sum;
  igraph_bool_t simple;

  /*long int join_order[] = { 16,5, 5,6, 6,0, 4,0, 10,0, 26,29, 29,33, 23,33, 27,33, 25,24, 24,31, 12,3, 21,1, 30,8, 8,32, 9,2, 17,1, 11,0, 7,3, 3,2, 13,2, 1,2, 28,31, 31,33, 22,32, 18,32, 20,32, 32,33, 15,33, 14,33, 0,19, 19,2, -1,-1 };*/
  /*long int join_order[] = { 43,42, 42,41, 44,41, 41,36, 35,36, 37,36, 36,29, 38,29, 34,29, 39,29, 33,29, 40,29, 32,29, 14,29, 30,29, 31,29, 6,18, 18,4, 23,4, 21,4, 19,4, 27,4, 20,4, 22,4, 26,4, 25,4, 24,4, 17,4, 0,13, 13,2, 1,2, 11,2, 8,2, 5,2, 3,2, 10,2, 9,2, 7,2, 2,28, 28,15, 12,15, 29,16, 4,15, -1,-1 };*/

  no_of_nodes = igraph_vcount(graph);
  no_of_edges = igraph_ecount(graph);
  
  if (igraph_is_directed(graph)) {
	IGRAPH_ERROR("fast greedy community detection works for undirected graphs only", IGRAPH_UNIMPLEMENTED);
  }
  
  total_joins=no_of_nodes-1;

  if (weights != 0) {
    if (igraph_vector_size(weights) < igraph_ecount(graph))
      IGRAPH_ERROR("fast greedy community detection: weight vector too short", IGRAPH_EINVAL);
    if (igraph_vector_any_smaller(weights, 0))
      IGRAPH_ERROR("weights must be positive", IGRAPH_EINVAL);
    weight_sum = igraph_vector_sum(weights);
  } else weight_sum = no_of_edges;

  IGRAPH_CHECK(igraph_is_simple(graph, &simple));
  if (!simple) {
    IGRAPH_ERROR("fast-greedy community finding works only on simple graphs", IGRAPH_EINVAL);
  }

  if (merges != 0) {
	IGRAPH_CHECK(igraph_matrix_resize(merges, total_joins, 2));
	igraph_matrix_null(merges);
  }
  if (modularity != 0) {
	IGRAPH_CHECK(igraph_vector_resize(modularity, total_joins+1));
  }

  /* Create degree vector */
  IGRAPH_VECTOR_INIT_FINALLY(&a, no_of_nodes);
  if (weights) {
    debug("Calculating weighted degrees\n");
    for (i=0; i < no_of_edges; i++) {
      VECTOR(a)[(long int)IGRAPH_FROM(graph, i)] += VECTOR(*weights)[i];
      VECTOR(a)[(long int)IGRAPH_TO(graph, i)] += VECTOR(*weights)[i];
    }
  } else {
    debug("Calculating degrees\n");
    IGRAPH_CHECK(igraph_degree(graph, &a, igraph_vss_all(), IGRAPH_ALL, 0));
  }

  /* Create list of communities */
  debug("Creating community list\n");
  communities.n = no_of_nodes;
  communities.no_of_communities = no_of_nodes;
  communities.e = (igraph_i_fastgreedy_community*)calloc(no_of_nodes, sizeof(igraph_i_fastgreedy_community));
  if (communities.e == 0) {
	IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(free, communities.e);
  communities.heap = (igraph_i_fastgreedy_community**)calloc(no_of_nodes, sizeof(igraph_i_fastgreedy_community*));
  if (communities.heap == 0) {
	IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(free, communities.heap);
  communities.heapindex = (igraph_integer_t*)calloc(no_of_nodes, sizeof(igraph_integer_t));
  if (communities.heapindex == 0) {
	IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY_CLEAN(2);
  IGRAPH_FINALLY(igraph_i_fastgreedy_community_list_destroy, &communities);
  for (i=0; i<no_of_nodes; i++) {
    igraph_vector_ptr_init(&communities.e[i].neis, 0);
    communities.e[i].id = i;
    communities.e[i].size = 1;
  }

  /* Create list of community pairs from edges */
  debug("Allocating dq vector\n");
  dq = (igraph_real_t*)calloc(no_of_edges, sizeof(igraph_real_t));
  if (dq == 0) {
	IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(free, dq);
  debug("Creating community pair list\n");
  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(0), &edgeit));
  IGRAPH_FINALLY(igraph_eit_destroy, &edgeit);
  pairs = (igraph_i_fastgreedy_commpair*)calloc(2*no_of_edges, sizeof(igraph_i_fastgreedy_commpair));
  if (pairs == 0) {
	IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(free, pairs);
  i=j=0;
  while (!IGRAPH_EIT_END(edgeit)) {
    long int eidx = IGRAPH_EIT_GET(edgeit);
    igraph_edge(graph, eidx, &ffrom, &fto);
    
	/* Create the pairs themselves */
	from = (long int)ffrom; to = (long int)fto;
	if (from == to) {
	  IGRAPH_ERROR("loop edge detected, simplify the graph before starting community detection", IGRAPH_EINVAL);
	}

	if (from>to) {
	  dummy=from; from=to; to=dummy;
	}
    if (weights) {
      dq[j]=2*(VECTOR(*weights)[eidx]/(weight_sum*2.0) - VECTOR(a)[from]*VECTOR(a)[to]/(4.0*weight_sum*weight_sum));
    } else {
	  dq[j]=2*(1.0/(no_of_edges*2.0) - VECTOR(a)[from]*VECTOR(a)[to]/(4.0*no_of_edges*no_of_edges));
    }
	pairs[i].first = from;
	pairs[i].second = to;
    pairs[i].dq = &dq[j];
	pairs[i].opposite = &pairs[i+1];
	pairs[i+1].first = to;
	pairs[i+1].second = from;
	pairs[i+1].dq = pairs[i].dq;
	pairs[i+1].opposite = &pairs[i];
	/* Link the pair to the communities */
	igraph_vector_ptr_push_back(&communities.e[from].neis, &pairs[i]);
	igraph_vector_ptr_push_back(&communities.e[to].neis, &pairs[i+1]);
	/* Update maximums */
	if (communities.e[from].maxdq==0 || *communities.e[from].maxdq->dq < *pairs[i].dq)
	  communities.e[from].maxdq = &pairs[i];
	if (communities.e[to].maxdq==0 || *communities.e[to].maxdq->dq < *pairs[i+1].dq)
	  communities.e[to].maxdq = &pairs[i+1];

    /* Iterate */
	i+=2; j++;
    IGRAPH_EIT_NEXT(edgeit);
  }
  igraph_eit_destroy(&edgeit);
  IGRAPH_FINALLY_CLEAN(1);

  /* Sorting community neighbor lists by community IDs */
  debug("Sorting community neighbor lists\n");
  for (i=0, j=0; i<no_of_nodes; i++) {
	igraph_vector_ptr_sort(&communities.e[i].neis, igraph_i_fastgreedy_commpair_cmp);
    /* Isolated vertices won't be stored in the heap (to avoid maxdq == 0) */
    if (VECTOR(a)[i] > 0) {
	  communities.heap[j] = &communities.e[i];
      communities.heapindex[i] = j;
      j++;
    } else {
      communities.heapindex[i] = -1;
    }
  }
  communities.no_of_communities = j;

  /* Calculate proper vector a (see paper) and initial modularity */
  q=0;
  igraph_vector_scale(&a, 1.0/(2.0 * (weights ? weight_sum : no_of_edges)));
  for (i=0; i<no_of_nodes; i++)
	q -= VECTOR(a)[i]*VECTOR(a)[i];
  maxq=q;

  /* Initializing community heap */
  debug("Initializing community heap\n");
  igraph_i_fastgreedy_community_list_build_heap(&communities);

  debug("Initial modularity: %.4f\n", q);

  /* Let's rock ;) */
  no_of_joins=0;
  while (no_of_joins<total_joins) {
    IGRAPH_ALLOW_INTERRUPTION();
	IGRAPH_PROGRESS("fast greedy community detection", no_of_joins*100.0/total_joins, 0);
    
	/* Store the modularity */
	if (modularity) VECTOR(*modularity)[no_of_joins] = q;
    
	/* Some debug info if needed */
	/* igraph_i_fastgreedy_community_list_check_heap(&communities); */
#ifdef DEBUG
	debug("===========================================\n");
	for (i=0; i<communities.n; i++) {
	  if (communities.e[i].maxdq == 0) {
	    debug("Community #%ld: PASSIVE\n", i);
	    continue;
	  }
      debug("Community #%ld\n ", i);
	  for (j=0; j<igraph_vector_ptr_size(&communities.e[i].neis); j++) {
	    p1=(igraph_i_fastgreedy_commpair*)VECTOR(communities.e[i].neis)[j];
	    debug(" (%ld,%ld,%.4f)", p1->first, p1->second, *p1->dq);
	  }
	  p1=communities.e[i].maxdq;
	  debug("\n  Maxdq: (%ld,%ld,%.4f)\n", p1->first, p1->second, *p1->dq);
    }
	debug("Global maxdq is: (%ld,%ld,%.4f)\n", communities.heap[0]->maxdq->first,
	    communities.heap[0]->maxdq->second, *communities.heap[0]->maxdq->dq);
    for (i=0; i<communities.no_of_communities; i++)
	  debug("(%ld,%ld,%.4f) ", communities.heap[i]->maxdq->first, communities.heap[i]->maxdq->second, *communities.heap[0]->maxdq->dq);
	debug("\n");
#endif
	if (communities.heap[0] == 0) break; /* no more communities */
	if (communities.heap[0]->maxdq == 0) break; /* there are only isolated comms */
    to=communities.heap[0]->maxdq->second;
	from=communities.heap[0]->maxdq->first;

	debug("Q[%ld] = %.7f\tdQ = %.7f\t |H| = %ld\n",
	  no_of_joins, q, *communities.heap[0]->maxdq->dq, no_of_nodes-no_of_joins-1);

	/* DEBUG */
	/* from=join_order[no_of_joins*2]; to=join_order[no_of_joins*2+1];
	if (to == -1) break;
    for (i=0; i<igraph_vector_ptr_size(&communities.e[to].neis); i++) {
      p1=(igraph_i_fastgreedy_commpair*)VECTOR(communities.e[to].neis)[i];
	  if (p1->second == from) communities.maxdq = p1;
	} */

	n = igraph_vector_ptr_size(&communities.e[to].neis);
	m = igraph_vector_ptr_size(&communities.e[from].neis);
	/*if (n>m) {
	  dummy=n; n=m; m=dummy;
	  dummy=to; to=from; from=dummy;
	}*/
	debug("  joining: %ld <- %ld\n", to, from);
    q += *communities.heap[0]->maxdq->dq; 
	
	/* Merge the second community into the first */
	i = j = 0;
	while (i<n && j<m) {
	  p1 = (igraph_i_fastgreedy_commpair*)VECTOR(communities.e[to].neis)[i];
	  p2 = (igraph_i_fastgreedy_commpair*)VECTOR(communities.e[from].neis)[j];
	  debug("Pairs: %ld-%ld and %ld-%ld\n", p1->first, p1->second,
		  p2->first, p2->second);
	  if (p1->second < p2->second) {
		/* Considering p1 from now on */
		debug("    Considering: %ld-%ld\n", p1->first, p1->second);
	    if (p1->second == from) {
		  debug("    WILL REMOVE: %ld-%ld\n", to, from);
	    } else {
		  /* chain, case 1 */
		  debug("    CHAIN(1): %ld-%ld %ld, now=%.7f, adding=%.7f, newdq(%ld,%ld)=%.7f\n",
		    to, p1->second, from, *p1->dq, -2*VECTOR(a)[from]*VECTOR(a)[p1->second], p1->first, p1->second, *p1->dq-2*VECTOR(a)[from]*VECTOR(a)[p1->second]);
		  igraph_i_fastgreedy_community_update_dq(&communities, p1, *p1->dq - 2*VECTOR(a)[from]*VECTOR(a)[p1->second]);
		}
		i++;
	  } else if (p1->second == p2->second) {
	    /* p1->first, p1->second and p2->first form a triangle */
		debug("    Considering: %ld-%ld and %ld-%ld\n", p1->first, p1->second,
		  p2->first, p2->second);
		/* Update dq value */
		debug("    TRIANGLE: %ld-%ld-%ld, now=%.7f, adding=%.7f, newdq(%ld,%ld)=%.7f\n",
		  to, p1->second, from, *p1->dq, *p2->dq, p1->first, p1->second, *p1->dq+*p2->dq);
		igraph_i_fastgreedy_community_update_dq(&communities, p1, *p1->dq + *p2->dq);
        igraph_i_fastgreedy_community_remove_nei(&communities, p1->second, from);
		i++;
		j++;
	  } else {
		debug("    Considering: %ld-%ld\n", p2->first, p2->second);
		if (p2->second == to) {
		  debug("    WILL REMOVE: %ld-%ld\n", p2->second, p2->first);
		} else {
		  /* chain, case 2 */
		  debug("    CHAIN(2): %ld %ld-%ld, newdq(%ld,%ld)=%.7f\n",
		    to, p2->second, from, to, p2->second, *p2->dq-2*VECTOR(a)[to]*VECTOR(a)[p2->second]);
		  p2->opposite->second=to;
	      /* need to re-sort community nei list `p2->second` */
	      /* TODO: quicksort is O(n*logn), although we could do a deletion and
	       * insertion which can be done in O(logn) if deletion is O(1) */
	      debug("    Re-sorting community %ld\n", p2->second);
	      igraph_vector_ptr_sort(&communities.e[p2->second].neis, igraph_i_fastgreedy_commpair_cmp);
		  /* link from.neis[j] to the current place in to.neis if
		   * from.neis[j] != to */
		  p2->first=to;
		  IGRAPH_CHECK(igraph_vector_ptr_insert(&communities.e[to].neis,i,p2));
		  n++; i++;
		  if (*p2->dq > *communities.e[to].maxdq->dq) {
		    communities.e[to].maxdq = p2;
            k=igraph_i_fastgreedy_community_list_find_in_heap(&communities, to);
		    igraph_i_fastgreedy_community_list_sift_up(&communities, k);
		  }
		  igraph_i_fastgreedy_community_update_dq(&communities, p2, *p2->dq - 2*VECTOR(a)[to]*VECTOR(a)[p2->second]);
		}
		j++;
	  }
	}

	while (i<n) {
	  p1 = (igraph_i_fastgreedy_commpair*)VECTOR(communities.e[to].neis)[i];
	  if (p1->second == from) {
	    debug("    WILL REMOVE: %ld-%ld\n", p1->first, from);
	  } else {
	    /* chain, case 1 */
	    debug("    CHAIN(1): %ld-%ld %ld, now=%.7f, adding=%.7f, newdq(%ld,%ld)=%.7f\n",
	      to, p1->second, from, *p1->dq, -2*VECTOR(a)[from]*VECTOR(a)[p1->second], p1->first, p1->second, *p1->dq-2*VECTOR(a)[from]*VECTOR(a)[p1->second]);
	    igraph_i_fastgreedy_community_update_dq(&communities, p1, *p1->dq - 2*VECTOR(a)[from]*VECTOR(a)[p1->second]);
	  }
	  i++;
	}
	while (j<m) {
	  p2 = (igraph_i_fastgreedy_commpair*)VECTOR(communities.e[from].neis)[j];
      if (to == p2->second) { j++; continue; }
	  /* chain, case 2 */
	  debug("    CHAIN(2): %ld %ld-%ld, newdq(%ld,%ld)=%.7f\n",
	    to, p2->second, from, p1->first, p2->second, *p2->dq-2*VECTOR(a)[to]*VECTOR(a)[p2->second]);
	  p2->opposite->second=to;
	  /* need to re-sort community nei list `p2->second` */
	  /* TODO: quicksort is O(n*logn), although we could do a deletion and
	   * insertion which can be done in O(logn) if deletion is O(1) */
	  debug("    Re-sorting community %ld\n", p2->second);
	  igraph_vector_ptr_sort(&communities.e[p2->second].neis, igraph_i_fastgreedy_commpair_cmp);
	  /* link from.neis[j] to the current place in to.neis if
	   * from.neis[j] != to */
	  p2->first=to;
	  IGRAPH_CHECK(igraph_vector_ptr_push_back(&communities.e[to].neis,p2));
	  if (*p2->dq > *communities.e[to].maxdq->dq) {
	    communities.e[to].maxdq = p2;
        k=igraph_i_fastgreedy_community_list_find_in_heap(&communities, to);
		igraph_i_fastgreedy_community_list_sift_up(&communities, k);
	  }
	  igraph_i_fastgreedy_community_update_dq(&communities, p2, *p2->dq-2*VECTOR(a)[to]*VECTOR(a)[p2->second]);
	  j++;
	}

	/* Now, remove community `from` from the neighbors of community `to` */
	if (communities.no_of_communities > 2) {
	  debug("    REMOVING: %ld-%ld\n", to, from);
	  igraph_i_fastgreedy_community_remove_nei(&communities, to, from);
	  i=igraph_i_fastgreedy_community_list_find_in_heap(&communities, from);
	  igraph_i_fastgreedy_community_list_remove(&communities, i);
    }
	communities.e[from].maxdq=0;

    /* Update community sizes */
    communities.e[to].size += communities.e[from].size;
    communities.e[from].size = 0;

	/* record what has been merged */
	/* igraph_vector_ptr_clear is not enough here as it won't free
	 * the memory consumed by communities.e[from].neis. Thanks
	 * to Tom Gregorovic for pointing that out. */
	igraph_vector_ptr_destroy(&communities.e[from].neis);
	if (merges) {
	  MATRIX(*merges, no_of_joins, 0) = communities.e[to].id;
	  MATRIX(*merges, no_of_joins, 1) = communities.e[from].id;
	  communities.e[to].id = no_of_nodes+no_of_joins;
    }

	/* Update vector a */
	VECTOR(a)[to] += VECTOR(a)[from];
	VECTOR(a)[from] = 0.0;
	
	no_of_joins++;
  }
  /* TODO: continue merging when some isolated communities remained. Always
   * joining the communities with the least number of nodes results in the
   * smallest decrease in modularity every step. Now we're simply deleting
   * the excess rows from the merge matrix */
  if (no_of_joins < total_joins) {
    long int *ivec;
    ivec=igraph_Calloc(igraph_matrix_nrow(merges), long int);
    if (ivec == 0)
      IGRAPH_ERROR("can't run fast greedy community detection", IGRAPH_ENOMEM);
    IGRAPH_FINALLY(free, ivec);
    for (i=0; i<no_of_joins; i++) ivec[i] = i+1;
    igraph_matrix_permdelete_rows(merges, ivec, total_joins-no_of_joins);
    free(ivec);
    IGRAPH_FINALLY_CLEAN(1);
  }
Exemple #16
0
int check_simple() {

  igraph_t g;
  long int nodes=100;
  long int edges=1000;
  igraph_real_t p=3.0/nodes;
  long int runs=10;
  long int r, e, ecount;
  igraph_vector_t eids, pairs, path;

  srand(time(0));

  igraph_vector_init(&pairs, edges*2);
  igraph_vector_init(&path, 0);
  igraph_vector_init(&eids, 0);

  for (r=0; r<runs; r++) {
    igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNP, nodes, p, 
			    /*directed=*/ 0, /*loops=*/ 0);
    ecount=igraph_ecount(&g);
    for (e=0; e<edges; e++) {
      long int edge=RNG_INTEGER(0, ecount-1);
      VECTOR(pairs)[2*e] = IGRAPH_FROM(&g, edge);
      VECTOR(pairs)[2*e+1] = IGRAPH_TO(&g, edge);
    }
    igraph_get_eids(&g, &eids, &pairs, /*path=*/ 0, 0, /*error=*/ 1);
    for (e=0; e<edges; e++) {
      long int edge=VECTOR(eids)[e];
      long int from1=VECTOR(pairs)[2*e];
      long int to1=VECTOR(pairs)[2*e+1];
      long int from2=IGRAPH_FROM(&g, edge);
      long int to2=IGRAPH_TO(&g, edge);
      long int min1= from1 < to1 ? from1 : to1;
      long int max1= from1 < to1 ? to1 : from1;
      long int min2= from2 < to2 ? from2 : to2;
      long int max2= from2 < to2 ? to2 : from2;
      if (min1 != min2 || max1 != max2) {
	return 11;
      }
    }
    
    igraph_diameter(&g, /*res=*/ 0, /*from=*/ 0, /*to=*/ 0, &path,
		    IGRAPH_UNDIRECTED, /*unconn=*/ 1);
    igraph_get_eids(&g, &eids, /*pairs=*/ 0, &path, 0, /*error=*/ 1);
    for (e=0; e<igraph_vector_size(&path)-1; e++) {
      long int edge=VECTOR(eids)[e];
      long int from1=VECTOR(path)[e];
      long int to1=VECTOR(path)[e+1];
      long int from2=IGRAPH_FROM(&g, edge);
      long int to2=IGRAPH_TO(&g, edge);
      long int min1= from1 < to1 ? from1 : to1;
      long int max1= from1 < to1 ? to1 : from1;
      long int min2= from2 < to2 ? from2 : to2;
      long int max2= from2 < to2 ? to2 : from2;
      if (min1 != min2 || max1 != max2) {
	return 12;
      }
    }

    igraph_destroy(&g);
  }

  igraph_vector_destroy(&path);
  igraph_vector_destroy(&pairs);
  igraph_vector_destroy(&eids);

  return 0;
}
Exemple #17
0
int igraph_layout_i_grid_fr(const igraph_t *graph,
            igraph_matrix_t *res, igraph_bool_t use_seed,
	    igraph_integer_t niter, igraph_real_t start_temp,
	    const igraph_vector_t *weight, const igraph_vector_t *minx,
	    const igraph_vector_t *maxx, const igraph_vector_t *miny,
	    const igraph_vector_t *maxy) {

  igraph_integer_t no_nodes=igraph_vcount(graph);
  igraph_integer_t no_edges=igraph_ecount(graph);
  float width=sqrtf(no_nodes), height=width;
  igraph_2dgrid_t grid;
  igraph_vector_float_t dispx, dispy;
  igraph_real_t temp=start_temp;
  igraph_real_t difftemp=start_temp / niter;
  igraph_2dgrid_iterator_t vidit;
  igraph_integer_t i;
  const float cellsize=2.0;

  RNG_BEGIN();

  if (!use_seed) {
    IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 2));
    for (i=0; i<no_nodes; i++) {
      igraph_real_t x1=minx ? VECTOR(*minx)[i] : -width/2;
      igraph_real_t x2=maxx ? VECTOR(*maxx)[i] :  width/2;
      igraph_real_t y1=miny ? VECTOR(*miny)[i] : -height/2;
      igraph_real_t y2=maxy ? VECTOR(*maxy)[i] :  height/2;
      if (!igraph_finite(x1)) { x1 = -sqrt(no_nodes)/2; }
      if (!igraph_finite(x2)) { x2 =  sqrt(no_nodes)/2; }
      if (!igraph_finite(y1)) { y1 = -sqrt(no_nodes)/2; }
      if (!igraph_finite(y2)) { y2 =  sqrt(no_nodes)/2; }
      MATRIX(*res, i, 0) = RNG_UNIF(x1, x2);
      MATRIX(*res, i, 1) = RNG_UNIF(y1, y2);
    }
  }

  /* make grid */
  IGRAPH_CHECK(igraph_2dgrid_init(&grid, res, -width/2, width/2, cellsize,
				  -height/2, height/2, cellsize));
  IGRAPH_FINALLY(igraph_2dgrid_destroy, &grid);

  /* place vertices on grid */
  for (i=0; i<no_nodes; i++) {
    igraph_2dgrid_add2(&grid, i);
  }

  IGRAPH_CHECK(igraph_vector_float_init(&dispx, no_nodes));
  IGRAPH_FINALLY(igraph_vector_float_destroy, &dispx);
  IGRAPH_CHECK(igraph_vector_float_init(&dispy, no_nodes));
  IGRAPH_FINALLY(igraph_vector_float_destroy, &dispy);

  for (i=0; i<niter; i++) {
    igraph_integer_t v, u, e;

    igraph_vector_float_null(&dispx);
    igraph_vector_float_null(&dispy);

    /* repulsion */
    igraph_2dgrid_reset(&grid, &vidit);
    while ( (v=igraph_2dgrid_next(&grid, &vidit)-1) != -1) {
      while ( (u=igraph_2dgrid_next_nei(&grid, &vidit)-1) != -1) {
	float dx=MATRIX(*res, v, 0)-MATRIX(*res, u, 0);
	float dy=MATRIX(*res, v, 1)-MATRIX(*res, u, 1);
	float dlen=dx * dx + dy * dy;
	if (dlen < cellsize * cellsize) {
	  VECTOR(dispx)[v] += dx/dlen;
	  VECTOR(dispy)[v] += dy/dlen;
	  VECTOR(dispx)[u] -= dx/dlen;
	  VECTOR(dispy)[u] -= dy/dlen;
	}
      }
    }

    /* attraction */
    for (e=0; e<no_edges; e++) {
      igraph_integer_t v=IGRAPH_FROM(graph, e);
      igraph_integer_t u=IGRAPH_TO(graph, e);
      igraph_real_t dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0);
      igraph_real_t dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1);
      igraph_real_t w=weight ? VECTOR(*weight)[e] : 1.0;
      igraph_real_t dlen=sqrt(dx * dx + dy * dy) * w;
      VECTOR(dispx)[v] -= (dx * dlen);
      VECTOR(dispy)[v] -= (dy * dlen);
      VECTOR(dispx)[u] += (dx * dlen);
      VECTOR(dispy)[u] += (dy * dlen);
    }

    /* update */
    for (v=0; v<no_nodes; v++) {
      igraph_real_t dx=VECTOR(dispx)[v] + RNG_UNIF01() * 1e-9;
      igraph_real_t dy=VECTOR(dispy)[v] + RNG_UNIF01() * 1e-9;
      igraph_real_t displen=sqrt(dx * dx + dy * dy);
      igraph_real_t mx=fabs(dx) < temp ? dx : temp;
      igraph_real_t my=fabs(dy) < temp ? dy : temp;
      if (displen > 0) {
        MATRIX(*res, v, 0) += (dx / displen) * mx;
        MATRIX(*res, v, 1) += (dy / displen) * my;
      }
      if (minx && MATRIX(*res, v, 0) < VECTOR(*minx)[v]) {
	MATRIX(*res, v, 0) = VECTOR(*minx)[v];
      }
      if (maxx && MATRIX(*res, v, 0) > VECTOR(*maxx)[v]) {
	MATRIX(*res, v, 0) = VECTOR(*maxx)[v];
      }
      if (miny && MATRIX(*res, v, 1) < VECTOR(*miny)[v]) {
	MATRIX(*res, v, 1) = VECTOR(*miny)[v];
      }
      if (maxy && MATRIX(*res, v, 1) > VECTOR(*maxy)[v]) {
	MATRIX(*res, v, 1) = VECTOR(*maxy)[v];
      }
    }

    temp -= difftemp;
  }

  igraph_vector_float_destroy(&dispx);
  igraph_vector_float_destroy(&dispy);
  igraph_2dgrid_destroy(&grid);
  IGRAPH_FINALLY_CLEAN(3);
  return 0;
}
Exemple #18
0
int print_attributes(const igraph_t *g) {

  igraph_vector_t gtypes, vtypes, etypes;
  igraph_strvector_t gnames, vnames, enames;
  long int i;

  igraph_vector_t vec;
  igraph_strvector_t svec;
  long int j;

  igraph_vector_init(&gtypes, 0);
  igraph_vector_init(&vtypes, 0);
  igraph_vector_init(&etypes, 0);
  igraph_strvector_init(&gnames, 0);
  igraph_strvector_init(&vnames, 0);
  igraph_strvector_init(&enames, 0);

  igraph_cattribute_list(g, &gnames, &gtypes, &vnames, &vtypes, 
			 &enames, &etypes);

  /* Graph attributes */
  for (i=0; i<igraph_strvector_size(&gnames); i++) {
    printf("%s=", STR(gnames, i));
    if (VECTOR(gtypes)[i]==IGRAPH_ATTRIBUTE_NUMERIC) {
      igraph_real_printf(GAN(g, STR(gnames,i)));
      putchar(' ');
    } else {
      printf("\"%s\" ", GAS(g, STR(gnames,i)));
    }
  }
  printf("\n");

  for (i=0; i<igraph_vcount(g); i++) {
    long int j;
    printf("Vertex %li: ", i);
    for (j=0; j<igraph_strvector_size(&vnames); j++) {
      printf("%s=", STR(vnames, j));
      if (VECTOR(vtypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) {
	igraph_real_printf(VAN(g, STR(vnames,j), i));
	putchar(' ');
      } else {
	printf("\"%s\" ", VAS(g, STR(vnames,j), i));
      }
    }
    printf("\n");
  }

  for (i=0; i<igraph_ecount(g); i++) {
    long int j;
    printf("Edge %li (%i-%i): ", i, (int)IGRAPH_FROM(g,i), (int)IGRAPH_TO(g,i));
    for (j=0; j<igraph_strvector_size(&enames); j++) {
      printf("%s=", STR(enames, j));
      if (VECTOR(etypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) {
	igraph_real_printf(EAN(g, STR(enames, j), i));
	putchar(' ');
      } else {
	printf("\"%s\" ", EAS(g, STR(enames, j), i));
      }
    }
    printf("\n");
  }

  /* Check vector-based query functions */
  igraph_vector_init(&vec, 0);
  igraph_strvector_init(&svec, 0);
  
  for (j=0; j<igraph_strvector_size(&vnames); j++) {
    if (VECTOR(vtypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) {
      igraph_cattribute_VANV(g, STR(vnames, j), igraph_vss_all(), &vec);
      for (i=0; i<igraph_vcount(g); i++) {
	igraph_real_t num=VAN(g, STR(vnames, j), i);
	if (num != VECTOR(vec)[i] &&
	    (!isnan(num) || !isnan(VECTOR(vec)[i]))) {
	  exit(51);
	}
      }
    } else {
      igraph_cattribute_VASV(g, STR(vnames, j), igraph_vss_all(), &svec);
      for (i=0; i<igraph_vcount(g); i++) {
	const char *str=VAS(g, STR(vnames, j), i);
	if (strcmp(str,STR(svec, i))) {
	  exit(52);
	}
      }
    }
  }

  for (j=0; j<igraph_strvector_size(&enames); j++) {
    if (VECTOR(etypes)[j]==IGRAPH_ATTRIBUTE_NUMERIC) {
      igraph_cattribute_EANV(g, STR(enames, j), 
			     igraph_ess_all(IGRAPH_EDGEORDER_ID), &vec);
      for (i=0; i<igraph_ecount(g); i++) {
	igraph_real_t num=EAN(g, STR(enames, j), i);
	if (num != VECTOR(vec)[i] && 
	    (!isnan(num) || !isnan(VECTOR(vec)[i]))) {
	  exit(53);
	}
      }
    } else {
      igraph_cattribute_EASV(g, STR(enames, j), 
			     igraph_ess_all(IGRAPH_EDGEORDER_ID), &svec);
      for (i=0; i<igraph_ecount(g); i++) {
	const char *str=EAS(g, STR(enames, j), i);
	if (strcmp(str,STR(svec, i))) {
	  exit(54);
	}
      }
    }
  }

  igraph_strvector_destroy(&svec);
  igraph_vector_destroy(&vec);

  igraph_strvector_destroy(&enames);
  igraph_strvector_destroy(&vnames);
  igraph_strvector_destroy(&gnames);
  igraph_vector_destroy(&etypes);
  igraph_vector_destroy(&vtypes);
  igraph_vector_destroy(&gtypes);

  return 0;
}
Exemple #19
0
int igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, 
					  igraph_matrix_t *res,
					  igraph_bool_t use_seed,
					  igraph_integer_t niter,
					  igraph_real_t start_temp,
					  const igraph_vector_t *weight, 
					  const igraph_vector_t *minx,
					  const igraph_vector_t *maxx,
					  const igraph_vector_t *miny,
					  const igraph_vector_t *maxy,
					  const igraph_vector_t *minz,
					  const igraph_vector_t *maxz) {

  igraph_integer_t no_nodes=igraph_vcount(graph);
  igraph_integer_t no_edges=igraph_ecount(graph);
  igraph_integer_t i;
  igraph_vector_float_t dispx, dispy, dispz;
  igraph_real_t temp=start_temp;
  igraph_real_t difftemp=start_temp / niter;
  float width=sqrtf(no_nodes), height=width, depth=width;
  igraph_bool_t conn=1;
  float C;

  if (niter < 0) {
    IGRAPH_ERROR("Number of iterations must be non-negative in "
		 "Fruchterman-Reingold layout", IGRAPH_EINVAL);
  }

  if (use_seed && (igraph_matrix_nrow(res) != no_nodes ||
		   igraph_matrix_ncol(res) != 3)) {
    IGRAPH_ERROR("Invalid start position matrix size in "
		 "Fruchterman-Reingold layout", IGRAPH_EINVAL);
  }

  if (weight && igraph_vector_size(weight) != igraph_ecount(graph)) {
    IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
  }

  if (minx && igraph_vector_size(minx) != no_nodes) {
    IGRAPH_ERROR("Invalid minx vector length", IGRAPH_EINVAL);
  }
  if (maxx && igraph_vector_size(maxx) != no_nodes) {
    IGRAPH_ERROR("Invalid maxx vector length", IGRAPH_EINVAL);
  }
  if (minx && maxx && !igraph_vector_all_le(minx, maxx)) {
    IGRAPH_ERROR("minx must not be greater than maxx", IGRAPH_EINVAL);
  }
  if (miny && igraph_vector_size(miny) != no_nodes) {
    IGRAPH_ERROR("Invalid miny vector length", IGRAPH_EINVAL);
  }
  if (maxy && igraph_vector_size(maxy) != no_nodes) {
    IGRAPH_ERROR("Invalid maxy vector length", IGRAPH_EINVAL);
  }
  if (miny && maxy && !igraph_vector_all_le(miny, maxy)) {
    IGRAPH_ERROR("miny must not be greater than maxy", IGRAPH_EINVAL);
  }
  if (minz && igraph_vector_size(minz) != no_nodes) {
    IGRAPH_ERROR("Invalid minz vector length", IGRAPH_EINVAL);
  }
  if (maxz && igraph_vector_size(maxz) != no_nodes) {
    IGRAPH_ERROR("Invalid maxz vector length", IGRAPH_EINVAL);
  }
  if (minz && maxz && !igraph_vector_all_le(minz, maxz)) {
    IGRAPH_ERROR("minz must not be greater than maxz", IGRAPH_EINVAL);
  }

  igraph_is_connected(graph, &conn, IGRAPH_WEAK);
  if (!conn) { C = no_nodes * sqrtf(no_nodes); }

  RNG_BEGIN();

  if (!use_seed) {
    IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 3));
    for (i=0; i<no_nodes; i++) {
      igraph_real_t x1=minx ? VECTOR(*minx)[i] : -width/2;
      igraph_real_t x2=maxx ? VECTOR(*maxx)[i] :  width/2;
      igraph_real_t y1=miny ? VECTOR(*miny)[i] : -height/2;
      igraph_real_t y2=maxy ? VECTOR(*maxy)[i] :  height/2;
      igraph_real_t z1=minz ? VECTOR(*minz)[i] : -depth/2;
      igraph_real_t z2=maxz ? VECTOR(*maxz)[i] :  depth/2;
      MATRIX(*res, i, 0) = RNG_UNIF(x1, x2);
      MATRIX(*res, i, 1) = RNG_UNIF(y1, y2);
      MATRIX(*res, i, 2) = RNG_UNIF(z1, z2);
    }
  }

  IGRAPH_CHECK(igraph_vector_float_init(&dispx, no_nodes));
  IGRAPH_FINALLY(igraph_vector_float_destroy, &dispx);
  IGRAPH_CHECK(igraph_vector_float_init(&dispy, no_nodes));
  IGRAPH_FINALLY(igraph_vector_float_destroy, &dispy);
  IGRAPH_CHECK(igraph_vector_float_init(&dispz, no_nodes));
  IGRAPH_FINALLY(igraph_vector_float_destroy, &dispz);

  for (i=0; i<niter; i++) {
    igraph_integer_t v, u, e;
    
    /* calculate repulsive forces, we have a special version
       for unconnected graphs */
    igraph_vector_float_null(&dispx);
    igraph_vector_float_null(&dispy);
    igraph_vector_float_null(&dispz);
    if (conn) {
      for (v=0; v<no_nodes; v++) {
	for (u=v+1; u<no_nodes; u++) {
	  float dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0);
	  float dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1);
	  float dz=MATRIX(*res, v, 2) - MATRIX(*res, u, 2);
	  float dlen=dx * dx + dy * dy + dz * dz;

          if (dlen == 0) {
            dx = RNG_UNIF01() * 1e-9;
            dy = RNG_UNIF01() * 1e-9;
            dz = RNG_UNIF01() * 1e-9;
            dlen = dx * dx + dy * dy + dz * dz;
          }

	  VECTOR(dispx)[v] += dx/dlen;
	  VECTOR(dispy)[v] += dy/dlen;
	  VECTOR(dispz)[v] += dz/dlen;
	  VECTOR(dispx)[u] -= dx/dlen;
	  VECTOR(dispy)[u] -= dy/dlen;
	  VECTOR(dispz)[u] -= dz/dlen;
	}
      }
    } else {
      for (v=0; v<no_nodes; v++) {
	for (u=v+1; u<no_nodes; u++) {
	  float dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0);
	  float dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1);
	  float dz=MATRIX(*res, v, 2) - MATRIX(*res, u, 2);
	  float dlen, rdlen;

	  dlen=dx * dx + dy * dy + dz * dz;
          if (dlen == 0) {
            dx = RNG_UNIF01() * 1e-9;
            dy = RNG_UNIF01() * 1e-9;
            dz = RNG_UNIF01() * 1e-9;
            dlen = dx * dx + dy * dy + dz * dz;
          }

	  rdlen=sqrt(dlen);

	  VECTOR(dispx)[v] += dx * (C-dlen * rdlen) / (dlen*C);
	  VECTOR(dispy)[v] += dy * (C-dlen * rdlen) / (dlen*C);
	  VECTOR(dispy)[v] += dz * (C-dlen * rdlen) / (dlen*C);
	  VECTOR(dispx)[u] -= dx * (C-dlen * rdlen) / (dlen*C);
	  VECTOR(dispy)[u] -= dy * (C-dlen * rdlen) / (dlen*C);
	  VECTOR(dispz)[u] -= dz * (C-dlen * rdlen) / (dlen*C);
	}
      }
    }

    /* calculate attractive forces */
    for (e=0; e<no_edges; e++) {
      /* each edges is an ordered pair of vertices v and u */
      igraph_integer_t v=IGRAPH_FROM(graph, e);
      igraph_integer_t u=IGRAPH_TO(graph, e);
      igraph_real_t dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0);
      igraph_real_t dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1);
      igraph_real_t dz=MATRIX(*res, v, 2) - MATRIX(*res, u, 2);
      igraph_real_t w=weight ? VECTOR(*weight)[e] : 1.0;
      igraph_real_t dlen=sqrt(dx * dx + dy * dy + dz * dz) * w;
      VECTOR(dispx)[v] -= (dx * dlen);
      VECTOR(dispy)[v] -= (dy * dlen);
      VECTOR(dispz)[v] -= (dz * dlen);
      VECTOR(dispx)[u] += (dx * dlen);
      VECTOR(dispy)[u] += (dy * dlen);
      VECTOR(dispz)[u] += (dz * dlen);
    }
    
    /* limit max displacement to temperature t and prevent from
       displacement outside frame */
    for (v=0; v<no_nodes; v++) {
      igraph_real_t dx=VECTOR(dispx)[v] + RNG_UNIF01() * 1e-9;
      igraph_real_t dy=VECTOR(dispy)[v] + RNG_UNIF01() * 1e-9;
      igraph_real_t dz=VECTOR(dispz)[v] + RNG_UNIF01() * 1e-9;
      igraph_real_t displen=sqrt(dx * dx + dy * dy + dz * dz);
      igraph_real_t mx=fabs(dx) < temp ? dx : temp;
      igraph_real_t my=fabs(dy) < temp ? dy : temp;
      igraph_real_t mz=fabs(dz) < temp ? dz : temp;
      if (displen > 0) {
        MATRIX(*res, v, 0) += (dx / displen) * mx;
        MATRIX(*res, v, 1) += (dy / displen) * my;
        MATRIX(*res, v, 2) += (dz / displen) * mz;
      }
      if (minx && MATRIX(*res, v, 0) < VECTOR(*minx)[v]) { 
	MATRIX(*res, v, 0) = VECTOR(*minx)[v]; 
      }
      if (maxx && MATRIX(*res, v, 0) > VECTOR(*maxx)[v]) {
	MATRIX(*res, v, 0) = VECTOR(*maxx)[v];
      }
      if (miny && MATRIX(*res, v, 1) < VECTOR(*miny)[v]) {
	MATRIX(*res, v, 1) = VECTOR(*miny)[v];
      }
      if (maxy && MATRIX(*res, v, 1) > VECTOR(*maxy)[v]) {
	MATRIX(*res, v, 1) = VECTOR(*maxy)[v];
      }
      if (minz && MATRIX(*res, v, 2) < VECTOR(*minz)[v]) {
	MATRIX(*res, v, 2) = VECTOR(*minz)[v];
      }
      if (maxz && MATRIX(*res, v, 2) > VECTOR(*maxz)[v]) {
	MATRIX(*res, v, 2) = VECTOR(*maxz)[v];
      }
    }

    temp -= difftemp;
  }

  RNG_END();

  igraph_vector_float_destroy(&dispx);
  igraph_vector_float_destroy(&dispy);
  igraph_vector_float_destroy(&dispz);
  IGRAPH_FINALLY_CLEAN(3);
  
  return 0;
}
Exemple #20
0
int igraph_layout_i_fr(const igraph_t *graph,
		       igraph_matrix_t *res,
		       igraph_bool_t use_seed,
		       igraph_integer_t niter,
		       igraph_real_t start_temp,
		       const igraph_vector_t *weight,
		       const igraph_vector_t *minx,
		       const igraph_vector_t *maxx,
		       const igraph_vector_t *miny,
		       const igraph_vector_t *maxy) {

  igraph_integer_t no_nodes=igraph_vcount(graph);
  igraph_integer_t no_edges=igraph_ecount(graph);
  igraph_integer_t i;
  igraph_vector_float_t dispx, dispy;
  igraph_real_t temp=start_temp;
  igraph_real_t difftemp=start_temp / niter;
  float width=sqrtf(no_nodes), height=width;
  igraph_bool_t conn=1;
  float C;

  igraph_is_connected(graph, &conn, IGRAPH_WEAK);
  if (!conn) { C = no_nodes * sqrtf(no_nodes); }

  RNG_BEGIN();

  if (!use_seed) {
    IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 2));
    for (i=0; i<no_nodes; i++) {
      igraph_real_t x1=minx ? VECTOR(*minx)[i] : -width/2;
      igraph_real_t x2=maxx ? VECTOR(*maxx)[i] :  width/2;
      igraph_real_t y1=miny ? VECTOR(*miny)[i] : -height/2;
      igraph_real_t y2=maxy ? VECTOR(*maxy)[i] :  height/2;
      if (!igraph_finite(x1)) { x1 = -sqrt(no_nodes)/2; }
      if (!igraph_finite(x2)) { x2 =  sqrt(no_nodes)/2; }
      if (!igraph_finite(y1)) { y1 = -sqrt(no_nodes)/2; }
      if (!igraph_finite(y2)) { y2 =  sqrt(no_nodes)/2; }
      MATRIX(*res, i, 0) = RNG_UNIF(x1, x2);
      MATRIX(*res, i, 1) = RNG_UNIF(y1, y2);
    }
  }

  IGRAPH_CHECK(igraph_vector_float_init(&dispx, no_nodes));
  IGRAPH_FINALLY(igraph_vector_float_destroy, &dispx);
  IGRAPH_CHECK(igraph_vector_float_init(&dispy, no_nodes));
  IGRAPH_FINALLY(igraph_vector_float_destroy, &dispy);

  for (i=0; i<niter; i++) {
    igraph_integer_t v, u, e;

    /* calculate repulsive forces, we have a special version
       for unconnected graphs */
    igraph_vector_float_null(&dispx);
    igraph_vector_float_null(&dispy);
    if (conn) {
      for (v=0; v<no_nodes; v++) {
	for (u=v+1; u<no_nodes; u++) {
	  float dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0);
	  float dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1);
	  float dlen=dx * dx + dy * dy;

          if (dlen == 0) {
            dx = RNG_UNIF01() * 1e-9;
            dy = RNG_UNIF01() * 1e-9;
            dlen = dx * dx + dy * dy;
          }

	  VECTOR(dispx)[v] += dx/dlen;
	  VECTOR(dispy)[v] += dy/dlen;
	  VECTOR(dispx)[u] -= dx/dlen;
	  VECTOR(dispy)[u] -= dy/dlen;
	}
      }
    } else {
      for (v=0; v<no_nodes; v++) {
	for (u=v+1; u<no_nodes; u++) {
	  float dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0);
	  float dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1);
	  float dlen, rdlen;

	  dlen=dx * dx + dy * dy;
          if (dlen == 0) {
            dx = RNG_UNIF(0, 1e-6);
            dy = RNG_UNIF(0, 1e-6);
            dlen = dx * dx + dy * dy;
          }

	  rdlen=sqrt(dlen);

	  VECTOR(dispx)[v] += dx * (C-dlen * rdlen) / (dlen*C);
	  VECTOR(dispy)[v] += dy * (C-dlen * rdlen) / (dlen*C);
	  VECTOR(dispx)[u] -= dx * (C-dlen * rdlen) / (dlen*C);
	  VECTOR(dispy)[u] -= dy * (C-dlen * rdlen) / (dlen*C);
	}
      }
    }

    /* calculate attractive forces */
    for (e=0; e<no_edges; e++) {
      /* each edges is an ordered pair of vertices v and u */
      igraph_integer_t v=IGRAPH_FROM(graph, e);
      igraph_integer_t u=IGRAPH_TO(graph, e);
      igraph_real_t dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0);
      igraph_real_t dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1);
      igraph_real_t w=weight ? VECTOR(*weight)[e] : 1.0;
      igraph_real_t dlen=sqrt(dx * dx + dy * dy) * w;
      VECTOR(dispx)[v] -= (dx * dlen);
      VECTOR(dispy)[v] -= (dy * dlen);
      VECTOR(dispx)[u] += (dx * dlen);
      VECTOR(dispy)[u] += (dy * dlen);
    }

    /* limit max displacement to temperature t and prevent from
       displacement outside frame */
    for (v=0; v<no_nodes; v++) {
      igraph_real_t dx=VECTOR(dispx)[v] + RNG_UNIF01() * 1e-9;
      igraph_real_t dy=VECTOR(dispy)[v] + RNG_UNIF01() * 1e-9;
      igraph_real_t displen=sqrt(dx * dx + dy * dy);
      igraph_real_t mx=fabs(dx) < temp ? dx : temp;
      igraph_real_t my=fabs(dy) < temp ? dy : temp;
      if (displen > 0) {
        MATRIX(*res, v, 0) += (dx / displen) * mx;
        MATRIX(*res, v, 1) += (dy / displen) * my;
      }
      if (minx && MATRIX(*res, v, 0) < VECTOR(*minx)[v]) {
	MATRIX(*res, v, 0) = VECTOR(*minx)[v];
      }
      if (maxx && MATRIX(*res, v, 0) > VECTOR(*maxx)[v]) {
	MATRIX(*res, v, 0) = VECTOR(*maxx)[v];
      }
      if (miny && MATRIX(*res, v, 1) < VECTOR(*miny)[v]) {
	MATRIX(*res, v, 1) = VECTOR(*miny)[v];
      }
      if (maxy && MATRIX(*res, v, 1) > VECTOR(*maxy)[v]) {
	MATRIX(*res, v, 1) = VECTOR(*maxy)[v];
      }
    }

    temp -= difftemp;
  }

  RNG_END();

  igraph_vector_float_destroy(&dispx);
  igraph_vector_float_destroy(&dispy);
  IGRAPH_FINALLY_CLEAN(2);
  
  return 0;
}
Exemple #21
0
integer_t Edge::destination() {
    return IGRAPH_TO(m_pGraph->c_graph(), m_index);
}
Exemple #22
0
int igraph_get_incidence(const igraph_t *graph,
			 const igraph_vector_bool_t *types,
			 igraph_matrix_t *res,
			 igraph_vector_t *row_ids,
			 igraph_vector_t *col_ids) {
  
  long int no_of_nodes=igraph_vcount(graph);
  long int no_of_edges=igraph_ecount(graph);
  long int n1=0, n2=0, i;
  igraph_vector_t perm;
  long int p1, p2;

  if (igraph_vector_bool_size(types) != no_of_nodes) {
    IGRAPH_ERROR("Invalid vertex type vector for bipartite graph", 
		 IGRAPH_EINVAL);
  }
  
  for (i=0; i<no_of_nodes; i++) {
    n1 += VECTOR(*types)[i] == 0 ? 1 : 0;
  }
  n2 = no_of_nodes-n1;

  IGRAPH_VECTOR_INIT_FINALLY(&perm, no_of_nodes);
  
  for (i=0, p1=0, p2=n1; i<no_of_nodes; i++) {
    VECTOR(perm)[i] = VECTOR(*types)[i] ? p2++ : p1++;
  }
  
  IGRAPH_CHECK(igraph_matrix_resize(res, n1, n2));
  igraph_matrix_null(res);
  for (i=0; i<no_of_edges; i++) {
    long int from=IGRAPH_FROM(graph, i);
    long int to=IGRAPH_TO(graph, i);
    long int from2=(long int) VECTOR(perm)[from];
    long int to2=(long int) VECTOR(perm)[to];
    if (! VECTOR(*types)[from]) {
      MATRIX(*res, from2, to2-n1) += 1;
    } else {
      MATRIX(*res, to2, from2-n1) += 1;
    }
  }

  if (row_ids) { 
    IGRAPH_CHECK(igraph_vector_resize(row_ids, n1));
  }
  if (col_ids) {
    IGRAPH_CHECK(igraph_vector_resize(col_ids, n2));
  }
  if (row_ids || col_ids) {
    for (i=0; i<no_of_nodes; i++) {
      if (! VECTOR(*types)[i]) {
	if (row_ids) {
	  long int i2=(long int) VECTOR(perm)[i];
	  VECTOR(*row_ids)[i2] = i;
	}
      } else {
	if (col_ids) {
	  long int i2=(long int) VECTOR(perm)[i];
	  VECTOR(*col_ids)[i2-n1] = i;
	}
      }
    }
  }

  igraph_vector_destroy(&perm);
  IGRAPH_FINALLY_CLEAN(1);
  return 0;
}
Exemple #23
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;
}
Exemple #24
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;
}