Example #1
0
int igraph_attribute_combination_remove(igraph_attribute_combination_t *comb, 
					const char *name) {
  long int i, n=igraph_vector_ptr_size(&comb->list);

  /* Search, in case it is already there */
  for (i=0; i<n; i++) {
    igraph_attribute_combination_record_t *r=VECTOR(comb->list)[i];
    const char *n=r->name;
    if ( (!name && !n) ||
	 (name && n && !strcmp(n, name)) ) {
      break;
    }
  }
  
  if (i!=n) {
    igraph_attribute_combination_record_t *r=VECTOR(comb->list)[i];
    if (r->name) { igraph_Free(r->name); }
    igraph_Free(r);
    igraph_vector_ptr_remove(&comb->list, i);
  } else {
    /* It is not there, we don't do anything */
  }
  
  return 0;
}
Example #2
0
void igraph_attribute_combination_destroy(igraph_attribute_combination_t *comb) {
  long int i, n=igraph_vector_ptr_size(&comb->list);
  for (i=0; i<n; i++) {
    igraph_attribute_combination_record_t *rec=VECTOR(comb->list)[i];
    if (rec->name) { igraph_Free(rec->name); }
    igraph_Free(rec);    
  }
  igraph_vector_ptr_destroy(&comb->list);
}
int main() {
  
  igraph_t graph;
  igraph_vector_ptr_t separators;
  long int i, n;
  
  igraph_famous(&graph, "zachary");
  igraph_vector_ptr_init(&separators, 0);
  igraph_all_minimal_st_separators(&graph, &separators);

  n=igraph_vector_ptr_size(&separators);
  for (i=0; i<n; i++) {
    igraph_bool_t res;
    igraph_vector_t *sep=VECTOR(separators)[i];
    igraph_is_separator(&graph, igraph_vss_vector(sep), &res);
    if (!res) { 
      printf("Vertex set %li is not a separator!\n", i);
      igraph_vector_print(sep);
      return 1;
    }
  }

  igraph_destroy(&graph);
  for (i=0; i<n; i++) {
    igraph_vector_t *v=VECTOR(separators)[i];
    igraph_vector_destroy(v);
    igraph_Free(v);
  }
  igraph_vector_ptr_destroy(&separators);
  
  return 0;
}
Example #4
0
void igraph_vector_ptr_destroy   (igraph_vector_ptr_t* v) {
  assert(v != 0);
  if (v->stor_begin != 0) {
    igraph_Free(v->stor_begin);
    v->stor_begin = NULL;
  }
}
Example #5
0
void igraph_adjlist_destroy(igraph_adjlist_t *al) {
  long int i;
  for (i=0; i<al->length; i++) {
    if (&al->adjs[i]) { igraph_vector_destroy(&al->adjs[i]); }
  }
  igraph_Free(al->adjs);
}
Example #6
0
void igraph_stack_ptr_free_all   (igraph_stack_ptr_t* v) {
  void **ptr;
  assert(v != 0);
  assert(v->stor_begin != 0);
  for (ptr=v->stor_begin; ptr<v->end; ptr++) {
    igraph_Free(*ptr);
  }
}
Example #7
0
void igraph_i_free_set_array(igraph_set_t* array) {
  long int i = 0;
  while (igraph_set_inited(array+i)) {
    igraph_set_destroy(array+i);
    i++;
  }
  igraph_Free(array);
}
Example #8
0
void igraph_i_union_many_free3(igraph_vector_ptr_t *v) {
  long int i, n=igraph_vector_ptr_size(v);
  for (i=0; i<n; i++) { 
    if (VECTOR(*v)[i] != 0) {
      igraph_vector_destroy(VECTOR(*v)[i]);
      igraph_Free(VECTOR(*v)[i]);
    }
  }
}
Example #9
0
void igraph_inclist_destroy(igraph_inclist_t *il) {
  long int i;
  for (i=0; i<il->length; i++) {
    /* This works if some igraph_vector_t's are 0, because igraph_vector_destroy can
       handle this. */
    igraph_vector_destroy(&il->incs[i]);
  }
  igraph_Free(il->incs);
}
Example #10
0
/**
 * \function igraph_lazy_inclist_clear
 * Removes all edges from a lazy incidence list.
 *
 * \param il The lazy incidence list.
 * Time complexity: depends on memory management, typically O(n), where n is
 * the total number of elements in the incidence list.
 */
void igraph_lazy_inclist_clear(igraph_lazy_inclist_t *il) {
  long int i, n=il->length;
  for (i=0; i<n; i++) {
    if (il->incs[i] != 0) {
      igraph_vector_destroy(il->incs[i]);
      igraph_Free(il->incs[i]);
    }
  }
}
Example #11
0
/**
 * \function igraph_lazy_adjlist_clear
 * Removes all edges from a lazy adjacency list.
 *
 * \param al The lazy adjacency list.
 * Time complexity: depends on memory management, typically O(n), where n is
 * the total number of elements in the adjacency list.
 */
void igraph_lazy_adjlist_clear(igraph_lazy_adjlist_t *al) {
  long int i, n=al->length;
  for (i=0; i<n; i++) {
    if (al->adjs[i] != 0) {
      igraph_vector_destroy(al->adjs[i]);
      igraph_Free(al->adjs[i]);
    }
  }
}
Example #12
0
int igraph_adjlist_init_complementer(const igraph_t *graph,
				       igraph_adjlist_t *al, 
				       igraph_neimode_t mode,
				       igraph_bool_t loops) {
  long int i, j, k, n;
  igraph_bool_t* seen;
  igraph_vector_t vec;

  if (mode != IGRAPH_IN && mode != IGRAPH_OUT && mode != IGRAPH_ALL) {
    IGRAPH_ERROR("Cannot create complementer adjlist view", IGRAPH_EINVMODE);
  }

  if (!igraph_is_directed(graph)) { mode=IGRAPH_ALL; }

  al->length=igraph_vcount(graph);
  al->adjs=igraph_Calloc(al->length, igraph_vector_t);
  if (al->adjs == 0) {
    IGRAPH_ERROR("Cannot create complementer adjlist view", IGRAPH_ENOMEM);
  }

  IGRAPH_FINALLY(igraph_adjlist_destroy, al);

  n=al->length;
  seen=igraph_Calloc(n, igraph_bool_t);
  if (seen==0) {
    IGRAPH_ERROR("Cannot create complementer adjlist view", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, seen);

  IGRAPH_VECTOR_INIT_FINALLY(&vec, 0);

  for (i=0; i<al->length; i++) {
    IGRAPH_ALLOW_INTERRUPTION();
    igraph_neighbors(graph, &vec, i, mode);
    memset(seen, 0, sizeof(igraph_bool_t)*al->length);
    n=al->length;
    if (!loops) { seen[i] = 1; n--; }
    for (j=0; j<igraph_vector_size(&vec); j++) {
      if (! seen [ (long int) VECTOR(vec)[j] ] ) {
	n--;
	seen[ (long int) VECTOR(vec)[j] ] = 1;
      }
    }
    IGRAPH_CHECK(igraph_vector_init(&al->adjs[i], n));
    for (j=0, k=0; k<n; j++) {
      if (!seen[j]) {
	VECTOR(al->adjs[i])[k++] = j;
      }
    }
  }

  igraph_Free(seen);
  igraph_vector_destroy(&vec);
  IGRAPH_FINALLY_CLEAN(3);
  return 0;
}
Example #13
0
void igraph_vector_ptr_free_all   (igraph_vector_ptr_t* v) {
  void **ptr;
  assert(v != 0);
  assert(v->stor_begin != 0);

  igraph_i_vector_ptr_call_item_destructor_all(v);
  for (ptr=v->stor_begin; ptr<v->end; ptr++) {
    igraph_Free(*ptr);
  }
}
Example #14
0
void igraph_i_separators_free(igraph_vector_ptr_t *separators) {
  long int i, n=igraph_vector_ptr_size(separators);
  for (i=0; i<n; i++) {
    igraph_vector_t *vec=VECTOR(*separators)[i];
    if (vec) {   
      igraph_vector_destroy(vec);
      igraph_Free(vec);
    }
  }
}
Example #15
0
void igraph_i_free_vectorlist(igraph_vector_ptr_t *list) {
  long int i, n=igraph_vector_ptr_size(list);
  for (i=0; i<n; i++) {
    igraph_vector_t *v=VECTOR(*list)[i];
    if (v) { 
      igraph_vector_destroy(v);
      igraph_Free(v);
    }
  }
  igraph_vector_ptr_destroy(list);
}
Example #16
0
int igraph_is_connected_weak(const igraph_t *graph, igraph_bool_t *res) {

  long int no_of_nodes=igraph_vcount(graph);
  char *already_added;
  igraph_vector_t neis=IGRAPH_VECTOR_NULL;
  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
  
  long int i, j;

  if (no_of_nodes == 0) {
    *res = 1;
    return IGRAPH_SUCCESS;
  }

  already_added=igraph_Calloc(no_of_nodes, char);
  if (already_added==0) {
    IGRAPH_ERROR("is connected (weak) failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(free, already_added); /* TODO: hack */

  IGRAPH_DQUEUE_INIT_FINALLY(&q, 10);
  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
  
  /* Try to find at least two clusters */
  already_added[0]=1;
  IGRAPH_CHECK(igraph_dqueue_push(&q, 0));
  
  j=1;
  while ( !igraph_dqueue_empty(&q)) {
    long int actnode=(long int) igraph_dqueue_pop(&q);
    IGRAPH_ALLOW_INTERRUPTION();
    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) actnode,
				  IGRAPH_ALL));
    for (i=0; i <igraph_vector_size(&neis); i++) {
      long int neighbor=(long int) VECTOR(neis)[i];
      if (already_added[neighbor] != 0) { continue; }
      IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
      j++;
      already_added[neighbor]++;
    }
  }
  
  /* Connected? */
  *res = (j == no_of_nodes);

  igraph_Free(already_added);
  igraph_dqueue_destroy(&q);
  igraph_vector_destroy(&neis);
  IGRAPH_FINALLY_CLEAN(3);

  return 0;
}
Example #17
0
int igraph_biguint_fprint(igraph_biguint_t *b, FILE *file) {

  /* It is hard to control memory allocation for the bn2d function,
     so we do our own version */

  long int n=igraph_biguint_size(b);
  long int size=12*n+1;
  igraph_biguint_t tmp;
  char *dst;
  limb_t r;

  /* Zero? */
  if (!bn_cmp_limb(VECTOR(b->v), 0, n)) {
    fputs("0", file);
    return 0;
  }
  
  IGRAPH_CHECK(igraph_biguint_copy(&tmp, b));
  IGRAPH_FINALLY(igraph_biguint_destroy, &tmp);
  dst=igraph_Calloc(size, char);
  if (!dst) {
    IGRAPH_ERROR("Cannot print big number", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, dst);
  
  size--;
  dst[size]='\0';
  while (0 != bn_cmp_limb(VECTOR(tmp.v), 0, n)) {
    r=bn_div_limb(VECTOR(tmp.v), VECTOR(tmp.v), 10, n);
    dst[--size] = '0' + r;
  }

  fputs(&dst[size], file);
  
  igraph_Free(dst);
  igraph_biguint_destroy(&tmp);
  IGRAPH_FINALLY_CLEAN(2);
  
  return 0;
}
Example #18
0
/**
 * \ingroup nongraph
 * \function igraph_convex_hull
 * \brief Determines the convex hull of a given set of points in the 2D plane
 *
 * </para><para>
 * The convex hull is determined by the Graham scan algorithm.
 * See the following reference for details:
 * 
 * </para><para>
 * Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford
 * Stein. Introduction to Algorithms, Second Edition. MIT Press and
 * McGraw-Hill, 2001. ISBN 0262032937. Pages 949-955 of section 33.3:
 * Finding the convex hull.
 * 
 * \param data vector containing the coordinates. The length of the
 *        vector must be even, since it contains X-Y coordinate pairs.
 * \param resverts the vector containing the result, e.g. the vector of
 *        vertex indices used as the corners of the convex hull. Supply
 *        \c NULL here if you are only interested in the coordinates of
 *        the convex hull corners.
 * \param rescoords the matrix containing the coordinates of the selected
 *        corner vertices. Supply \c NULL here if you are only interested in
 *        the vertex indices.
 * \return Error code:
 *         \c IGRAPH_ENOMEM: not enough memory
 * 
 * Time complexity: O(n log(n)) where n is the number of vertices
 */
int igraph_convex_hull(const igraph_matrix_t *data, igraph_vector_t *resverts,
		       igraph_matrix_t *rescoords) {
  igraph_integer_t no_of_nodes;
  long int i, pivot_idx=0, last_idx, before_last_idx, next_idx, j;
  igraph_real_t* angles;
  igraph_vector_t stack;
  igraph_indheap_t order;
  igraph_real_t px, py, cp;
  
  no_of_nodes=igraph_matrix_nrow(data);
  if (igraph_matrix_ncol(data) != 2) {
    IGRAPH_ERROR("matrix must have 2 columns", IGRAPH_EINVAL);
  }
  if (no_of_nodes == 0) {
    if (resverts != 0) {
      IGRAPH_CHECK(igraph_vector_resize(resverts, 0));
    } 
    if (rescoords != 0) {
      IGRAPH_CHECK(igraph_matrix_resize(rescoords, 0, 2));
    }
    /**************************** this is an exit here *********/
    return 0;
  }
    
  angles=igraph_Calloc(no_of_nodes, igraph_real_t);
  if (!angles) IGRAPH_ERROR("not enough memory for angle array", IGRAPH_ENOMEM);
  IGRAPH_FINALLY(free, angles);
  
  IGRAPH_VECTOR_INIT_FINALLY(&stack, 0);
  
  /* Search for the pivot vertex */
  for (i=1; i<no_of_nodes; i++) {
    if (MATRIX(*data, i, 1)<MATRIX(*data, pivot_idx, 1))
      pivot_idx=i;
    else if (MATRIX(*data, i, 1) == MATRIX(*data, pivot_idx, 1) &&
	     MATRIX(*data, i, 0) < MATRIX(*data, pivot_idx, 0))
      pivot_idx=i;
  }
  px=MATRIX(*data, pivot_idx, 0);
  py=MATRIX(*data, pivot_idx, 1);
  
  /* Create angle array */
  for (i=0; i<no_of_nodes; i++) {
    if (i == pivot_idx) {
      /* We can't calculate the angle of the pivot point with itself,
       * so we use 10 here. This way, after sorting the angle vector,
       * the pivot point will always be the first one, since the range
       * of atan2 is -3.14..3.14 */
      angles[i] = 10;
    } else {
      angles[i] = atan2(MATRIX(*data, i, 1)-py,
			MATRIX(*data, i, 0)-px);
    }
  }

  IGRAPH_CHECK(igraph_indheap_init_array(&order, angles, no_of_nodes));
  IGRAPH_FINALLY(igraph_indheap_destroy, &order);
  
  igraph_Free(angles);
  IGRAPH_FINALLY_CLEAN(1);

  if (no_of_nodes == 1) {
    IGRAPH_CHECK(igraph_vector_push_back(&stack, 0));
    igraph_indheap_delete_max(&order);
  } else {
    /* Do the trick */
    IGRAPH_CHECK(igraph_vector_push_back(&stack, igraph_indheap_max_index(&order)-1));
    igraph_indheap_delete_max(&order);
    IGRAPH_CHECK(igraph_vector_push_back(&stack, igraph_indheap_max_index(&order)-1));
    igraph_indheap_delete_max(&order);
    
    j=2;
    while (!igraph_indheap_empty(&order)) {
      /* Determine whether we are at a left or right turn */
      last_idx=VECTOR(stack)[j-1];
      before_last_idx=VECTOR(stack)[j-2];
      next_idx=(long)igraph_indheap_max_index(&order)-1;
      igraph_indheap_delete_max(&order);
      cp=(MATRIX(*data, last_idx, 0)-MATRIX(*data, before_last_idx, 0))*
	(MATRIX(*data, next_idx, 1)-MATRIX(*data, before_last_idx, 1))-
	(MATRIX(*data, next_idx, 0)-MATRIX(*data, before_last_idx, 0))*
	(MATRIX(*data, last_idx, 1)-MATRIX(*data, before_last_idx, 1));
      /*
       printf("B L N cp: %d, %d, %d, %f [", before_last_idx, last_idx, next_idx, (float)cp);
       for (k=0; k<j; k++) printf("%ld ", (long)VECTOR(stack)[k]);
       printf("]\n");
       */
      if (cp == 0) {
	/* The last three points are collinear. Replace the last one in
	 * the stack to the newest one */
	VECTOR(stack)[j-1]=next_idx;
      } else if (cp < 0) {
	/* We are turning into the right direction */
	IGRAPH_CHECK(igraph_vector_push_back(&stack, next_idx));
	j++;
      } else {
	/* No, skip back until we're okay */
	while (cp >= 0 && j > 2) {
	  igraph_vector_pop_back(&stack);
	  j--;
	  last_idx=VECTOR(stack)[j-1];
	  before_last_idx=VECTOR(stack)[j-2];
	  cp=(MATRIX(*data, last_idx, 0)-MATRIX(*data, before_last_idx, 0))*
	    (MATRIX(*data, next_idx, 1)-MATRIX(*data, before_last_idx, 1))-
	    (MATRIX(*data, next_idx, 0)-MATRIX(*data, before_last_idx, 0))*
	    (MATRIX(*data, last_idx, 1)-MATRIX(*data, before_last_idx, 1));
	}
	IGRAPH_CHECK(igraph_vector_push_back(&stack, next_idx));
	j++;
      }
    }
  }
  
  /* Create result vector */
  if (resverts != 0) {
    igraph_vector_clear(resverts);
    IGRAPH_CHECK(igraph_vector_append(resverts, &stack));
  } 
  if (rescoords != 0) {
    igraph_matrix_select_rows(data, rescoords, &stack);
  }
  
  /* Free everything */
  igraph_vector_destroy(&stack);
  igraph_indheap_destroy(&order);
  IGRAPH_FINALLY_CLEAN(2);
  
  return 0;
}
Example #19
0
int igraph_bfs(igraph_t *graph, igraph_integer_t vid, igraph_neimode_t mode,
	       igraph_vector_t *vids, igraph_vector_t *layers,
	       igraph_vector_t *parents) {   

  igraph_dqueue_t q;
  long int vidspos=0;
  igraph_vector_t neis;
  long int no_of_nodes=igraph_vcount(graph);
  long int i;
  char *added;
  long int lastlayer=-1;
  
  if (!igraph_is_directed(graph)) { mode=IGRAPH_ALL; }

  if (mode != IGRAPH_OUT && mode != IGRAPH_IN && 
      mode != IGRAPH_ALL) {
    IGRAPH_ERROR("Invalid mode argument", IGRAPH_EINVMODE);
  }
  
  /* temporary storage */
  added=igraph_Calloc(no_of_nodes, char);
  if (added==0) {
    IGRAPH_ERROR("Cannot calculate BFS", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, added);
  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
  IGRAPH_CHECK(igraph_dqueue_init(&q, 100));
  IGRAPH_FINALLY(igraph_dqueue_destroy, &q);

  /* results */
  IGRAPH_CHECK(igraph_vector_resize(vids, no_of_nodes));
  igraph_vector_clear(layers);
  IGRAPH_CHECK(igraph_vector_resize(parents, no_of_nodes));
  
  /* ok start with vid */
  IGRAPH_CHECK(igraph_dqueue_push(&q, vid));
  IGRAPH_CHECK(igraph_dqueue_push(&q, 0));
  IGRAPH_CHECK(igraph_vector_push_back(layers, vidspos)); 
  VECTOR(*vids)[vidspos++]=vid; 
  VECTOR(*parents)[(long int)vid]=vid;
  added[(long int)vid]=1;
  
  while (!igraph_dqueue_empty(&q)) {
    long int actvect=igraph_dqueue_pop(&q);
    long int actdist=igraph_dqueue_pop(&q);
    IGRAPH_CHECK(igraph_neighbors(graph, &neis, actvect, mode));
    for (i=0; i<igraph_vector_size(&neis); i++) {
      long int neighbor=VECTOR(neis)[i];
      if (added[neighbor]==0) {
	added[neighbor]=1;
	VECTOR(*parents)[neighbor]=actvect;
	IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
	IGRAPH_CHECK(igraph_dqueue_push(&q, actdist+1));
	if (lastlayer != actdist+1) { 
	  IGRAPH_CHECK(igraph_vector_push_back(layers, vidspos));
	}
	VECTOR(*vids)[vidspos++]=neighbor;
	lastlayer=actdist+1;
      }
    } /* for i in neis */
  } /* while ! dqueue_empty */
  IGRAPH_CHECK(igraph_vector_push_back(layers, vidspos));
  
  igraph_vector_destroy(&neis);
  igraph_dqueue_destroy(&q);
  igraph_Free(added);
  IGRAPH_FINALLY_CLEAN(3);
		 
  return 0;
}
Example #20
0
void igraph_lazy_adjlist_destroy(igraph_lazy_adjlist_t *al) {
  igraph_lazy_adjlist_clear(al);
  igraph_Free(al->adjs);
}
Example #21
0
int igraph_clusters_weak(const igraph_t *graph, igraph_vector_t *membership,
			 igraph_vector_t *csize, igraph_integer_t *no) {

  long int no_of_nodes=igraph_vcount(graph);
  char *already_added;
  long int first_node, act_cluster_size=0, no_of_clusters=1;
  
  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
  
  long int i;
  igraph_vector_t neis=IGRAPH_VECTOR_NULL;

  already_added=igraph_Calloc(no_of_nodes,char);
  if (already_added==0) {
    IGRAPH_ERROR("Cannot calculate clusters", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, already_added);

  IGRAPH_DQUEUE_INIT_FINALLY(&q, no_of_nodes > 100000 ? 10000 : no_of_nodes/10);
  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);

  /* Memory for result, csize is dynamically allocated */
  if (membership) { 
    IGRAPH_CHECK(igraph_vector_resize(membership, no_of_nodes));
  }
  if (csize) { 
    igraph_vector_clear(csize);
  }

  /* The algorithm */

  for (first_node=0; first_node < no_of_nodes; ++first_node) {
    if (already_added[first_node]==1) continue;
    IGRAPH_ALLOW_INTERRUPTION();

    already_added[first_node]=1;
    act_cluster_size=1;
    if (membership) {
      VECTOR(*membership)[first_node]=no_of_clusters-1;
    }
    IGRAPH_CHECK(igraph_dqueue_push(&q, first_node));
    
    while ( !igraph_dqueue_empty(&q) ) {
      long int act_node=(long int) igraph_dqueue_pop(&q);
      IGRAPH_CHECK(igraph_neighbors(graph, &neis, 
				    (igraph_integer_t) act_node, IGRAPH_ALL));
      for (i=0; i<igraph_vector_size(&neis); i++) {
	long int neighbor=(long int) VECTOR(neis)[i];
	if (already_added[neighbor]==1) { continue; }
	IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
	already_added[neighbor]=1;
	act_cluster_size++;
	if (membership) {
	  VECTOR(*membership)[neighbor]=no_of_clusters-1;
	}
      }
    }
    no_of_clusters++;
    if (csize) {
      IGRAPH_CHECK(igraph_vector_push_back(csize, act_cluster_size));
    }
  }
  
  /* Cleaning up */
  
  if (no) { *no = (igraph_integer_t) no_of_clusters-1; }
  
  igraph_Free(already_added);
  igraph_dqueue_destroy(&q);
  igraph_vector_destroy(&neis);
  IGRAPH_FINALLY_CLEAN(3);
  
  return 0;
}
Example #22
0
int igraph_i_minimum_spanning_tree_unweighted(const igraph_t* graph,
    igraph_vector_t* res) {

  long int no_of_nodes=igraph_vcount(graph);
  long int no_of_edges=igraph_ecount(graph);
  char *already_added;
  char *added_edges;
  
  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
  igraph_vector_t tmp=IGRAPH_VECTOR_NULL;
  long int i, j;

  igraph_vector_clear(res);

  added_edges=igraph_Calloc(no_of_edges, char);
  if (added_edges==0) {
    IGRAPH_ERROR("unweighted spanning tree failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, added_edges);
  already_added=igraph_Calloc(no_of_nodes, char);
  if (already_added==0) {
    IGRAPH_ERROR("unweighted spanning tree failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, already_added);
  IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0);
  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
  
  for (i=0; i<no_of_nodes; i++) {
    if (already_added[i]>0) { continue; }

    IGRAPH_ALLOW_INTERRUPTION();

    already_added[i]=1;
    IGRAPH_CHECK(igraph_dqueue_push(&q, i));
    while (! igraph_dqueue_empty(&q)) {
      long int act_node=(long int) igraph_dqueue_pop(&q);
      IGRAPH_CHECK(igraph_incident(graph, &tmp, (igraph_integer_t) act_node,
				   IGRAPH_ALL));
      igraph_vector_sort(&tmp);
      for (j=0; j<igraph_vector_size(&tmp); j++) {
        long int edge=(long int) VECTOR(tmp)[j];
        if (added_edges[edge]==0) {
          igraph_integer_t from, to;
          igraph_edge(graph, (igraph_integer_t) edge, &from, &to);
          if (act_node==to) { to=from; }
          if (already_added[(long int) to]==0) {
            already_added[(long int) to]=1;
            added_edges[edge]=1;
            IGRAPH_CHECK(igraph_vector_push_back(res, edge));
            IGRAPH_CHECK(igraph_dqueue_push(&q, to));
          }
        }
      }
    }
  }
  
  igraph_dqueue_destroy(&q);
  igraph_Free(already_added);
  igraph_vector_destroy(&tmp);
  igraph_Free(added_edges);
  IGRAPH_FINALLY_CLEAN(4);

  return IGRAPH_SUCCESS;
}
Example #23
0
void igraph_lazy_inclist_destroy(igraph_lazy_inclist_t *il) {
  igraph_lazy_inclist_clear(il);
  igraph_Free(il->incs);
}
Example #24
0
void igraph_i_layout_mergegrid_destroy(igraph_i_layout_mergegrid_t *grid) {
    igraph_Free(grid->data);
}
/**
 * \ingroup interface
 * \function igraph_delete_edges
 * \brief Removes edges from a graph.
 *
 * </para><para>
 * The edges to remove are given as an edge selector.
 *
 * </para><para>
 * This function cannot remove vertices, they will be kept, even if
 * they lose all their edges.
 *
 * </para><para>
 * This function invalidates all iterators.
 * \param graph The graph to work on.
 * \param edges The edges to remove.
 * \return Error code.
 *
 * Time complexity: O(|V|+|E|) where
 * |V| 
 * and |E| are the number of vertices
 * and edges in the \em original graph, respectively.
 */
int igraph_delete_edges(igraph_t *graph, igraph_es_t edges) {
  long int no_of_edges=igraph_ecount(graph);
  long int no_of_nodes=igraph_vcount(graph);
  long int edges_to_remove=0;
  long int remaining_edges;
  igraph_eit_t eit;
  
  igraph_vector_t newfrom, newto, newoi;

  int *mark;
  long int i, j;
  
  mark=igraph_Calloc(no_of_edges, int);
  if (mark==0) {
    IGRAPH_ERROR("Cannot delete edges", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, mark);

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

  for (IGRAPH_EIT_RESET(eit); !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) {
    long int e=IGRAPH_EIT_GET(eit);
    if (mark[e]==0) {
      edges_to_remove++;
      mark[e]++;
    }
  }
  remaining_edges=no_of_edges-edges_to_remove;

  /* We don't need the iterator any more */
  igraph_eit_destroy(&eit);
  IGRAPH_FINALLY_CLEAN(1);

  IGRAPH_VECTOR_INIT_FINALLY(&newfrom, remaining_edges);
  IGRAPH_VECTOR_INIT_FINALLY(&newto, remaining_edges);
  
  /* Actually remove the edges, move from pos i to pos j in newfrom/newto */
  for (i=0,j=0; j<remaining_edges; i++) {
    if (mark[i]==0) {
      VECTOR(newfrom)[j] = VECTOR(graph->from)[i];
      VECTOR(newto)[j] = VECTOR(graph->to)[i];
      j++;
    }
  }

  /* Create index, this might require additional memory */
  IGRAPH_VECTOR_INIT_FINALLY(&newoi, remaining_edges);
  IGRAPH_CHECK(igraph_vector_order(&newfrom, &newto, &newoi, no_of_nodes));
  IGRAPH_CHECK(igraph_vector_order(&newto, &newfrom, &graph->ii, no_of_nodes));
  
  /* Attributes, we use the original from vector to create an index,
     needed for the attribute handler. This index is the same as the
     one used for copying the edges of course The attribute handler is
     safe, never returns error. */
  if (graph->attr) {
    long int i, j=1;
    for (i=0; i<igraph_vector_size(&graph->from); i++) {
      if (mark[i] == 0) {
	VECTOR(graph->from)[i]=j++;
      } else {
	VECTOR(graph->from)[i]=0;
      }
    }
    igraph_i_attribute_delete_edges(graph, &graph->from);
  }

  /* Ok, we've all memory needed, free the old structure  */
  igraph_vector_destroy(&graph->from);
  igraph_vector_destroy(&graph->to);
  igraph_vector_destroy(&graph->oi);
  graph->from=newfrom;
  graph->to=newto;
  graph->oi=newoi;
  IGRAPH_FINALLY_CLEAN(3);

  igraph_Free(mark);
  IGRAPH_FINALLY_CLEAN(1);
  
  /* Create start vectors, no memory is needed for this */
  igraph_i_create_start(&graph->os, &graph->from, &graph->oi, no_of_nodes);
  igraph_i_create_start(&graph->is, &graph->to,   &graph->ii, no_of_nodes);
  
  /* Nothing to deallocate... */
  return 0;
}
int igraph_get_eids(const igraph_t *graph, igraph_vector_t *eids,
		    const igraph_vector_t *pairs, igraph_bool_t directed) {

  long int n=igraph_vector_size(pairs);
  long int no_of_nodes=igraph_vcount(graph);
  long int no_of_edges=igraph_ecount(graph);
  igraph_bool_t *seen;
  long int i;
  igraph_integer_t eid=-1;
    
  if (n % 2 != 0) {
    IGRAPH_ERROR("Cannot get edge ids, invalid length of edge ids",
		 IGRAPH_EINVAL);
  }
  if (!igraph_vector_isininterval(pairs, 0, no_of_nodes-1)) {
    IGRAPH_ERROR("Cannot get edge ids, invalid vertex id", IGRAPH_EINVVID);
  }

  seen=igraph_Calloc(no_of_edges, igraph_bool_t);
  if (seen==0) {
    IGRAPH_ERROR("Cannot get edge ids", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, seen);
  IGRAPH_CHECK(igraph_vector_resize(eids, n/2));
  
  if (igraph_is_directed(graph)) {
    for (i=0; i<n/2; i++) {
      long int from=VECTOR(*pairs)[2*i];
      long int to=VECTOR(*pairs)[2*i+1];

      eid=-1;
      FIND_DIRECTED_EDGE(graph,from,to,&eid,seen);
      if (!directed && eid < 0) {
	FIND_DIRECTED_EDGE(graph,to,from,&eid,seen);
      }
      
      if (eid >= 0) {
	VECTOR(*eids)[i]=eid;
	seen[(long int)(eid)]=1;
      } else {
	IGRAPH_ERROR("Cannot get edge id, no such edge", IGRAPH_EINVAL);
      }
    }
  } else {
    for (i=0; i<n/2; i++) {
      long int from=VECTOR(*pairs)[2*i];
      long int to=VECTOR(*pairs)[2*i+1];

      eid=-1;
      FIND_UNDIRECTED_EDGE(graph,from,to,&eid,seen);
      if (eid >= 0) {
	VECTOR(*eids)[i]=eid;
	seen[(long int)(eid)]=1;
      } else {
	IGRAPH_ERROR("Cannot get edge id, no such edge", IGRAPH_EINVAL);
      }
    }
  }
  
  igraph_Free(seen);
  IGRAPH_FINALLY_CLEAN(1);
  return 0;
}
Example #27
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;
}
void igraph_i_graphml_destroy_state(struct igraph_i_graphml_parser_state* state) {
  long int i;

  if (state->destroyed) return;
  state->destroyed=1;

  /* this is the easy part */
  igraph_trie_destroy(&state->node_trie);
  igraph_strvector_destroy(&state->edgeids);
  igraph_trie_destroy(&state->v_names);
  igraph_trie_destroy(&state->e_names);
  igraph_trie_destroy(&state->g_names);
  igraph_vector_destroy(&state->edgelist);
   
  if (state->error_message) { free(state->error_message); }
  if (state->data_key) { free(state->data_key); }
  if (state->data_char) { free(state->data_char); }
  
  for (i=0; i<igraph_vector_ptr_size(&state->v_attrs); i++) {
    igraph_i_graphml_attribute_record_t *rec=VECTOR(state->v_attrs)[i];
    if (rec->record.type==IGRAPH_ATTRIBUTE_NUMERIC) {
      if (rec->record.value != 0) {
	igraph_vector_destroy((igraph_vector_t*)rec->record.value);
	igraph_Free(rec->record.value);
      }
    } else if (rec->record.type==IGRAPH_ATTRIBUTE_STRING) {
      if (rec->record.value != 0) {
	igraph_strvector_destroy((igraph_strvector_t*)rec->record.value);
	igraph_Free(rec->record.value);
      }
    }
    if (rec->id != 0) igraph_Free(rec->id);
    if (rec->record.name != 0) igraph_Free(rec->record.name);
    igraph_Free(rec);
  }	 

  for (i=0; i<igraph_vector_ptr_size(&state->e_attrs); i++) {
    igraph_i_graphml_attribute_record_t *rec=VECTOR(state->e_attrs)[i];
    if (rec->record.type==IGRAPH_ATTRIBUTE_NUMERIC) {
      if (rec->record.value != 0) {
	igraph_vector_destroy((igraph_vector_t*)rec->record.value);
	igraph_Free(rec->record.value);
      }
    } else if (rec->record.type==IGRAPH_ATTRIBUTE_STRING) {
      if (rec->record.value != 0) {
	igraph_strvector_destroy((igraph_strvector_t*)rec->record.value);
	igraph_Free(rec->record.value);
      }
    }
    if (rec->id != 0) igraph_Free(rec->id);
    if (rec->record.name != 0) igraph_Free(rec->record.name);
    igraph_Free(rec);
  }

  for (i=0; i<igraph_vector_ptr_size(&state->g_attrs); i++) {
    igraph_i_graphml_attribute_record_t *rec=VECTOR(state->g_attrs)[i];
    if (rec->record.type==IGRAPH_ATTRIBUTE_NUMERIC) {
      if (rec->record.value != 0) {
	igraph_vector_destroy((igraph_vector_t*)rec->record.value);
	igraph_Free(rec->record.value);
      }
    } else if (rec->record.type==IGRAPH_ATTRIBUTE_STRING) {
      if (rec->record.value != 0) {
	igraph_strvector_destroy((igraph_strvector_t*)rec->record.value);
	igraph_Free(rec->record.value);
      }
    }
    if (rec->id != 0) igraph_Free(rec->id);
    if (rec->record.name != 0) igraph_Free(rec->record.name);
    igraph_Free(rec);
  }

  igraph_vector_ptr_destroy(&state->v_attrs);
  igraph_vector_ptr_destroy(&state->e_attrs);
  igraph_vector_ptr_destroy(&state->g_attrs);
  
  IGRAPH_FINALLY_CLEAN(1);
}
Example #29
0
int igraph_free(void *p) {
  igraph_Free(p);
  return 0;
}
Example #30
0
/**
 * \ingroup structural
 * \function igraph_edge_betweenness_estimate
 * \brief Estimated betweenness centrality of the edges.
 * 
 * </para><para>
 * The betweenness centrality of an edge is the number of geodesics
 * going through it. If there are more than one geodesics between two
 * vertices, the value of these geodesics are weighted by one over the 
 * number of geodesics. When estimating betweenness centrality, igraph
 * takes into consideration only those paths that are shorter than or
 * equal to a prescribed length. Note that the estimated centrality
 * will always be less than the real one.
 * \param graph The graph object.
 * \param result The result of the computation, vector containing the
 *        betweenness scores for the edges.
 * \param directed Logical, if true directed paths will be considered
 *        for directed graphs. It is ignored for undirected graphs.
 * \param cutoff The maximal length of paths that will be considered.
 *        If zero or negative, the exact betweenness will be calculated
 *        (no upper limit on path lengths).
 * \return Error code:
 *        \c IGRAPH_ENOMEM, not enough memory for
 *        temporary data. 
 *
 * Time complexity: O(|V||E|),
 * |V| and
 * |E| are the number of vertices and
 * edges in the graph. 
 *
 * \sa Other centrality types: \ref igraph_degree(), \ref igraph_closeness().
 *     See \ref igraph_betweenness() for calculating the betweenness score
 *     of the vertices in a graph.
 */
int igraph_edge_betweenness_estimate(const igraph_t *graph, igraph_vector_t *result,
                                     igraph_bool_t directed, igraph_integer_t cutoff) {
  long int no_of_nodes=igraph_vcount(graph);
  long int no_of_edges=igraph_ecount(graph);
  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
  long int *distance;
  long int *nrgeo;
  double *tmpscore;
  igraph_stack_t stack=IGRAPH_STACK_NULL;
  long int source;
  long int j;

  igraph_adjedgelist_t elist_out, elist_in;
  igraph_adjedgelist_t *elist_out_p, *elist_in_p;
  igraph_vector_t *neip;
  long int neino;
  long int i;
  igraph_integer_t modein, modeout;

  directed=directed && igraph_is_directed(graph);
  if (directed) {
    modeout=IGRAPH_OUT;
    modein=IGRAPH_IN;
    IGRAPH_CHECK(igraph_adjedgelist_init(graph, &elist_out, IGRAPH_OUT));
    IGRAPH_FINALLY(igraph_adjedgelist_destroy, &elist_out);
    IGRAPH_CHECK(igraph_adjedgelist_init(graph, &elist_in, IGRAPH_IN));
    IGRAPH_FINALLY(igraph_adjedgelist_destroy, &elist_in);
    elist_out_p=&elist_out;
    elist_in_p=&elist_in;
  } else {
    modeout=modein=IGRAPH_ALL;
    IGRAPH_CHECK(igraph_adjedgelist_init(graph,&elist_out, IGRAPH_ALL));
    IGRAPH_FINALLY(igraph_adjedgelist_destroy, &elist_out);
    elist_out_p=elist_in_p=&elist_out;
  }
  
  distance=igraph_Calloc(no_of_nodes, long int);
  if (distance==0) {
    IGRAPH_ERROR("edge betweenness failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, distance);
  nrgeo=igraph_Calloc(no_of_nodes, long int);
  if (nrgeo==0) {
    IGRAPH_ERROR("edge betweenness failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, nrgeo);
  tmpscore=igraph_Calloc(no_of_nodes, double);
  if (tmpscore==0) {
    IGRAPH_ERROR("edge betweenness failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, tmpscore);

  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
  IGRAPH_CHECK(igraph_stack_init(&stack, no_of_nodes));
  IGRAPH_FINALLY(igraph_stack_destroy, &stack);

  IGRAPH_CHECK(igraph_vector_resize(result, no_of_edges));

  igraph_vector_null(result);

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

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

      if (cutoff > 0 && distance[actnode] >= cutoff ) continue;

      neip=igraph_adjedgelist_get(elist_out_p, actnode);
      neino=igraph_vector_size(neip);
      for (i=0; i<neino; i++) {
	igraph_integer_t edge=VECTOR(*neip)[i], from, to;
	long int neighbor;
	igraph_edge(graph, edge, &from, &to);
	neighbor = actnode!=from ? from : to;
	if (nrgeo[neighbor] != 0) {
	  /* we've already seen this node, another shortest path? */
	  if (distance[neighbor]==distance[actnode]+1) {
	    nrgeo[neighbor]+=nrgeo[actnode];
	  }
	} else {
	  /* we haven't seen this node yet */
	  nrgeo[neighbor]+=nrgeo[actnode];
	  distance[neighbor]=distance[actnode]+1;
	  IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
	  IGRAPH_CHECK(igraph_stack_push(&stack, neighbor));
	}
      }
    } /* while !igraph_dqueue_empty */
    
    /* Ok, we've the distance of each node and also the number of
       shortest paths to them. Now we do an inverse search, starting
       with the farthest nodes. */
    while (!igraph_stack_empty(&stack)) {
      long int actnode=igraph_stack_pop(&stack);
      if (distance[actnode]<1) { continue; } /* skip source node */
      
      /* set the temporary score of the friends */
      neip=igraph_adjedgelist_get(elist_in_p, actnode);
      neino=igraph_vector_size(neip);
      for (i=0; i<neino; i++) {
	igraph_integer_t from, to;
	long int neighbor;
	long int edgeno=VECTOR(*neip)[i];
	igraph_edge(graph, edgeno, &from, &to);
	neighbor= actnode != from ? from : to;
	if (distance[neighbor]==distance[actnode]-1 &&
	    nrgeo[neighbor] != 0) {
	  tmpscore[neighbor] +=
	    (tmpscore[actnode]+1)*nrgeo[neighbor]/nrgeo[actnode];
	  VECTOR(*result)[edgeno] +=
	    (tmpscore[actnode]+1)*nrgeo[neighbor]/nrgeo[actnode];
	}
      }
    }
    /* Ok, we've the scores for this source */
  } /* for source <= no_of_nodes */
  IGRAPH_PROGRESS("Edge betweenness centrality: ", 100.0, 0);

  /* clean and return */
  igraph_Free(distance);
  igraph_Free(nrgeo);
  igraph_Free(tmpscore);
  igraph_dqueue_destroy(&q);
  igraph_stack_destroy(&stack);
  IGRAPH_FINALLY_CLEAN(5);

  if (directed) {
    igraph_adjedgelist_destroy(&elist_out);
    igraph_adjedgelist_destroy(&elist_in);
    IGRAPH_FINALLY_CLEAN(2);
  } else {
    igraph_adjedgelist_destroy(&elist_out);
    IGRAPH_FINALLY_CLEAN(1);
  }

  /* divide by 2 for undirected graph */
  if (!directed || !igraph_is_directed(graph)) {
    for (j=0; j<igraph_vector_size(result); j++) {
      VECTOR(*result)[j] /= 2.0;
    }
  }
  
  return 0;
}