Esempio n. 1
0
int igraph_i_is_separator(const igraph_t *graph,
			  igraph_vit_t *vit,
			  long int except,
			  igraph_bool_t *res,
			  igraph_vector_bool_t *removed,
			  igraph_dqueue_t *Q,
			  igraph_vector_t *neis,
			  long int no_of_nodes) {

  long int start=0;

  if (IGRAPH_VIT_SIZE(*vit) >= no_of_nodes-1) {
    /* Just need to check that we really have at least n-1 vertices in it */
    igraph_vector_bool_t hit;
    long int nohit=0;
    IGRAPH_CHECK(igraph_vector_bool_init(&hit, no_of_nodes));
    IGRAPH_FINALLY(igraph_vector_bool_destroy, &hit);
    for (IGRAPH_VIT_RESET(*vit); 
	 !IGRAPH_VIT_END(*vit); 
	 IGRAPH_VIT_NEXT(*vit)) {
      long int v=IGRAPH_VIT_GET(*vit);
      if (!VECTOR(hit)[v]) {
	nohit++;
	VECTOR(hit)[v] = 1;
      }
    }
    igraph_vector_bool_destroy(&hit);
    IGRAPH_FINALLY_CLEAN(1);
    if (nohit >= no_of_nodes-1) {
      *res = 0;
      return 0;
    }
  }
  
  /* Remove the given vertices from the graph, do a breadth-first
     search and check the number of components */  

  if (except < 0) {
    for (IGRAPH_VIT_RESET(*vit); 
	 !IGRAPH_VIT_END(*vit);
	 IGRAPH_VIT_NEXT(*vit)) {
      VECTOR(*removed)[ (long int) IGRAPH_VIT_GET(*vit) ] = 1;
    }
  } else {
    /* There is an exception */
    long int i;
    for (i=0, IGRAPH_VIT_RESET(*vit);
	 i<except; 
	 i++, IGRAPH_VIT_NEXT(*vit)) {
      VECTOR(*removed)[ (long int) IGRAPH_VIT_GET(*vit) ] = 1;
    }
    for (IGRAPH_VIT_NEXT(*vit); 
	 !IGRAPH_VIT_END(*vit); 
	 IGRAPH_VIT_NEXT(*vit)) {
      VECTOR(*removed)[ (long int) IGRAPH_VIT_GET(*vit) ] = 1;
    }
  }

  /* Look for the first node that is not removed */
  while (start < no_of_nodes && VECTOR(*removed)[start]) start++;
  
  if (start==no_of_nodes) { 
    IGRAPH_ERROR("All vertices are included in the separator", 
		 IGRAPH_EINVAL);
  }
  
  igraph_dqueue_push(Q, start);
  VECTOR(*removed)[start]=1;
  while (!igraph_dqueue_empty(Q)) {
    long int node=(long int) igraph_dqueue_pop(Q);
    long int j, n;
    igraph_neighbors(graph, neis, (igraph_integer_t) node, IGRAPH_ALL);
    n=igraph_vector_size(neis);
    for (j=0; j<n; j++) {
      long int nei=(long int) VECTOR(*neis)[j];
      if (!VECTOR(*removed)[nei]) {
	IGRAPH_CHECK(igraph_dqueue_push(Q, nei));
	VECTOR(*removed)[nei]=1;
      }
    }
  }
  
  /* Look for the next node that was neighter removed, not visited */
  while (start < no_of_nodes && VECTOR(*removed)[start]) start++;
  
  /* If there is another component, then we have a separator */
  *res = (start < no_of_nodes);

  return 0;
}
Esempio n. 2
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;
}
Esempio n. 3
0
/**
 * \ingroup structural
 * \function igraph_betweenness_estimate
 * \brief Estimated betweenness centrality of some vertices.
 * 
 * </para><para>
 * The betweenness centrality of a vertex is the number of geodesics
 * going through it. If there are more than one geodesic between two
 * vertices, the value of these geodesics are weighted by one over the 
 * number of geodesics. When estimating betweenness centrality, igraph
 * takes into consideration only those paths that are shorter than or
 * equal to a prescribed length. Note that the estimated centrality
 * will always be less than the real one.
 *
 * \param graph The graph object.
 * \param res The result of the computation, a vector containing the
 *        estimated betweenness scores for the specified vertices.
 * \param vids The vertices of which the betweenness centrality scores
 *        will be estimated.
 * \param directed Logical, if true directed paths will be considered
 *        for directed graphs. It is ignored for undirected graphs.
 * \param cutoff The maximal length of paths that will be considered.
 *        If zero or negative, the exact betweenness will be calculated
 *        (no upper limit on path lengths).
 * \return Error code:
 *        \c IGRAPH_ENOMEM, not enough memory for
 *        temporary data. 
 *        \c IGRAPH_EINVVID, invalid vertex id passed in
 *        \p vids. 
 *
 * Time complexity: O(|V||E|),
 * |V| and 
 * |E| are the number of vertices and
 * edges in the graph. 
 * Note that the time complexity is independent of the number of
 * vertices for which the score is calculated.
 *
 * \sa Other centrality types: \ref igraph_degree(), \ref igraph_closeness().
 *     See \ref igraph_edge_betweenness() for calculating the betweenness score
 *     of the edges in a graph.
 */
int igraph_betweenness_estimate(const igraph_t *graph, igraph_vector_t *res, 
			const igraph_vs_t vids, igraph_bool_t directed,
                        igraph_integer_t cutoff) {

  long int no_of_nodes=igraph_vcount(graph);
  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
  long int *distance;
  long int *nrgeo;
  double *tmpscore;
  igraph_stack_t stack=IGRAPH_STACK_NULL;
  long int source;
  long int j, k;
  igraph_integer_t modein, modeout;
  igraph_vit_t vit;
  igraph_vector_t *neis;

  igraph_adjlist_t adjlist_out, adjlist_in;
  igraph_adjlist_t *adjlist_out_p, *adjlist_in_p;

  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
  IGRAPH_FINALLY(igraph_vit_destroy, &vit);

  directed=directed && igraph_is_directed(graph);
  if (directed) {
    modeout=IGRAPH_OUT;
    modein=IGRAPH_IN;
    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist_out, IGRAPH_OUT));
    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist_out);
    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist_in, IGRAPH_IN));
    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist_in);
    adjlist_out_p=&adjlist_out;
    adjlist_in_p=&adjlist_in;
  } else {
    modeout=modein=IGRAPH_ALL;
    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist_out, IGRAPH_ALL));
    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist_out);
    adjlist_out_p=adjlist_in_p=&adjlist_out;
  }
  
  distance=igraph_Calloc(no_of_nodes, long int);
  if (distance==0) {
    IGRAPH_ERROR("betweenness failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, distance);
  nrgeo=igraph_Calloc(no_of_nodes, long int);
  if (nrgeo==0) {
    IGRAPH_ERROR("betweenness failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, nrgeo);
  tmpscore=igraph_Calloc(no_of_nodes, double);
  if (tmpscore==0) {
    IGRAPH_ERROR("betweenness failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, tmpscore);

  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
  igraph_stack_init(&stack, no_of_nodes);
  IGRAPH_FINALLY(igraph_stack_destroy, &stack);
    
  IGRAPH_CHECK(igraph_vector_resize(res, IGRAPH_VIT_SIZE(vit)));
  igraph_vector_null(res);

  /* here we go */
  
  for (source=0; source<no_of_nodes; source++) {
    IGRAPH_PROGRESS("Betweenness centrality: ", 100.0*source/no_of_nodes, 0);
    IGRAPH_ALLOW_INTERRUPTION();

    memset(distance, 0, no_of_nodes*sizeof(long int));
    memset(nrgeo, 0, no_of_nodes*sizeof(long int));
    memset(tmpscore, 0, no_of_nodes*sizeof(double));
    igraph_stack_clear(&stack); /* it should be empty anyway... */
    
    IGRAPH_CHECK(igraph_dqueue_push(&q, source));
    nrgeo[source]=1;
    distance[source]=0;
    
    while (!igraph_dqueue_empty(&q)) {
      long int actnode=igraph_dqueue_pop(&q);

      if (cutoff > 0 && distance[actnode] >= cutoff) continue;
       
      neis = igraph_adjlist_get(adjlist_out_p, actnode);
      for (j=0; j<igraph_vector_size(neis); j++) {
        long int neighbor=VECTOR(*neis)[j];
        if (nrgeo[neighbor] != 0) {
	      /* we've already seen this node, another shortest path? */
	      if (distance[neighbor]==distance[actnode]+1) {
	        nrgeo[neighbor]+=nrgeo[actnode];
	      }
	    } else {
	      /* we haven't seen this node yet */
	      nrgeo[neighbor]+=nrgeo[actnode];
              distance[neighbor]=distance[actnode]+1;
	      IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
	      IGRAPH_CHECK(igraph_stack_push(&stack, neighbor));
	    }
      }
    } /* while !igraph_dqueue_empty */

    /* Ok, we've the distance of each node and also the number of
       shortest paths to them. Now we do an inverse search, starting
       with the farthest nodes. */
    while (!igraph_stack_empty(&stack)) {
      long int actnode=igraph_stack_pop(&stack);      
      if (distance[actnode]<=1) { continue; } /* skip source node */
      
      /* set the temporary score of the friends */
      neis = igraph_adjlist_get(adjlist_in_p, actnode);
      for (j=0; j<igraph_vector_size(neis); j++) {
        long int neighbor=VECTOR(*neis)[j];
	    if (distance[neighbor]==distance[actnode]-1 && nrgeo[neighbor] != 0) {
	      tmpscore[neighbor] += 
	        (tmpscore[actnode]+1)*nrgeo[neighbor]/nrgeo[actnode];
	    }
      }
    }
    
    /* Ok, we've the scores for this source */
    for (k=0, IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); 
	 IGRAPH_VIT_NEXT(vit), k++) {
      long int node=IGRAPH_VIT_GET(vit);
      VECTOR(*res)[k] += tmpscore[node];
      tmpscore[node] = 0.0; /* in case a node is in vids multiple times */
    }

  } /* for source < no_of_nodes */

  /* divide by 2 for undirected graph */
  if (!directed) {
    for (j=0; j<igraph_vector_size(res); j++) {
      VECTOR(*res)[j] /= 2.0;
    }
  }
  
  /* clean  */
  igraph_Free(distance);
  igraph_Free(nrgeo);
  igraph_Free(tmpscore);
  
  igraph_dqueue_destroy(&q);
  igraph_stack_destroy(&stack);
  igraph_vit_destroy(&vit);
  IGRAPH_FINALLY_CLEAN(6);

  if (directed) {
    igraph_adjlist_destroy(&adjlist_out);
    igraph_adjlist_destroy(&adjlist_in);
    IGRAPH_FINALLY_CLEAN(2);
  } else {
    igraph_adjlist_destroy(&adjlist_out);
    IGRAPH_FINALLY_CLEAN(1);
  }

  return 0;
}
Esempio n. 4
0
/**
 * \ingroup structural
 * \function igraph_closeness_estimate
 * \brief Closeness centrality estimations for some vertices.
 *
 * </para><para>
 * The closeness centrality of a vertex measures how easily other
 * vertices can be reached from it (or the other way: how easily it
 * can be reached from the other vertices). It is defined as the
 * number of the number of vertices minus one divided by the sum of the
 * lengths of all geodesics from/to the given vertex. When estimating
 * closeness centrality, igraph considers paths having a length less than
 * or equal to a prescribed cutoff value.
 *
 * </para><para>
 * If the graph is not connected, and there is no such path between two
 * vertices, the number of vertices is used instead the length of the
 * geodesic. This is always longer than the longest possible geodesic.
 *
 * </para><para>
 * Since the estimation considers vertex pairs with a distance greater than
 * the given value as disconnected, the resulting estimation will always be
 * lower than the actual closeness centrality.
 * 
 * \param graph The graph object.
 * \param res The result of the computation, a vector containing the
 *        closeness centrality scores for the given vertices.
 * \param vids Vector giving the vertices for which the closeness
 *        centrality scores will be computed.
 * \param mode The type of shortest paths to be used for the
 *        calculation in directed graphs. Possible values: 
 *        \clist
 *        \cli IGRAPH_OUT 
 *          the lengths of the outgoing paths are calculated. 
 *        \cli IGRAPH_IN 
 *          the lengths of the incoming paths are calculated. 
 *        \cli IGRAPH_ALL
 *          the directed graph is considered as an
 *          undirected one for the computation.
 *        \endclist
 * \param cutoff The maximal length of paths that will be considered.
 *        If zero or negative, the exact closeness will be calculated
 *        (no upper limit on path lengths).
 * \return Error code:
 *        \clist
 *        \cli IGRAPH_ENOMEM
 *           not enough memory for temporary data.
 *        \cli IGRAPH_EINVVID
 *           invalid vertex id passed.
 *        \cli IGRAPH_EINVMODE
 *           invalid mode argument.
 *        \endclist
 *
 * Time complexity: O(n|E|),
 * n is the number 
 * of vertices for which the calculation is done and
 * |E| is the number 
 * of edges in the graph.
 *
 * \sa Other centrality types: \ref igraph_degree(), \ref igraph_betweenness().
 */
int igraph_closeness_estimate(const igraph_t *graph, igraph_vector_t *res, 
		              const igraph_vs_t vids, igraph_neimode_t mode,
                              igraph_integer_t cutoff) {
  long int no_of_nodes=igraph_vcount(graph);
  igraph_vector_t already_counted, *neis;
  long int i, j;
  long int nodes_reached;
  igraph_adjlist_t allneis;

  igraph_dqueue_t q;
  
  long int nodes_to_calc;
  igraph_vit_t vit;

  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
  IGRAPH_FINALLY(igraph_vit_destroy, &vit);

  nodes_to_calc=IGRAPH_VIT_SIZE(vit);
  
  if (mode != IGRAPH_OUT && mode != IGRAPH_IN && 
      mode != IGRAPH_ALL) {
    IGRAPH_ERROR("calculating closeness", IGRAPH_EINVMODE);
  }

  IGRAPH_VECTOR_INIT_FINALLY(&already_counted, no_of_nodes);
  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);

  IGRAPH_CHECK(igraph_adjlist_init(graph, &allneis, mode));
  IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis);

  IGRAPH_CHECK(igraph_vector_resize(res, nodes_to_calc));
  igraph_vector_null(res);
  
  for (IGRAPH_VIT_RESET(vit), i=0; 
       !IGRAPH_VIT_END(vit); 
       IGRAPH_VIT_NEXT(vit), i++) {
    IGRAPH_CHECK(igraph_dqueue_push(&q, IGRAPH_VIT_GET(vit)));
    IGRAPH_CHECK(igraph_dqueue_push(&q, 0));
    nodes_reached=1;
    VECTOR(already_counted)[(long int)IGRAPH_VIT_GET(vit)]=i+1;

    IGRAPH_PROGRESS("Closeness: ", 100.0*i/no_of_nodes, NULL);
    IGRAPH_ALLOW_INTERRUPTION();
    
    while (!igraph_dqueue_empty(&q)) {
      long int act=igraph_dqueue_pop(&q);
      long int actdist=igraph_dqueue_pop(&q);
      
      VECTOR(*res)[i] += actdist;

      if (cutoff>0 && actdist>=cutoff) continue;

      neis=igraph_adjlist_get(&allneis, act);
      for (j=0; j<igraph_vector_size(neis); j++) {
        long int neighbor=VECTOR(*neis)[j];
        if (VECTOR(already_counted)[neighbor] == i+1) { continue; }
        VECTOR(already_counted)[neighbor] = i+1;
        nodes_reached++;
        IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
        IGRAPH_CHECK(igraph_dqueue_push(&q, actdist+1));
      }
    }
    VECTOR(*res)[i] += ((igraph_integer_t)no_of_nodes * (no_of_nodes-nodes_reached));
    VECTOR(*res)[i] = (no_of_nodes-1) / VECTOR(*res)[i];
  }

  IGRAPH_PROGRESS("Closeness: ", 100.0, NULL);

  /* Clean */
  igraph_dqueue_destroy(&q);
  igraph_vector_destroy(&already_counted);
  igraph_vit_destroy(&vit);
  igraph_adjlist_destroy(&allneis);
  IGRAPH_FINALLY_CLEAN(4);
  
  return 0;
}