Example #1
0
int igraph_i_largest_cliques_store(const igraph_vector_t* clique, void* data, igraph_bool_t* cont) {
  igraph_vector_ptr_t* result = (igraph_vector_ptr_t*)data;
  igraph_vector_t* vec;
  long int i, n;

  /* Is the current clique at least as large as the others that we have found? */
  if (!igraph_vector_ptr_empty(result)) {
    n = igraph_vector_size(clique);
    if (n < igraph_vector_size(VECTOR(*result)[0]))
      return IGRAPH_SUCCESS;

    if (n > igraph_vector_size(VECTOR(*result)[0])) {
      for (i = 0; i < igraph_vector_ptr_size(result); i++)
        igraph_vector_destroy(VECTOR(*result)[i]);
      igraph_vector_ptr_free_all(result);
      igraph_vector_ptr_resize(result, 0);
    }
  }

  vec = igraph_Calloc(1, igraph_vector_t);
  if (vec == 0)
    IGRAPH_ERROR("cannot allocate memory for storing next clique", IGRAPH_ENOMEM);

  IGRAPH_CHECK(igraph_vector_copy(vec, clique));
  IGRAPH_CHECK(igraph_vector_ptr_push_back(result, vec));

  return IGRAPH_SUCCESS;
}
Example #2
0
/**
 * \ingroup python_interface_edgeseq
 * \brief Copies an edge sequence object
 * \return the copied PyObject
 */
igraphmodule_EdgeSeqObject*
igraphmodule_EdgeSeq_copy(igraphmodule_EdgeSeqObject* o) {
  igraphmodule_EdgeSeqObject *copy;

  copy=(igraphmodule_EdgeSeqObject*)PyType_GenericNew(Py_TYPE(o), 0, 0);
  if (copy == NULL) return NULL;
 
  if (igraph_es_type(&o->es) == IGRAPH_ES_VECTOR) {
    igraph_vector_t v;
    if (igraph_vector_copy(&v, o->es.data.vecptr)) {
      igraphmodule_handle_igraph_error();
      return 0;
    }
    if (igraph_es_vector_copy(&copy->es, &v)) {
      igraphmodule_handle_igraph_error();
      igraph_vector_destroy(&v);
      return 0;
    }
    igraph_vector_destroy(&v);
  } else {
    copy->es = o->es;
  }

  copy->gref = o->gref;
  if (o->gref) Py_INCREF(o->gref);
  RC_ALLOC("EdgeSeq(copy)", copy);

  return copy;
}
Example #3
0
int igraph_i_separators_store(igraph_vector_ptr_t *separators, 
			      const igraph_adjlist_t *adjlist,
			      igraph_vector_t *components, 
			      igraph_vector_t *leaveout, 
			      unsigned long int *mark, 
			      igraph_vector_t *sorter) {
  
  /* We need to stote N(C), the neighborhood of C, but only if it is 
   * not already stored among the separators.
   */
  
  long int cptr=0, next, complen=igraph_vector_size(components);

  while (cptr < complen) {
    long int saved=cptr;
    igraph_vector_clear(sorter);

    /* Calculate N(C) for the next C */

    while ( (next=(long int) VECTOR(*components)[cptr++]) != -1) {
      VECTOR(*leaveout)[next] = *mark;
    }
    cptr=saved;

    while ( (next=(long int) VECTOR(*components)[cptr++]) != -1) {
      igraph_vector_int_t *neis=igraph_adjlist_get(adjlist, next);
      long int j, nn=igraph_vector_int_size(neis);
      for (j=0; j<nn; j++) {
	long int nei=(long int) VECTOR(*neis)[j];
	if (VECTOR(*leaveout)[nei] != *mark) {
	  igraph_vector_push_back(sorter, nei);
	  VECTOR(*leaveout)[nei] = *mark;
	}
      }    
    }
    igraph_vector_sort(sorter);

    UPDATEMARK();

    /* Add it to the list of separators, if it is new */

    if (igraph_i_separators_newsep(separators, sorter)) {
      igraph_vector_t *newc=igraph_Calloc(1, igraph_vector_t);
      if (!newc) {
	IGRAPH_ERROR("Cannot calculate minimal separators", IGRAPH_ENOMEM);
      }
      IGRAPH_FINALLY(igraph_free, newc);
      igraph_vector_copy(newc, sorter);
      IGRAPH_FINALLY(igraph_vector_destroy, newc);
      IGRAPH_CHECK(igraph_vector_ptr_push_back(separators, newc));
      IGRAPH_FINALLY_CLEAN(2);      
    }
  } /* while cptr < complen */

  return 0;
}
Example #4
0
int igraph_i_maximal_cliques_store(const igraph_vector_t* clique, void* data, igraph_bool_t* cont) {
  igraph_vector_ptr_t* result = (igraph_vector_ptr_t*)data;
  igraph_vector_t* vec;

  vec = igraph_Calloc(1, igraph_vector_t);
  if (vec == 0)
    IGRAPH_ERROR("cannot allocate memory for storing next clique", IGRAPH_ENOMEM);

  IGRAPH_CHECK(igraph_vector_copy(vec, clique));
  IGRAPH_CHECK(igraph_vector_ptr_push_back(result, vec));

  return IGRAPH_SUCCESS;
}
Example #5
0
int igraph_i_maximal_cliques_store_size_check(const igraph_vector_t* clique, void* data_, igraph_bool_t* cont) {
  igraph_i_maximal_clique_data_t* data = (igraph_i_maximal_clique_data_t*)data_;
  igraph_vector_t* vec;
  igraph_integer_t size = igraph_vector_size(clique);

  if (size < data->min_size || size > data->max_size)
    return IGRAPH_SUCCESS;

  vec = igraph_Calloc(1, igraph_vector_t);
  if (vec == 0)
    IGRAPH_ERROR("cannot allocate memory for storing next clique", IGRAPH_ENOMEM);

  IGRAPH_CHECK(igraph_vector_copy(vec, clique));
  IGRAPH_CHECK(igraph_vector_ptr_push_back(data->result, vec));

  return IGRAPH_SUCCESS;
}
Example #6
0
int check(const igraph_vector_t *v1, const igraph_vector_t *v2, int code) {
  igraph_vector_t v;
  long int i, n=igraph_vector_size(v1);
  igraph_real_t m;

  igraph_vector_copy(&v, v1);
  igraph_vector_sub(&v, v2);
  
  for (i=0; i<n; i++) {
    VECTOR(v)[i] = fabs(VECTOR(v)[i]);
  }
  
  if ( (m=igraph_vector_max(&v)) > 0.01) { 
    printf("Difference: %g\n", m);
    exit(code); 
  }

  igraph_vector_destroy(&v);

  return 0;
}
Example #7
0
igraph_bool_t check_solution(const igraph_sparsemat_t *A,
			     const igraph_vector_t *x,
			     const igraph_vector_t *b) {

  long int dim=igraph_vector_size(x);
  igraph_vector_t res;
  int j, p;
  igraph_real_t min, max;

  igraph_vector_copy(&res, b);
  
  for (j=0; j<dim; j++) {
    for (p=A->cs->p[j]; p < A->cs->p[j+1]; p++) {
      long int from=A->cs->i[p];
      igraph_real_t value=A->cs->x[p];
      VECTOR(res)[from] -= VECTOR(*x)[j] * value;
    }
  }
  
  igraph_vector_minmax(&res, &min, &max);
  igraph_vector_destroy(&res);

  return abs(min) < 1e-15 && abs(max) < 1e-15;
}
int igraph_copy(igraph_t *to, const igraph_t *from) {
  to->n=from->n;
  to->directed=from->directed;
  IGRAPH_CHECK(igraph_vector_copy(&to->from, &from->from));
  IGRAPH_FINALLY(igraph_vector_destroy, &to->from);
  IGRAPH_CHECK(igraph_vector_copy(&to->to, &from->to));
  IGRAPH_FINALLY(igraph_vector_destroy, &to->to);
  IGRAPH_CHECK(igraph_vector_copy(&to->oi, &from->oi));
  IGRAPH_FINALLY(igraph_vector_destroy, &to->oi);
  IGRAPH_CHECK(igraph_vector_copy(&to->ii, &from->ii));
  IGRAPH_FINALLY(igraph_vector_destroy, &to->ii);
  IGRAPH_CHECK(igraph_vector_copy(&to->os, &from->os));
  IGRAPH_FINALLY(igraph_vector_destroy, &to->os);
  IGRAPH_CHECK(igraph_vector_copy(&to->is, &from->is));
  IGRAPH_FINALLY(igraph_vector_destroy, &to->is);

  IGRAPH_I_ATTRIBUTE_COPY(to, from, 1,1,1); /* does IGRAPH_CHECK */

  IGRAPH_FINALLY_CLEAN(6);
  return 0;
}
Example #9
0
igraph_vector_t * ggen_analyze_longest_antichain(igraph_t *g)
{
	/* The following steps are implemented :
	 *  - Convert our DAG to a specific bipartite graph B
	 *  - solve maximum matching on B
	 *  - conver maximum matching to min vectex cover
	 *  - convert min vertex cover to antichain on G
	 */
	int err;
	unsigned long i,vg,found,added;
	igraph_t b,gstar;
	igraph_vector_t edges,*res = NULL;
	igraph_vector_t c,s,t,todo,n,next,l,r;
	igraph_eit_t eit;
	igraph_es_t es;
	igraph_integer_t from,to;
	igraph_vit_t vit;
	igraph_vs_t vs;
	igraph_real_t value;

	if(g == NULL)
		return NULL;

	/* before creating the bipartite graph, we need all relations
	 * between any two vertices : the transitive closure of g */
	err = igraph_copy(&gstar,g);
	if(err) return NULL;

	err = ggen_transform_transitive_closure(&gstar);
	if(err) goto error;

	/* Bipartite convertion : let G = (S,C),
	 * we build B = (U,V,E) with
	 *	- U = V = S (each vertex is present twice)
	 *	- (u,v) \in E iff :
	 *		- u \in U
	 *		- v \in V
	 *		- u < v in C (warning, this means that we take
	 *		transitive closure into account, not just the
	 *		original edges)
	 * We will also need two additional nodes further in the code.
	 */
	vg = igraph_vcount(g);
	err = igraph_empty(&b,vg*2,1);
	if(err) goto error;

	/* id and id+vg will be a vertex in U and its copy in V,
	 * iterate over gstar edges to create edges in b
	 */
	err = igraph_vector_init(&edges,igraph_ecount(&gstar));
	if(err) goto d_b;
	igraph_vector_clear(&edges);

	err = igraph_eit_create(&gstar,igraph_ess_all(IGRAPH_EDGEORDER_ID),&eit);
	if(err) goto d_edges;

	for(IGRAPH_EIT_RESET(eit); !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit))
	{
		err = igraph_edge(&gstar,IGRAPH_EIT_GET(eit),&from,&to);
		if(err)
		{
			igraph_eit_destroy(&eit);
			goto d_edges;
		}
		to += vg;
		igraph_vector_push_back(&edges,(igraph_real_t)from);
		igraph_vector_push_back(&edges,(igraph_real_t)to);
	}
	igraph_eit_destroy(&eit);
	err = igraph_add_edges(&b,&edges,NULL);
	if(err) goto d_edges;

	/* maximum matching on b */
	igraph_vector_clear(&edges);
	err = bipartite_maximum_matching(&b,&edges);
	if(err) goto d_edges;

	/* Let M be the max matching, and N be E - M
	 * Define T as all unmatched vectices from U as well as all vertices
	 * reachable from those by going left-to-right along N and right-to-left along
	 * M.
	 * Define L = U - T, R = V \inter T
	 * C:= L + R
	 * C is a minimum vertex cover
	 */
	err = igraph_vector_init_seq(&n,0,igraph_ecount(&b)-1);
	if(err) goto d_edges;

	err = vector_diff(&n,&edges);
	if(err) goto d_n;

	err = igraph_vector_init(&c,vg);
	if(err) goto d_n;
	igraph_vector_clear(&c);

	/* matched vertices : S */
	err = igraph_vector_init(&s,vg);
	if(err) goto d_c;
	igraph_vector_clear(&s);

	for(i = 0; i < igraph_vector_size(&edges); i++)
	{
		err = igraph_edge(&b,VECTOR(edges)[i],&from,&to);
		if(err) goto d_s;

		igraph_vector_push_back(&s,from);
	}
	/* we may have inserted the same vertex multiple times */
	err = vector_uniq(&s);
	if(err) goto d_s;

	/* unmatched */
	err = igraph_vector_init_seq(&t,0,vg-1);
	if(err) goto d_s;

	err = vector_diff(&t,&s);
	if(err) goto d_t;

	/* alternating paths
	 */
	err = igraph_vector_copy(&todo,&t);
	if(err) goto d_t;

	err = igraph_vector_init(&next,vg);
	if(err) goto d_todo;
	igraph_vector_clear(&next);
	do {
		vector_uniq(&todo);
		added = 0;
		for(i = 0; i < igraph_vector_size(&todo); i++)
		{
			if(VECTOR(todo)[i] < vg)
			{
				/* scan edges */
				err = igraph_es_adj(&es,VECTOR(todo)[i],IGRAPH_OUT);
				if(err) goto d_next;
				err = igraph_eit_create(&b,es,&eit);
				if(err)
				{
					igraph_es_destroy(&es);
					goto d_next;
				}
				for(IGRAPH_EIT_RESET(eit); !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit))
				{
					if(igraph_vector_binsearch(&n,IGRAPH_EIT_GET(eit),NULL))
					{
						err = igraph_edge(&b,IGRAPH_EIT_GET(eit),&from,&to);
						if(err)
						{
							igraph_eit_destroy(&eit);
							igraph_es_destroy(&es);
							goto d_next;
						}
						if(!igraph_vector_binsearch(&t,to,NULL))
						{
							igraph_vector_push_back(&next,to);
							added = 1;
						}
					}
				}
			}
			else
			{
				/* scan edges */
				err = igraph_es_adj(&es,VECTOR(todo)[i],IGRAPH_IN);
				if(err) goto d_next;
				err = igraph_eit_create(&b,es,&eit);
				if(err)
				{
					igraph_es_destroy(&es);
					goto d_next;
				}
				for(IGRAPH_EIT_RESET(eit); !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit))
				{
					if(igraph_vector_binsearch(&edges,IGRAPH_EIT_GET(eit),NULL))
					{
						err = igraph_edge(&b,IGRAPH_EIT_GET(eit),&from,&to);
						if(err)
						{
							igraph_eit_destroy(&eit);
							igraph_es_destroy(&es);
							goto d_next;
						}
						if(!igraph_vector_binsearch(&t,to,NULL))
						{
							igraph_vector_push_back(&next,from);
							added = 1;
						}
					}
				}
			}
			igraph_es_destroy(&es);
			igraph_eit_destroy(&eit);
		}
		igraph_vector_append(&t,&todo);
		igraph_vector_clear(&todo);
		igraph_vector_append(&todo,&next);
		igraph_vector_clear(&next);
	} while(added);

	err = igraph_vector_init_seq(&l,0,vg-1);
	if(err) goto d_t;

	err = vector_diff(&l,&t);
	if(err) goto d_l;

	err = igraph_vector_update(&c,&l);
	if(err) goto d_l;

	err = igraph_vector_init(&r,vg);
	if(err) goto d_l;
	igraph_vector_clear(&r);

	/* compute V \inter T */
	for(i = 0; i < igraph_vector_size(&t); i++)
	{
		if(VECTOR(t)[i] >= vg)
			igraph_vector_push_back(&r,VECTOR(t)[i]);
	}

	igraph_vector_add_constant(&r,(igraph_real_t)-vg);
	err = vector_union(&c,&r);
	if(err) goto d_r;

	/* our antichain is U - C */
	res = malloc(sizeof(igraph_vector_t));
	if(res == NULL) goto d_r;

	err = igraph_vector_init_seq(res,0,vg-1);
	if(err) goto f_res;

	err = vector_diff(res,&c);
	if(err) goto d_res;

	goto ret;
d_res:
	igraph_vector_destroy(res);
f_res:
	free(res);
	res = NULL;
ret:
d_r:
	igraph_vector_destroy(&r);
d_l:
	igraph_vector_destroy(&l);
d_next:
	igraph_vector_destroy(&next);
d_todo:
	igraph_vector_destroy(&todo);
d_t:
	igraph_vector_destroy(&t);
d_s:
	igraph_vector_destroy(&s);
d_c:
	igraph_vector_destroy(&c);
d_n:
	igraph_vector_destroy(&n);
d_edges:
	igraph_vector_destroy(&edges);
d_b:
	igraph_destroy(&b);
error:
	igraph_destroy(&gstar);
	return res;
}
Example #10
0
int test_unnormalized_laplacian(igraph_vector_t* w, igraph_bool_t dir) {
  igraph_t g;
  igraph_matrix_t m, m2;
  igraph_sparsemat_t sm;
  igraph_vector_t vec, *weights = 0;
  igraph_matrix_init(&m, 1, 1);
  igraph_sparsemat_init(&sm, 0, 0, 0);

  if (w) {
    weights = (igraph_vector_t*)calloc(1, sizeof(igraph_vector_t));
    igraph_vector_copy(weights, w);
  }

  /* No loop or multiple edges */
  igraph_ring(&g, 5, dir, 0, 1);
  igraph_laplacian(&g, &m, &sm, 0, weights);
  igraph_matrix_init(&m2, 0, 0);
  igraph_sparsemat_as_matrix(&m2, &sm);
  if (!igraph_matrix_all_e_tol(&m, &m2, 0)) { 
    return 41;
  }
  igraph_matrix_destroy(&m2);
  igraph_matrix_print(&m);
  printf("===\n");

  /* Add some loop edges */
  igraph_vector_init_real(&vec, 4, 1.0, 1.0, 2.0, 2.0);
  igraph_add_edges(&g, &vec, 0);
  igraph_vector_destroy(&vec);
  if (weights) {
    igraph_vector_push_back(weights, 2);
    igraph_vector_push_back(weights, 2);
  }

  igraph_laplacian(&g, &m, &sm, 0, weights);
  igraph_matrix_init(&m2, 0, 0);
  igraph_sparsemat_as_matrix(&m2, &sm);
  if (!igraph_matrix_all_e_tol(&m, &m2, 0)) { 
    return 42;
  }
  igraph_matrix_destroy(&m2);
  igraph_matrix_print(&m);
  printf("===\n");

  /* Duplicate some edges */
  igraph_vector_init_real(&vec, 4, 1.0, 2.0, 3.0, 4.0);
  igraph_add_edges(&g, &vec, 0);
  igraph_vector_destroy(&vec);
  if (weights) {
    igraph_vector_push_back(weights, 3);
    igraph_vector_push_back(weights, 3);
  }

  igraph_laplacian(&g, &m, &sm, 0, weights);
  igraph_matrix_init(&m2, 0, 0);
  igraph_sparsemat_as_matrix(&m2, &sm);
  if (!igraph_matrix_all_e_tol(&m, &m2, 0)) { 
    return 43;
  }
  igraph_matrix_destroy(&m2);
  igraph_matrix_print(&m);

  igraph_destroy(&g);

  igraph_matrix_destroy(&m);
  if (weights) {
    igraph_vector_destroy(weights); free(weights);
  }

  return 0;
}
Example #11
0
int test_normalized_laplacian(igraph_vector_t *w, igraph_bool_t dir) {
  igraph_t g;
  igraph_matrix_t m, m2;
  igraph_sparsemat_t sm;
  igraph_vector_t vec, *weights = 0;
  igraph_bool_t ok = 1;
  igraph_matrix_init(&m, 1, 1);
  igraph_sparsemat_init(&sm, 0, 0, 0);

  if (w) {
    weights = (igraph_vector_t*)calloc(1, sizeof(igraph_vector_t));
    igraph_vector_copy(weights, w);
  }

  /* Undirected graph, no loop or multiple edges */
  igraph_ring(&g, 5, dir, 0, 1);
  igraph_laplacian(&g, &m, &sm, 1, weights);
  igraph_matrix_init(&m2, 0, 0);
  igraph_sparsemat_as_matrix(&m2, &sm);
  if (!igraph_matrix_all_e_tol(&m, &m2, 0)) { 
    return 44;
  }
  igraph_matrix_destroy(&m2);
  ok = ok && check_laplacian(&g, &m, weights);

  /* Add some loop edges */
  igraph_vector_init_real(&vec, 4, 1.0, 1.0, 2.0, 2.0);
  igraph_add_edges(&g, &vec, 0);
  igraph_vector_destroy(&vec);
  if (weights) {
    igraph_vector_push_back(weights, 2);
    igraph_vector_push_back(weights, 2);
  }

  igraph_laplacian(&g, &m, &sm, 1, weights);
  igraph_matrix_init(&m2, 0, 0);
  igraph_sparsemat_as_matrix(&m2, &sm);
  if (!igraph_matrix_all_e_tol(&m, &m2, 0)) { 
    return 45;
  }
  igraph_matrix_destroy(&m2);
  ok = ok && check_laplacian(&g, &m, weights);

  /* Duplicate some edges */
  igraph_vector_init_real(&vec, 4, 1.0, 2.0, 3.0, 4.0);
  igraph_add_edges(&g, &vec, 0);
  igraph_vector_destroy(&vec);
  if (weights) {
    igraph_vector_push_back(weights, 3);
    igraph_vector_push_back(weights, 3);
  }

  igraph_laplacian(&g, &m, &sm, 1, weights);
  igraph_matrix_init(&m2, 0, 0);
  igraph_sparsemat_as_matrix(&m2, &sm);
  if (!igraph_matrix_all_e_tol(&m, &m2, 0)) { 
    return 46;
  }
  igraph_matrix_destroy(&m2);
  ok = ok && check_laplacian(&g, &m, weights);

  igraph_destroy(&g);

  igraph_matrix_destroy(&m);
  if (weights) {
    igraph_vector_destroy(weights); free(weights);
  }

  if (ok)
    printf("OK\n");

  return !ok;
}
Example #12
0
int igraph_community_multilevel(const igraph_t *graph,
  const igraph_vector_t *weights, igraph_vector_t *membership,
  igraph_matrix_t *memberships, igraph_vector_t *modularity) {
 
  igraph_t g;
  igraph_vector_t w, m, level_membership;
  igraph_real_t prev_q = -1, q = -1;
  int i, level = 1;
  long int vcount = igraph_vcount(graph);

  /* Make a copy of the original graph, we will do the merges on the copy */
  IGRAPH_CHECK(igraph_copy(&g, graph));
  IGRAPH_FINALLY(igraph_destroy, &g);

  if (weights) {
    IGRAPH_CHECK(igraph_vector_copy(&w, weights));   
    IGRAPH_FINALLY(igraph_vector_destroy, &w);  
  } else {
    IGRAPH_VECTOR_INIT_FINALLY(&w, igraph_ecount(&g));
    igraph_vector_fill(&w, 1);
  }

  IGRAPH_VECTOR_INIT_FINALLY(&m, vcount);
  IGRAPH_VECTOR_INIT_FINALLY(&level_membership, vcount);

  if (memberships || membership) {
    /* Put each vertex in its own community */
    for (i = 0; i < vcount; i++) {
      VECTOR(level_membership)[i] = i;
    }
  }
  if (memberships) {
    /* Resize the membership matrix to have vcount columns and no rows */
    IGRAPH_CHECK(igraph_matrix_resize(memberships, 0, vcount));
  }
  if (modularity) {
    /* Clear the modularity vector */
    igraph_vector_clear(modularity);
  }
  
  while (1) {
    /* Remember the previous modularity and vertex count, do a single step */
    igraph_integer_t step_vcount = igraph_vcount(&g);

    prev_q = q;
    IGRAPH_CHECK(igraph_i_community_multilevel_step(&g, &w, &m, &q));
 
    /* Were there any merges? If not, we have to stop the process */
    if (igraph_vcount(&g) == step_vcount || q < prev_q)
      break;

    if (memberships || membership) {
      for (i = 0; i < vcount; i++) {
        /* Readjust the membership vector */
        VECTOR(level_membership)[i] = VECTOR(m)[(long int) VECTOR(level_membership)[i]];
      }
        
    }

    if (modularity) {
      /* If we have to return the modularity scores, add it to the modularity vector */
      IGRAPH_CHECK(igraph_vector_push_back(modularity, q));
    }

    if (memberships) {
      /* If we have to return the membership vectors at each level, store the new
       * membership vector */
      IGRAPH_CHECK(igraph_matrix_add_rows(memberships, 1));
      IGRAPH_CHECK(igraph_matrix_set_row(memberships, &level_membership, level - 1));
    }

    /* debug("Level: %d Communities: %ld Modularity: %f\n", level, (long int) igraph_vcount(&g),
      (double) q); */

    /* Increase the level counter */
    level++;
  }

  /* It might happen that there are no merges, so every vertex is in its 
     own community. We still might want the modularity score for that. */
  if (modularity && igraph_vector_size(modularity) == 0) {
    igraph_vector_t tmp;
    igraph_real_t mod;
    int i;
    IGRAPH_VECTOR_INIT_FINALLY(&tmp, vcount);
    for (i=0; i<vcount; i++) { VECTOR(tmp)[i]=i; }
    IGRAPH_CHECK(igraph_modularity(graph, &tmp, &mod, weights));
    igraph_vector_destroy(&tmp);
    IGRAPH_FINALLY_CLEAN(1);
    IGRAPH_CHECK(igraph_vector_resize(modularity, 1));
    VECTOR(*modularity)[0]=mod;
  }

  /* If we need the final membership vector, copy it to the output */
  if (membership) {
    IGRAPH_CHECK(igraph_vector_resize(membership, vcount));   
    for (i = 0; i < vcount; i++) {
      VECTOR(*membership)[i] = VECTOR(level_membership)[i];
    }
  }

  /* Destroy the copy of the graph */
  igraph_destroy(&g);

  /* Destroy the temporary vectors */
  igraph_vector_destroy(&m);
  igraph_vector_destroy(&w);
  igraph_vector_destroy(&level_membership);
  IGRAPH_FINALLY_CLEAN(4);

  return 0;
}