Пример #1
0
int main() {
  
  igraph_t g;
  igraph_vector_t v, weights;
  long int i;
  igraph_real_t value;
  igraph_arpack_options_t options;
  
  igraph_star(&g, 100, IGRAPH_STAR_UNDIRECTED, 0);

  igraph_arpack_options_init(&options);
  igraph_vector_init(&v, 0);
  igraph_eigenvector_centrality(&g, &v, &value, /*directed=*/ 0, 
				/*scale=*/0, /*weights=*/0, 
				&options);

  if (options.info != 0) {
    return 1;
  }

  for (i=0; i<igraph_vector_size(&v); i++) {
    printf(" %.3f", fabs(VECTOR(v)[i]));
  }
  printf("\n");
  
  igraph_destroy(&g);

  /* Special cases: check for empty graph */
  igraph_empty(&g, 10, 0);
  igraph_eigenvector_centrality(&g, &v, &value, 0, 0, 0, &options);
  if (value != 0.0) {
    return 1;
  }
  for (i=0; i<igraph_vector_size(&v); i++) {
    printf(" %.2f", fabs(VECTOR(v)[i]));
  }
  printf("\n");
  igraph_destroy(&g);

  /* Special cases: check for full graph, zero weights */
  igraph_full(&g, 10, 0, 0);
  igraph_vector_init(&weights, 45);
  igraph_vector_fill(&weights, 0);
  igraph_eigenvector_centrality(&g, &v, &value, 0, 0, &weights, &options);
  igraph_vector_destroy(&weights);
  if (value != 0.0) {
    return 2;
  }
  for (i=0; i<igraph_vector_size(&v); i++) {
    printf(" %.2f", fabs(VECTOR(v)[i]));
  }
  printf("\n");
  igraph_destroy(&g);

  igraph_vector_destroy(&v);

  return 0;
}
Пример #2
0
int igraph_i_maximum_bipartite_matching_unweighted_relabel(const igraph_t* graph,
    const igraph_vector_bool_t* types, igraph_vector_t* labels,
    igraph_vector_long_t* match, igraph_bool_t smaller_set) {
  long int i, j, n, no_of_nodes = igraph_vcount(graph), matched_to;
  igraph_dqueue_long_t q;
  igraph_vector_t neis;

  debug("Running global relabeling.\n");

  /* Set all the labels to no_of_nodes first */
  igraph_vector_fill(labels, no_of_nodes);

  /* Allocate vector for neighbors */
  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);

  /* Create a FIFO for the BFS and initialize it with the unmatched rows
   * (i.e. members of the larger set) */
  IGRAPH_CHECK(igraph_dqueue_long_init(&q, 0));
  IGRAPH_FINALLY(igraph_dqueue_long_destroy, &q);
  for (i = 0; i < no_of_nodes; i++) {
    if (VECTOR(*types)[i] != smaller_set && VECTOR(*match)[i] == -1) {
      IGRAPH_CHECK(igraph_dqueue_long_push(&q, i));
      VECTOR(*labels)[i] = 0;
    }
  }

  /* Run the BFS */
  while (!igraph_dqueue_long_empty(&q)) {
    long int v = igraph_dqueue_long_pop(&q);
    long int w;

    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) v,
				  IGRAPH_ALL));

    n = igraph_vector_size(&neis);
    //igraph_vector_shuffle(&neis);
    for (j = 0; j < n; j++) {
      w = (long int) VECTOR(neis)[j];
      if (VECTOR(*labels)[w] == no_of_nodes) {
        VECTOR(*labels)[w] = VECTOR(*labels)[v] + 1;
        matched_to = VECTOR(*match)[w];
        if (matched_to != -1 && VECTOR(*labels)[matched_to] == no_of_nodes) {
          IGRAPH_CHECK(igraph_dqueue_long_push(&q, matched_to));
          VECTOR(*labels)[matched_to] = VECTOR(*labels)[w] + 1;
        }
      }
    }
  }
  printf("Inside relabel : ");
  igraph_vector_print(labels);
  igraph_dqueue_long_destroy(&q);
  igraph_vector_destroy(&neis);
  IGRAPH_FINALLY_CLEAN(2);

  return IGRAPH_SUCCESS;
}
Пример #3
0
int main() {

  igraph_t g;
  igraph_vector_t v, res, reset, weights;
  igraph_arpack_options_t arpack_options;
  igraph_real_t value;
  int ret;
  igraph_pagerank_power_options_t power_options;

  /* Test graphs taken from http://www.iprcom.com/papers/pagerank/ */
  igraph_vector_init(&v, 10);
  VECTOR(v)[0]=0; VECTOR(v)[1]=1;
  VECTOR(v)[2]=1; VECTOR(v)[3]=2;
  VECTOR(v)[4]=2; VECTOR(v)[5]=0;
  VECTOR(v)[6]=3; VECTOR(v)[7]=2;
  VECTOR(v)[8]=0; VECTOR(v)[9]=2;
  igraph_create(&g, &v, 0, 1);

  igraph_vector_init(&res, 0);
  oldwarn=igraph_set_warning_handler(warning_handler_stdout);
  igraph_pagerank_old(&g, &res, igraph_vss_all(), 1, 1000, 0.001, 0.85, 0);
  print_vector(&res, stdout);
  igraph_vector_destroy(&res);
  igraph_vector_destroy(&v);
  
  igraph_destroy(&g);

  igraph_vector_init(&v, 28);
  VECTOR(v)[ 0]=0; VECTOR(v)[ 1]=1;
  VECTOR(v)[ 2]=0; VECTOR(v)[ 3]=2;
  VECTOR(v)[ 4]=0; VECTOR(v)[ 5]=3;
  VECTOR(v)[ 6]=1; VECTOR(v)[ 7]=0;
  VECTOR(v)[ 8]=2; VECTOR(v)[ 9]=0;
  VECTOR(v)[10]=3; VECTOR(v)[11]=0;
  VECTOR(v)[12]=3; VECTOR(v)[13]=4;
  VECTOR(v)[14]=3; VECTOR(v)[15]=5;
  VECTOR(v)[16]=3; VECTOR(v)[17]=6;
  VECTOR(v)[18]=3; VECTOR(v)[19]=7;
  VECTOR(v)[20]=4; VECTOR(v)[21]=0;
  VECTOR(v)[22]=5; VECTOR(v)[23]=0;
  VECTOR(v)[24]=6; VECTOR(v)[25]=0;
  VECTOR(v)[26]=7; VECTOR(v)[27]=0;
  igraph_create(&g, &v, 0, 1);

  igraph_vector_init(&res, 0);
  igraph_pagerank_old(&g, &res, igraph_vss_all(), 1, 10000, 0.0001, 0.85, 0);
  print_vector(&res, stdout);
  igraph_vector_destroy(&res);
  igraph_vector_destroy(&v);
  igraph_destroy(&g);

  igraph_set_warning_handler(oldwarn);

  /* New PageRank */
  igraph_star(&g, 11, IGRAPH_STAR_UNDIRECTED, 0);
  igraph_vector_init(&res, 0);
  igraph_arpack_options_init(&arpack_options);
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, 0,
		  igraph_vss_all(), 0, 0.85, 0, &arpack_options);
  print_vector(&res, stdout);
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, 0,
		  igraph_vss_all(), 0, 0.85, 0, 0);
  print_vector(&res, stdout);
  /* Check twice more for consistency */
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, 0,
		  igraph_vss_all(), 0, 0.85, 0, &arpack_options);
  print_vector(&res, stdout);
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, 0,
		  igraph_vss_all(), 0, 0.85, 0, 0);
  print_vector(&res, stdout);

  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, 0,
		  igraph_vss_all(), 0, 0.85, 0, &arpack_options);
  print_vector(&res, stdout);
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, 0,
		  igraph_vss_all(), 0, 0.85, 0, 0);
  print_vector(&res, stdout);

  /* Check personalized PageRank */
  igraph_personalized_pagerank_vs(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, 0,
				  igraph_vss_all(), 0, 0.5,
				  igraph_vss_1(1), 0, &arpack_options);
  print_vector(&res, stdout);
  igraph_personalized_pagerank_vs(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, 0,
				  igraph_vss_all(), 0, 0.5,
				  igraph_vss_1(1), 0, 0);
  print_vector(&res, stdout);

  /* Errors */
  power_options.niter = -1; power_options.eps=0.0001;
  igraph_set_error_handler(igraph_error_handler_ignore);
  igraph_set_warning_handler(igraph_warning_handler_ignore);
  ret=igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_POWER, &res,
		      /*value=*/ 0, igraph_vss_all(), 1, 0.85,
		      /*weights=*/ 0, &power_options);
  if (ret != IGRAPH_EINVAL) {
    return 1;
  }
  
  power_options.niter=10000; power_options.eps=-1;
  ret=igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_POWER, &res,
		      /*value=*/ 0, igraph_vss_all(), 1, 0.85,
		      /*weights=*/ 0, &power_options);
  if (ret != IGRAPH_EINVAL) {
    return 2;
  }

  power_options.niter=10000; power_options.eps=0.0001;
  ret=igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_POWER, &res,
		      /*value=*/ 0, igraph_vss_all(), 1, 1.2,
		      /*weights=*/ 0, &power_options);
  if (ret != IGRAPH_EINVAL) {
    return 3;
  }

  igraph_vector_init(&reset, 2);
  ret=igraph_personalized_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, 0,
				   igraph_vss_all(), 0, 0.85, &reset, 0,
				   &arpack_options);
  if (ret != IGRAPH_EINVAL) {
    return 4;
  }
  ret=igraph_personalized_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, 0,
				   igraph_vss_all(), 0, 0.85, &reset, 0, 0);
  if (ret != IGRAPH_EINVAL) {
    return 4;
  }
  igraph_vector_resize(&reset, 10);
  igraph_vector_fill(&reset, 0);
  ret=igraph_personalized_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK,
				   &res, 0, igraph_vss_all(), 0, 0.85,
				   &reset, 0, &arpack_options);
  if (ret != IGRAPH_EINVAL) {
    return 5;
  }
  ret=igraph_personalized_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK,
				   &res, 0, igraph_vss_all(), 0, 0.85,
				   &reset, 0, 0);
  if (ret != IGRAPH_EINVAL) {
    return 5;
  }
  igraph_vector_destroy(&reset);
  igraph_destroy(&g);
  igraph_set_error_handler(igraph_error_handler_abort);

  /* Special cases: check for empty graph */
  igraph_empty(&g, 10, 0);
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, &value,
		  igraph_vss_all(), 1, 0.85, 0, &arpack_options);
  if (value != 1.0) {
    return 6;
  }
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, &value,
		  igraph_vss_all(), 1, 0.85, 0, 0);
  if (value != 1.0) {
    return 6;
  }
  print_vector(&res, stdout);
  igraph_destroy(&g);

  /* Special cases: check for full graph, zero weights */
  igraph_full(&g, 10, 0, 0);
  igraph_vector_init(&v, 45);
  igraph_vector_fill(&v, 0);
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, &value,
		  igraph_vss_all(), 1, 0.85, &v, &arpack_options);
  if (value != 1.0) {
    return 7;
  }
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, &value,
		  igraph_vss_all(), 1, 0.85, &v, 0);
  if (value != 1.0) {
    return 7;
  }
  igraph_vector_destroy(&v);
  print_vector(&res, stdout);
  igraph_destroy(&g);

  /* Another test case for PageRank (bug #792352) */
  igraph_small(&g, 9, 1, 0, 5, 1, 5, 2, 0, 3, 1, 5, 4, 5, 7, 6, 0, 8, 0, 8, 1, -1);
  igraph_vector_init(&weights, 9);
  VECTOR(weights)[0] = 4; VECTOR(weights)[1] = 5; VECTOR(weights)[2] = 5;
  VECTOR(weights)[3] = 4; VECTOR(weights)[4] = 4; VECTOR(weights)[5] = 4;
  VECTOR(weights)[6] = 3; VECTOR(weights)[7] = 4; VECTOR(weights)[8] = 4;
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, 0,
		  igraph_vss_all(), 1, 0.85, &weights, &arpack_options);
  print_vector(&res, stdout);
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, 0,
		  igraph_vss_all(), 1, 0.85, &weights, 0);
  print_vector(&res, stdout);
  igraph_vector_destroy(&weights);
  igraph_destroy(&g);

  igraph_vector_destroy(&res);
  return 0;
}
Пример #4
0
int igraph_cocitation_real(const igraph_t *graph, igraph_matrix_t *res, 
                           igraph_vs_t vids,
                           igraph_neimode_t mode,
                           igraph_vector_t *weights) {

  long int no_of_nodes=igraph_vcount(graph);
  long int no_of_vids;
  long int from, i, j, k, l, u, v;
  igraph_vector_t neis=IGRAPH_VECTOR_NULL;
  igraph_vector_t vid_reverse_index;
  igraph_vit_t vit;
  
  IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
  IGRAPH_FINALLY(igraph_vit_destroy, &vit);

  no_of_vids = IGRAPH_VIT_SIZE(vit);

  /* Create a mapping from vertex IDs to the row of the matrix where
   * the result for this vertex will appear */
  IGRAPH_VECTOR_INIT_FINALLY(&vid_reverse_index, no_of_nodes);
  igraph_vector_fill(&vid_reverse_index, -1);
  for (IGRAPH_VIT_RESET(vit), i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
    v = IGRAPH_VIT_GET(vit);
    if (v < 0 || v >= no_of_nodes)
      IGRAPH_ERROR("invalid vertex ID in vertex selector", IGRAPH_EINVAL);
    VECTOR(vid_reverse_index)[v] = i;
  }

  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_vids, no_of_nodes));
  igraph_matrix_null(res);

  /* The result */
  
  for (from=0; from<no_of_nodes; from++) {
    igraph_real_t weight = 1;

    IGRAPH_ALLOW_INTERRUPTION();
    IGRAPH_CHECK(igraph_neighbors(graph, &neis, 
				  (igraph_integer_t) from, mode));
    if (weights)
      weight = VECTOR(*weights)[from];

    for (i=0; i < igraph_vector_size(&neis)-1; i++) {
      u = (long int) VECTOR(neis)[i];
      k = (long int) VECTOR(vid_reverse_index)[u];
      for (j=i+1; j<igraph_vector_size(&neis); j++) {
        v = (long int) VECTOR(neis)[j];
        l = (long int) VECTOR(vid_reverse_index)[v];
        if (k != -1)
          MATRIX(*res, k, v) += weight;
        if (l != -1)
          MATRIX(*res, l, u) += weight;
      }
    }
  }

  /* Clean up */
  igraph_vector_destroy(&neis);
  igraph_vector_destroy(&vid_reverse_index);
  igraph_vit_destroy(&vit);
  IGRAPH_FINALLY_CLEAN(3);

  return 0;
}
Пример #5
0
igraph_vector_t * ggen_analyze_longest_path(igraph_t *g)
{
	igraph_vector_t topology;
	igraph_vector_t lengths;
	igraph_vector_t preds;
	igraph_vs_t vs;
	igraph_vit_t vit;
	igraph_vector_t *res = NULL;
	int err;
	unsigned long v,i,f,t;
	long maxv;
	if(g == NULL)
		return NULL;

	v = igraph_vcount(g);
	err = igraph_vector_init(&topology,v);
	if(err)	return NULL;

	err = igraph_vector_init(&lengths,v);
	if(err) goto error_il;

	err = igraph_vector_init(&preds,v);
	if(err) goto error_ip;

	res = malloc(sizeof(igraph_vector_t));
	if(res == NULL) goto cleanup;

	err = igraph_vector_init(res,v);
	if(err) goto error_ir;

	// sort topologically the vertices
	err = igraph_topological_sorting(g,&topology,IGRAPH_OUT);
	if(err) goto error;
	// igraph is stupid, it returns 0 even if the graph isn't a dag
	if(igraph_vector_size(&topology) != v)
		goto error;

	// find the best path incomming from every node
	igraph_vector_null(&lengths);
	igraph_vector_fill(&preds,-1);
	maxv = -1;
	for(i = 0; i < v; i++)
	{
		f = VECTOR(topology)[i];
		err = igraph_vs_adj(&vs,f,IGRAPH_OUT);
		if(err) goto error;
		err = igraph_vit_create(g,vs,&vit);
		if(err)
		{
			igraph_vs_destroy(&vs);
			goto error;
		}

		for(vit; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit))
		{
			t = IGRAPH_VIT_GET(vit);
			if(VECTOR(lengths)[t] < VECTOR(lengths)[f] + 1)
			{
				VECTOR(lengths)[t] = VECTOR(lengths)[f] +1;
				VECTOR(preds)[t] = f;
			}
			if(maxv == -1 || VECTOR(lengths)[t] > VECTOR(lengths)[maxv])
				maxv = t;
		}
		igraph_vs_destroy(&vs);
		igraph_vit_destroy(&vit);

	}
	// build the path, using preds and maxv
	f = 0;
	while(maxv != -1)
	{
		VECTOR(*res)[f++] = maxv;
		maxv = VECTOR(preds)[maxv];
	}

	// finish the path correctly, resizing and reversing the array
	err = igraph_vector_resize(res,f);
	if(err) goto error;

	err = igraph_vector_reverse(res);
	if(err) goto error;

	goto cleanup;
error:
	igraph_vector_destroy(res);
error_ir:
	free(res);
	res = NULL;
cleanup:
	igraph_vector_destroy(&preds);
error_ip:
	igraph_vector_destroy(&lengths);
error_il:
	igraph_vector_destroy(&topology);
	return res;
}
Пример #6
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;
}
Пример #7
0
int main() {
  
  igraph_t g;
  igraph_vector_t bet, bet2, weights, edges;
  igraph_vector_t bbet, bbet2;
  
  igraph_real_t nontriv[] = { 0, 19, 0, 16, 0, 20, 1, 19, 2, 5, 3, 7, 3, 8, 
			      4, 15, 4, 11, 5, 8, 5, 19, 6, 7, 6, 10, 6, 8, 
			      6, 9, 7, 20, 9, 10, 9, 20, 10, 19, 
			      11, 12, 11, 20, 12, 15, 13, 15, 
			      14, 18, 14, 16, 14, 17, 15, 16, 17, 18 };
  
  igraph_real_t nontriv_weights[] = { 0.5249, 1, 0.1934, 0.6274, 0.5249, 
				      0.0029, 0.3831, 0.05, 0.6274, 0.3831, 
				      0.5249, 0.0587, 0.0579, 0.0562, 0.0562, 
				      0.1934, 0.6274, 0.6274, 0.6274, 0.0418, 
				      0.6274, 0.3511, 0.3511, 0.1486, 1, 1, 
				      0.0711, 0.2409 };

  igraph_real_t nontriv_res[] = { 20, 0, 0, 0, 0, 19, 80, 85, 32, 0, 10, 
				  75, 70, 0, 36, 81, 60, 0, 19, 19, 86 };

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

  igraph_barabasi_game(/* graph= */    &g,
		       /* n= */        1000,
		       /* power= */    1,
		       /* m= */        3,
		       /* outseq= */   0,
		       /* outpref= */  0,
		       /* A= */        1,
		       /* directed= */ 0, 
		       /* algo= */     IGRAPH_BARABASI_BAG,
		       /* start_from= */ 0);
  
  igraph_simplify(&g, /* multiple= */ 1, /* loops= */ 1, /*edge_comb=*/ 0);
  
  igraph_vector_init(&bet, 0);
  igraph_vector_init(&bbet, 0);
  
  igraph_betweenness_estimate(/* graph=     */ &g,
			      /* res=       */ &bet,
			      /* vids=      */ igraph_vss_all(),
			      /* directed = */ 0,
			      /* cutoff=    */ 2,
			      /* weights=   */ 0, 
			      /* nobigint=  */ 1);

  igraph_betweenness_estimate(/* graph=     */ &g,
			      /* res=       */ &bbet,
			      /* vids=      */ igraph_vss_all(),
			      /* directed = */ 0,
			      /* cutoff=    */ 2,
			      /* weights=   */ 0, 
			      /* nobigint=  */ 0);  

  check(&bet, &bbet, 10);

  igraph_vector_destroy(&bet);
  igraph_vector_destroy(&bbet);
  igraph_destroy(&g);

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

  igraph_tree(&g, 20000, 10, IGRAPH_TREE_UNDIRECTED);
  
  igraph_vector_init(&bet, 0);
  igraph_vector_init(&bbet, 0);
  
  igraph_betweenness_estimate(/* graph=     */ &g,
			      /* res=       */ &bet,
			      /* vids=      */ igraph_vss_all(),
			      /* directed = */ 0,
			      /* cutoff=    */ 3,
			      /* weights=   */ 0, 
			      /* nobigint=  */ 1);

  igraph_betweenness_estimate(/* graph=     */ &g,
			      /* res=       */ &bbet,
			      /* vids=      */ igraph_vss_all(),
			      /* directed = */ 0,
			      /* cutoff=    */ 3,
			      /* weights=   */ 0, 
			      /* nobigint=  */ 0);

  check(&bet, &bbet, 20);

  igraph_vector_init(&bet2, 0);
  igraph_vector_init(&bbet2, 0);
  igraph_vector_init(&weights, igraph_ecount(&g));
  igraph_vector_fill(&weights, 1.0);
  
  igraph_betweenness_estimate(/* graph=     */ &g,
			      /* res=       */ &bet2,
			      /* vids=      */ igraph_vss_all(),
			      /* directed = */ 0,
			      /* cutoff=    */ 3,
			      /* weights=   */ &weights, 
			      /* nobigint=  */ 1);

  igraph_betweenness_estimate(/* graph=     */ &g,
			      /* res=       */ &bbet2,
			      /* vids=      */ igraph_vss_all(),
			      /* directed = */ 0,
			      /* cutoff=    */ 3,
			      /* weights=   */ &weights, 
			      /* nobigint=  */ 0);

  if (!igraph_vector_all_e(&bet, &bet2)) {
    return 1;
  }

/*   if (!igraph_vector_all_e(&bbet, &bbet2)) { */
/*     return 2; */
/*   } */

  check(&bet, &bbet, 30);
  check(&bet2, &bbet2, 40);

  igraph_vector_destroy(&bet);
  igraph_vector_destroy(&bet2);
  igraph_vector_destroy(&bbet);
  igraph_vector_destroy(&bbet2);
  igraph_vector_destroy(&weights);
  igraph_destroy(&g);

  /* Non-trivial weighted graph */
  igraph_vector_view(&edges, nontriv, sizeof(nontriv)/sizeof(igraph_real_t));
  igraph_create(&g, &edges, 0, /* directed= */ 0);
  igraph_vector_view(&weights, nontriv_weights, 
		     sizeof(nontriv_weights)/sizeof(igraph_real_t));
  igraph_vector_init(&bet, 0);
  igraph_vector_init(&bbet, 0);

  igraph_betweenness(/*graph=*/ &g, /*res=*/ &bet, /*vids=*/ igraph_vss_all(), 
		     /*directed=*/0, /*weights=*/ &weights, /*nobigint=*/ 1);

  igraph_betweenness(/*graph=*/ &g, /*res=*/ &bbet, /*vids=*/ igraph_vss_all(), 
		     /*directed=*/0, /*weights=*/ &weights, /*nobigint=*/ 0);

  igraph_vector_view(&bet2, nontriv_res, 
		     sizeof(nontriv_res)/sizeof(igraph_real_t));

  if (!igraph_vector_all_e(&bet, &bet2)) {
    return 2;
  }

  check(&bet, &bbet, 50);
  
  igraph_vector_destroy(&bet);
  igraph_vector_destroy(&bbet);
  igraph_destroy(&g);

  if (IGRAPH_FINALLY_STACK_SIZE() != 0) return 3;

  return 0;
}
Пример #8
0
/**
 * \ingroup communities
 * \function igraph_i_community_multilevel_step
 * \brief Performs a single step of the multi-level modularity optimization method
 *
 * This function implements a single step of the multi-level modularity optimization
 * algorithm for finding community structure, see VD Blondel, J-L Guillaume,
 * R Lambiotte and E Lefebvre: Fast unfolding of community hierarchies in large
 * networks, http://arxiv.org/abs/0803.0476 for the details.
 *
 * This function was contributed by Tom Gregorovic.
 *
 * \param graph   The input graph. It must be an undirected graph.
 * \param weights Numeric vector containing edge weights. If \c NULL, every edge
 *     has equal weight. The weights are expected to be non-negative.
 * \param membership The membership vector, the result is returned here.
 *     For each vertex it gives the ID of its community.
 * \param modularity The modularity of the partition is returned here.
 *     \c NULL means that the modularity is not needed.
 * \return Error code.
 *
 * Time complexity: in average near linear on sparse graphs.
 */
int igraph_i_community_multilevel_step(igraph_t *graph,
  igraph_vector_t *weights, igraph_vector_t *membership,
  igraph_real_t *modularity) {
  
  long int i, j;
  long int vcount = igraph_vcount(graph);
  long int ecount = igraph_ecount(graph);
  igraph_integer_t ffrom, fto;
  igraph_real_t q, pass_q;
  int pass;
  igraph_bool_t changed = 0;
  igraph_vector_t links_community;
  igraph_vector_t links_weight;
  igraph_vector_t edges;
  igraph_vector_t temp_membership;
  igraph_i_multilevel_community_list communities;

  /* Initial sanity checks on the input parameters */
  if (igraph_is_directed(graph)) {
    IGRAPH_ERROR("multi-level community detection works for undirected graphs only",
        IGRAPH_UNIMPLEMENTED);
  }
  if (igraph_vector_size(weights) < igraph_ecount(graph))
    IGRAPH_ERROR("multi-level community detection: weight vector too short", IGRAPH_EINVAL);
  if (igraph_vector_any_smaller(weights, 0))
    IGRAPH_ERROR("weights must be positive", IGRAPH_EINVAL);

  /* Initialize data structures */
  IGRAPH_VECTOR_INIT_FINALLY(&links_community, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&links_weight, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&temp_membership, vcount);
  IGRAPH_CHECK(igraph_vector_resize(membership, vcount));
 
  /* Initialize list of communities from graph vertices */
  communities.vertices_no = vcount;
  communities.communities_no = vcount;
  communities.weights = weights;
  communities.weight_sum = 2 * igraph_vector_sum(weights);
  communities.membership = membership;
  communities.item = igraph_Calloc(vcount, igraph_i_multilevel_community);
  if (communities.item == 0) {
    IGRAPH_ERROR("multi-level community structure detection failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, communities.item);

  /* Still initializing the communities data structure */
  for (i=0; i < vcount; i++) {
    VECTOR(*communities.membership)[i] = i;
    communities.item[i].size = 1;
    communities.item[i].weight_inside = 0;
    communities.item[i].weight_all = 0;
  }

  /* Some more initialization :) */
  for (i = 0; i < ecount; i++) {
    igraph_real_t weight = 1;
    igraph_edge(graph, (igraph_integer_t) i, &ffrom, &fto);

    weight = VECTOR(*weights)[i];
    communities.item[(long int) ffrom].weight_all += weight;
    communities.item[(long int) fto].weight_all += weight;
    if (ffrom == fto)
      communities.item[(long int) ffrom].weight_inside += 2*weight;
  }

  q = igraph_i_multilevel_community_modularity(&communities);
  pass = 1;

  do { /* Pass begin */
    long int temp_communities_no = communities.communities_no;

    pass_q = q;
    changed = 0;
    
    /* Save the current membership, it will be restored in case of worse result */
    IGRAPH_CHECK(igraph_vector_update(&temp_membership, communities.membership));

    for (i = 0; i < vcount; i++) {
      /* Exclude vertex from its current community */
      igraph_real_t weight_all = 0;
      igraph_real_t weight_inside = 0;
      igraph_real_t weight_loop = 0;
      igraph_real_t max_q_gain = 0;
      igraph_real_t max_weight;
      long int old_id, new_id, n;

      igraph_i_multilevel_community_links(graph, &communities, 
					  (igraph_integer_t) i, &edges,
					  &weight_all, &weight_inside, 
					  &weight_loop, &links_community,
					  &links_weight);
      old_id = (long int)VECTOR(*(communities.membership))[i];
      new_id = old_id;

      /* Update old community */
      igraph_vector_set(communities.membership, i, -1);
      communities.item[old_id].size--;
      if (communities.item[old_id].size == 0) {communities.communities_no--;}
      communities.item[old_id].weight_all -= weight_all;
      communities.item[old_id].weight_inside -= 2*weight_inside + weight_loop;

      /* debug("Remove %ld all: %lf Inside: %lf\n", i, -weight_all, -2*weight_inside + weight_loop); */

      /* Find new community to join with the best modification gain */
      max_q_gain = 0;
      max_weight = weight_inside;
      n = igraph_vector_size(&links_community);
   
      igraph_vector_sort(&links_community);
    
      for (j = 0; j < n; j++) {
        long int c = (long int) VECTOR(links_community)[j];
        igraph_real_t w = VECTOR(links_weight)[j];

        igraph_real_t q_gain = 
	  igraph_i_multilevel_community_modularity_gain(&communities, 
							(igraph_integer_t) c, 
							(igraph_integer_t) i,
							weight_all, w);
        /* debug("Link %ld -> %ld weight: %lf gain: %lf\n", i, c, (double) w, (double) q_gain); */
        if (q_gain > max_q_gain) {
          new_id = c;
          max_q_gain = q_gain;
          max_weight = w;
        }
      }

      /* debug("Added vertex %ld to community %ld (gain %lf).\n", i, new_id, (double) max_q_gain); */

      /* Add vertex to "new" community and update it */
      igraph_vector_set(communities.membership, i, new_id);
      if (communities.item[new_id].size == 0) {communities.communities_no++;}
      communities.item[new_id].size++;
      communities.item[new_id].weight_all += weight_all;
      communities.item[new_id].weight_inside += 2*max_weight + weight_loop;

      if (new_id != old_id) {
        changed++;
      }
       
    }
        
    q = igraph_i_multilevel_community_modularity(&communities);

    if (changed && (q > pass_q)) { 
      /* debug("Pass %d (changed: %d) Communities: %ld Modularity from %lf to %lf\n",
        pass, changed, communities.communities_no, (double) pass_q, (double) q); */
      pass++;
    } else {
      /* No changes or the modularity became worse, restore last membership */
      IGRAPH_CHECK(igraph_vector_update(communities.membership, &temp_membership));
      communities.communities_no = temp_communities_no;
      break;
    }

    IGRAPH_ALLOW_INTERRUPTION();
  } while (changed && (q > pass_q)); /* Pass end */

  if (modularity) {
    *modularity = q;
  }

  /* debug("Result Communities: %ld Modularity: %lf\n",
    communities.communities_no, (double) q); */

  IGRAPH_CHECK(igraph_reindex_membership(membership, 0));

  /* Shrink the nodes of the graph according to the present community structure
   * and simplify the resulting graph */

  /* TODO: check if we really need to copy temp_membership */
  IGRAPH_CHECK(igraph_vector_update(&temp_membership, membership));
  IGRAPH_CHECK(igraph_i_multilevel_shrink(graph, &temp_membership));
  igraph_vector_destroy(&temp_membership);
  IGRAPH_FINALLY_CLEAN(1);  
  
  /* Update edge weights after shrinking and simplification */
  /* Here we reuse the edges vector as we don't need the previous contents anymore */
  /* TODO: can we use igraph_simplify here? */
  IGRAPH_CHECK(igraph_i_multilevel_simplify_multiple(graph, &edges));

  /* We reuse the links_weight vector to store the old edge weights */
  IGRAPH_CHECK(igraph_vector_update(&links_weight, weights));
  igraph_vector_fill(weights, 0);
   
  for (i = 0; i < ecount; i++) {
    VECTOR(*weights)[(long int)VECTOR(edges)[i]] += VECTOR(links_weight)[i];
  }

  igraph_free(communities.item);
  igraph_vector_destroy(&links_community);
  igraph_vector_destroy(&links_weight);
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(4);
  
  return 0;
}
Пример #9
0
/* Fan-in/ Fan-out method
*/
igraph_t *ggen_generate_fifo(gsl_rng *r, unsigned long n, unsigned long od, unsigned long id)
{
    igraph_t *g = NULL;
    igraph_vector_t available_od;
    igraph_vector_t out_degrees;
    igraph_vector_t vertices;
    igraph_vector_t choice;
    igraph_vector_t edges;
    unsigned long max;
    unsigned long i,j,k;
    unsigned long vcount = 1;
    int err;

    ggen_error_start_stack();
    if(r == NULL)
        GGEN_SET_ERRNO(GGEN_EINVAL);

    if(id == 0 || od == 0 || od > n || id > n)
        GGEN_SET_ERRNO(GGEN_EINVAL);

    g = malloc(sizeof(igraph_t));
    GGEN_CHECK_ALLOC(g);
    GGEN_FINALLY3(free,g,1);

    GGEN_CHECK_IGRAPH(igraph_empty(g,1,1));
    GGEN_FINALLY3(igraph_destroy,g,1);

    GGEN_CHECK_IGRAPH(igraph_vector_init(&available_od,n));
    GGEN_FINALLY(igraph_vector_destroy,&available_od);
    GGEN_CHECK_IGRAPH(igraph_vector_init(&out_degrees,n));
    GGEN_FINALLY(igraph_vector_destroy,&out_degrees);
    GGEN_CHECK_IGRAPH(igraph_vector_init(&vertices,n));
    GGEN_FINALLY(igraph_vector_destroy,&vertices);
    GGEN_CHECK_IGRAPH(igraph_vector_init(&choice,n));
    GGEN_FINALLY(igraph_vector_destroy,&choice);
    GGEN_CHECK_IGRAPH(igraph_vector_init(&edges,n*2));
    GGEN_FINALLY(igraph_vector_destroy,&edges);
    while(vcount < n)
    {
        // never trigger errors as it doesn't allocate or free memory
        igraph_vector_resize(&available_od,vcount);
        igraph_vector_resize(&out_degrees,vcount);
        igraph_vector_resize(&vertices,vcount);

        // compute the available out degree of each vertex
        GGEN_CHECK_IGRAPH(igraph_degree(g,&out_degrees,igraph_vss_all(),IGRAPH_OUT,0));

        // fill available with od and substract out_degrees
        igraph_vector_fill(&available_od,od);
        GGEN_CHECK_IGRAPH(igraph_vector_sub(&available_od,&out_degrees));

        if(gsl_ran_bernoulli(r,0.5))     //Fan-out Step
        {
            // find max
            max = igraph_vector_max(&available_od);

            // register all vertices having max as outdegree
            j = 0;
            for (i = 0; i < vcount; i++)
                if(VECTOR(available_od)[i] == max)
                    VECTOR(vertices)[j++] = i;

            // choose randomly a vertex among availables
            GGEN_CHECK_GSL_DO(i = gsl_rng_uniform_int(r,j));

            // how many children ?
            GGEN_CHECK_GSL_DO(j = gsl_rng_uniform_int(r,max));
            j = j+1;

            // create all new nodes and add edges
            GGEN_CHECK_IGRAPH(igraph_add_vertices(g,j,NULL));

            // cannot fail
            igraph_vector_resize(&edges,j*2);

            for(k = 0; k < j; k++)
            {
                VECTOR(edges)[2*k] = i;
                VECTOR(edges)[2*k+1] = vcount + k;
            }
            vcount+=k;
        }
        else	//Fan-In Step
        {
            // register all vertices having an available outdegree
            j = 0;
            for (i = 0; i < vcount; i++)
                if(VECTOR(available_od)[i] > 0)
                    VECTOR(vertices)[j++] = i;

            // we can add at most id vertices
            max =( j > id)? id: j;
            // how many edges to add
            GGEN_CHECK_GSL_DO(k = gsl_rng_uniform_int(r,max));
            k = k+1;

            // choose that many nodes and add edges from them to the new node
            // cannot fail either
            igraph_vector_resize(&choice,k);

            gsl_ran_choose(r,VECTOR(choice),k,
                           VECTOR(vertices),j,sizeof(VECTOR(vertices)[0]));

            // add a vertex to the graph
            GGEN_CHECK_IGRAPH(igraph_add_vertices(g,1,NULL));

            igraph_vector_resize(&edges,k*2);
            // be carefull, vcount is the last ID of vertices not vcount +1
            for(i = 0; i < k; i++)
            {
                VECTOR(edges)[2*i] = VECTOR(choice)[i];
                VECTOR(edges)[2*i+1] = vcount;
            }
            vcount++;

        }
        // in all cases, edges should be added
        GGEN_CHECK_IGRAPH(igraph_add_edges(g,&edges,NULL));
    }
    ggen_error_clean(1);
    return g;
ggen_error_label:
    return NULL;
}
Пример #10
0
int igraph_intersection_many(igraph_t *res, 
			     const igraph_vector_ptr_t *graphs, 
			     igraph_vector_ptr_t *edgemaps) {

  long int no_of_graphs=igraph_vector_ptr_size(graphs);
  long int no_of_nodes=0;
  igraph_bool_t directed=1;
  igraph_vector_t edges;
  igraph_vector_ptr_t edge_vects, order_vects;
  long int i, j, tailfrom = no_of_graphs > 0 ? 0 : -1, tailto=-1;
  igraph_vector_long_t no_edges;
  igraph_bool_t allne= no_of_graphs == 0 ? 0 : 1, allsame=0;
  long int idx=0;
  
  /* Check directedness */
  if (no_of_graphs != 0) {
    directed=igraph_is_directed(VECTOR(*graphs)[0]);
  }
  for (i=1; i<no_of_graphs; i++) {
    if (directed != igraph_is_directed(VECTOR(*graphs)[i])) {
      IGRAPH_ERROR("Cannot intersect directed and undirected graphs",
		   IGRAPH_EINVAL);
    }
  }

  if (edgemaps) {
    IGRAPH_CHECK(igraph_vector_ptr_resize(edgemaps, no_of_graphs));
    igraph_vector_ptr_null(edgemaps);
    IGRAPH_FINALLY(igraph_i_union_many_free3, edgemaps);
  }

  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  IGRAPH_CHECK(igraph_vector_long_init(&no_edges, no_of_graphs));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &no_edges);

  /* Calculate number of nodes, query number of edges */
  for (i=0; i<no_of_graphs; i++) {
    long int n=igraph_vcount(VECTOR(*graphs)[i]);
    if (n > no_of_nodes) { no_of_nodes=n; }
    VECTOR(no_edges)[i] = igraph_ecount(VECTOR(*graphs)[i]);
    allne = allne && VECTOR(no_edges)[i] > 0;
  }

  if (edgemaps) {
    for (i=0; i<no_of_graphs; i++) {
      VECTOR(*edgemaps)[i]=igraph_Calloc(1, igraph_vector_t);
      if (!VECTOR(*edgemaps)[i]) {
	IGRAPH_ERROR("Cannot intersect graphs", IGRAPH_ENOMEM);
      }
      IGRAPH_CHECK(igraph_vector_init(VECTOR(*edgemaps)[i],
				      VECTOR(no_edges)[i]));
      igraph_vector_fill(VECTOR(*edgemaps)[i], -1);
    }
  }

  /* Allocate memory for the edge lists and their index vectors */
  if (no_of_graphs != 0) {
    IGRAPH_CHECK(igraph_vector_ptr_init(&edge_vects, no_of_graphs));
    IGRAPH_FINALLY(igraph_i_union_many_free, &edge_vects);
    IGRAPH_CHECK(igraph_vector_ptr_init(&order_vects, no_of_graphs));
    IGRAPH_FINALLY(igraph_i_union_many_free2, &order_vects);
  }
  for (i=0; i<no_of_graphs; i++) {
    VECTOR(edge_vects)[i]=igraph_Calloc(1, igraph_vector_t);
    VECTOR(order_vects)[i]=igraph_Calloc(1, igraph_vector_long_t);
    if (! VECTOR(edge_vects)[i] || ! VECTOR(order_vects)[i]) { 
      IGRAPH_ERROR("Cannot intersect graphs", IGRAPH_ENOMEM);
    }
    IGRAPH_CHECK(igraph_vector_init(VECTOR(edge_vects)[i],
				    2 * VECTOR(no_edges)[i]));
    IGRAPH_CHECK(igraph_vector_long_init(VECTOR(order_vects)[i], 
					 VECTOR(no_edges)[i]));
  }

  /* Query and sort the edge lists */
  for (i=0; i<no_of_graphs; i++) {
    long int k, j, n=VECTOR(no_edges)[i];
    igraph_vector_t *edges=VECTOR(edge_vects)[i];
    igraph_vector_long_t *order=VECTOR(order_vects)[i];
    IGRAPH_CHECK(igraph_get_edgelist(VECTOR(*graphs)[i], edges, /*bycol=*/0));
    if (!directed) {
      for (k=0, j=0; k<n; k++, j+=2) {
	if (VECTOR(*edges)[j] > VECTOR(*edges)[j+1]) {
	  long int tmp=VECTOR(*edges)[j];
	  VECTOR(*edges)[j]=VECTOR(*edges)[j+1];
	  VECTOR(*edges)[j+1]=tmp;
	}
      }
    }
    for (k=0; k<n; k++) { VECTOR(*order)[k]=k; }
    igraph_qsort_r(VECTOR(*order), n, sizeof(VECTOR(*order)[0]), edges, 
		   igraph_i_order_edgelist_cmp);
  }

  /* Do the merge. We work from the end of the edge lists, 
     because then we don't have to keep track of where we are right
     now in the edge and order lists. We find the "largest" edge,
     and if it is present in all graphs, then we copy it to the
     result. We remove all instances of this edge.  */

  while (allne) {

    /* Look for the smallest tail element */
    for (j=0, tailfrom=LONG_MAX, tailto=LONG_MAX; j<no_of_graphs; j++) {
      long int edge=igraph_vector_long_tail(VECTOR(order_vects)[j]);
      igraph_vector_t *ev=VECTOR(edge_vects)[j];
      long int from=VECTOR(*ev)[2*edge];
      long int to=VECTOR(*ev)[2*edge+1];
      if (from < tailfrom || (from == tailfrom && to < tailto)) {
	tailfrom = from; tailto = to;
      }
    }
    
    /* OK, now remove all elements from the tail(s) that are bigger
       than the smallest tail element. */
    for (j=0, allsame=1; j<no_of_graphs; j++) { 
      long int from=-1, to=-1;
      while (1) {
	long int edge=igraph_vector_long_tail(VECTOR(order_vects)[j]);
	igraph_vector_t *ev=VECTOR(edge_vects)[j];
	from=VECTOR(*ev)[2*edge];
	to=VECTOR(*ev)[2*edge+1];
	if (from > tailfrom || (from==tailfrom && to > tailto)) {
	  igraph_vector_long_pop_back(VECTOR(order_vects)[j]);
	  if (igraph_vector_long_empty(VECTOR(order_vects)[j])) {
	    allne=0;
	    break;
	  }
	} else {
	  break;
	}
      }
      if (from != tailfrom || to != tailto) { allsame=0; }
    } 

    /* Add the edge, if the smallest tail element was present 
       in all graphs. */
    if (allsame) { 
      IGRAPH_CHECK(igraph_vector_push_back(&edges, tailfrom));
      IGRAPH_CHECK(igraph_vector_push_back(&edges, tailto));
    }

    /* Drop edges matching the smalles tail elements
       from the order vectors, build edge maps */
    if (allne) {
      for (j=0; j<no_of_graphs; j++) {
	long int edge=igraph_vector_long_tail(VECTOR(order_vects)[j]);
	igraph_vector_t *ev=VECTOR(edge_vects)[j];
	long int from=VECTOR(*ev)[2*edge];
	long int to=VECTOR(*ev)[2*edge+1];
	if (from == tailfrom && to == tailto) {
	  igraph_vector_long_pop_back(VECTOR(order_vects)[j]);
	  if (igraph_vector_long_empty(VECTOR(order_vects)[j])) {
	    allne=0;
	  }
	  if (edgemaps && allsame) {
	    igraph_vector_t *map=VECTOR(*edgemaps)[j];
	    VECTOR(*map)[edge]=idx;
	  }
	}
      }
      if (allsame) { idx++; }
    }

  } /* while allne */

  if (no_of_graphs > 0) {
    igraph_i_union_many_free2(&order_vects);
    igraph_i_union_many_free(&edge_vects);
    IGRAPH_FINALLY_CLEAN(2);
  }
  
  igraph_vector_long_destroy(&no_edges);
  IGRAPH_FINALLY_CLEAN(1);  

  IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) no_of_nodes,
			     directed));
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  if (edgemaps) { IGRAPH_FINALLY_CLEAN(1); }    

  return 0;
}
Пример #11
0
int main() {
  
  igraph_t g, g2;
  FILE *ifile;
  igraph_vector_t gtypes, vtypes, etypes;
  igraph_strvector_t gnames, vnames, enames;
  long int i;
  igraph_vector_t y;
  igraph_strvector_t id;
  char str[20];

  /* turn on attribute handling */
  igraph_i_set_attribute_table(&igraph_cattribute_table);
  
  ifile=fopen("LINKS.NET", "r");
  if (ifile==0) {
    return 10;
  }
  igraph_read_graph_pajek(&g, ifile);
  fclose(ifile);

  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);
  
  /* List attribute names and types */
  printf("Graph attributes: ");
  for (i=0; i<igraph_strvector_size(&gnames); i++) {
    printf("%s (%i) ", STR(gnames, i), (int)VECTOR(gtypes)[i]);
  }
  printf("\n");
  printf("Vertex attributes: ");
  for (i=0; i<igraph_strvector_size(&vnames); i++) {
    printf("%s (%i) ", STR(vnames, i), (int)VECTOR(vtypes)[i]);
  }
  printf("\n");
  printf("Edge attributes: ");
  for (i=0; i<igraph_strvector_size(&enames); i++) {
    printf("%s (%i) ", STR(enames, i), (int)VECTOR(etypes)[i]);
  }
  printf("\n");

  print_attributes(&g);

  /* Copying a graph */
  igraph_copy(&g2, &g);
  print_attributes(&g2);
  igraph_destroy(&g2);
  
  /* Adding vertices */
  igraph_add_vertices(&g, 3, 0);
  print_attributes(&g);

  /* Adding edges */
  igraph_add_edge(&g, 1, 1);
  igraph_add_edge(&g, 2, 5);
  igraph_add_edge(&g, 3, 6);
  print_attributes(&g);

  /* Deleting vertices */
  igraph_delete_vertices(&g, igraph_vss_1(1));
  igraph_delete_vertices(&g, igraph_vss_1(4));
  print_attributes(&g);

  /* Deleting edges */
  igraph_delete_edges(&g, igraph_ess_1(igraph_ecount(&g)-1));
  igraph_delete_edges(&g, igraph_ess_1(0));
  print_attributes(&g);

  /* Set graph attributes */
  SETGAN(&g, "id", 10);
  if (GAN(&g, "id") != 10) {
    return 11;
  }
  SETGAS(&g, "name", "toy");
  if (strcmp(GAS(&g, "name"), "toy")) {
    return 12;
  }
  
  /* Delete graph attributes */
  DELGA(&g, "id");
  DELGA(&g, "name");
  igraph_cattribute_list(&g, &gnames, 0,0,0,0,0);
  if (igraph_strvector_size(&gnames) != 0) {
    return 14;
  }  

  /* Delete vertex attributes */
  DELVA(&g, "x");
  DELVA(&g, "shape");
  DELVA(&g, "xfact");
  DELVA(&g, "yfact");
  igraph_cattribute_list(&g, 0,0, &vnames, 0,0,0);  
  if (igraph_strvector_size(&vnames) != 2) {
    return 15;
  }
  
  /* Delete edge attributes */
  igraph_cattribute_list(&g, 0,0,0,0,&enames,0);
  i=igraph_strvector_size(&enames);
  DELEA(&g, "hook1");
  DELEA(&g, "hook2"); 
  DELEA(&g, "label");
  igraph_cattribute_list(&g, 0,0,0,0,&enames,0);
  if (igraph_strvector_size(&enames) != i-3) {
    return 16;
  }
  
  /* Set vertex attributes */
  SETVAN(&g, "y", 0, -1);
  SETVAN(&g, "y", 1, 2.1);
  if (VAN(&g, "y", 0) != -1 || 
      VAN(&g, "y", 1) != 2.1) {
    return 17;
  }
  SETVAS(&g, "id", 0, "foo");
  SETVAS(&g, "id", 1, "bar");
  if (strcmp(VAS(&g, "id", 0), "foo") ||
      strcmp(VAS(&g, "id", 1), "bar")) {
    return 18;
  }

  /* Set edge attributes */
  SETEAN(&g, "weight", 2, 100.0);
  SETEAN(&g, "weight", 0, -100.1);
  if (EAN(&g, "weight", 2) != 100.0 ||
      EAN(&g, "weight", 0) != -100.1) {
    return 19;
  }
  SETEAS(&g, "color", 2, "RED");
  SETEAS(&g, "color", 0, "Blue");
  if (strcmp(EAS(&g, "color", 2), "RED") ||
      strcmp(EAS(&g, "color", 0), "Blue")) {
    return 20;
  }      

  /* Set vector attributes as vector */
  igraph_vector_init(&y, igraph_vcount(&g));
  igraph_vector_fill(&y, 1.23);
  SETVANV(&g, "y", &y);
  igraph_vector_destroy(&y);
  for (i=0; i<igraph_vcount(&g); i++) {    
    if (VAN(&g, "y", i) != 1.23) {
      return 21;
    }
  }
  igraph_vector_init_seq(&y, 0, igraph_vcount(&g)-1);
  SETVANV(&g, "foobar", &y);
  igraph_vector_destroy(&y);
  for (i=0; i<igraph_vcount(&g); i++) {
    if (VAN(&g, "foobar", i) != i) {
      return 22;
    }
  }  
  
  igraph_strvector_init(&id, igraph_vcount(&g));
  for (i=0; i<igraph_vcount(&g); i++) {
    snprintf(str, sizeof(str)-1, "%li", i);
    igraph_strvector_set(&id, i, str);
  }
  SETVASV(&g, "foo", &id);
  igraph_strvector_destroy(&id);
  for (i=0; i<igraph_vcount(&g); i++) {
    printf("%s ", VAS(&g, "foo", i));
  }
  printf("\n");
  igraph_strvector_init(&id, igraph_vcount(&g));
  for (i=0; i<igraph_vcount(&g); i++) {
    snprintf(str, sizeof(str)-1, "%li", i);
    igraph_strvector_set(&id, i, str);
  }
  SETVASV(&g, "id", &id);
  igraph_strvector_destroy(&id);
  for (i=0; i<igraph_vcount(&g); i++) {
    printf("%s ", VAS(&g, "id", i));
  }
  printf("\n");  
  
  /* Set edge attributes as vector */
  igraph_vector_init(&y, igraph_ecount(&g));
  igraph_vector_fill(&y, 12.3);
  SETEANV(&g, "weight", &y);
  igraph_vector_destroy(&y);
  for (i=0; i<igraph_ecount(&g); i++) {    
    if (EAN(&g, "weight", i) != 12.3) {
      return 23;
    }
  }
  igraph_vector_init_seq(&y, 0, igraph_ecount(&g)-1);
  SETEANV(&g, "foobar", &y);
  igraph_vector_destroy(&y);
  for (i=0; i<igraph_ecount(&g); i++) {
    if (VAN(&g, "foobar", i) != i) {
      return 24;
    }
  }  
  
  igraph_strvector_init(&id, igraph_ecount(&g));
  for (i=0; i<igraph_ecount(&g); i++) {
    snprintf(str, sizeof(str)-1, "%li", i);
    igraph_strvector_set(&id, i, str);
  }
  SETEASV(&g, "foo", &id);
  igraph_strvector_destroy(&id);
  for (i=0; i<igraph_ecount(&g); i++) {
    printf("%s ", EAS(&g, "foo", i));
  }
  printf("\n");
  igraph_strvector_init(&id, igraph_ecount(&g));
  for (i=0; i<igraph_ecount(&g); i++) {
    snprintf(str, sizeof(str)-1, "%li", i);
    igraph_strvector_set(&id, i, str);
  }
  SETEASV(&g, "color", &id);
  igraph_strvector_destroy(&id);
  for (i=0; i<igraph_ecount(&g); i++) {
    printf("%s ", EAS(&g, "color", i));
  }
  printf("\n");    

  /* Delete all remaining attributes */
  DELALL(&g);
  igraph_cattribute_list(&g, &gnames, &gtypes, &vnames, &vtypes, &enames, &etypes);
  if (igraph_strvector_size(&gnames) != 0 ||
      igraph_strvector_size(&vnames) != 0 ||
      igraph_strvector_size(&enames) != 0) {
    return 25;
  }

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

  igraph_destroy(&g);

  return 0;
}
Пример #12
0
/**
 * Finding maximum bipartite matchings on bipartite graphs using the
 * Hungarian algorithm (a.k.a. Kuhn-Munkres algorithm).
 *
 * The algorithm uses a maximum cardinality matching on a subset of
 * tight edges as a starting point. This is achieved by
 * \c igraph_i_maximum_bipartite_matching_unweighted on the restricted
 * graph.
 *
 * The algorithm works reliably only if the weights are integers. The
 * \c eps parameter should specity a very small number; if the slack on
 * an edge falls below \c eps, it will be considered tight. If all your
 * weights are integers, you can safely set \c eps to zero.
 */
int igraph_i_maximum_bipartite_matching_weighted(const igraph_t* graph,
    const igraph_vector_bool_t* types, igraph_integer_t* matching_size,
    igraph_real_t* matching_weight, igraph_vector_long_t* matching,
    const igraph_vector_t* weights, igraph_real_t eps) {
  long int i, j, k, n, no_of_nodes, no_of_edges;
  igraph_integer_t u, v, w, msize;
  igraph_t newgraph;
  igraph_vector_long_t match;       /* will store the matching */
  igraph_vector_t slack;            /* will store the slack on each edge */
  igraph_vector_t parent;           /* parent vertices during a BFS */
  igraph_vector_t vec1, vec2;       /* general temporary vectors */
  igraph_vector_t labels;           /* will store the labels */
  igraph_dqueue_long_t q;           /* a FIFO for BST */
  igraph_bool_t smaller_set;        /* denotes which part of the bipartite graph is smaller */
  long int smaller_set_size;        /* size of the smaller set */
  igraph_real_t dual;               /* solution of the dual problem */
  igraph_adjlist_t tight_phantom_edges; /* adjacency list to manage tight phantom edges */
  igraph_integer_t alternating_path_endpoint;
  igraph_vector_t* neis;
  igraph_vector_int_t *neis2;
  igraph_inclist_t inclist;         /* incidence list of the original graph */ 

  /* The Hungarian algorithm is originally for complete bipartite graphs.
   * For non-complete bipartite graphs, a phantom edge of weight zero must be
   * added between every pair of non-connected vertices. We don't do this
   * explicitly of course. See the comments below about how phantom edges
   * are taken into account. */

  no_of_nodes = igraph_vcount(graph);
  no_of_edges = igraph_ecount(graph);
  if (eps < 0) {
    IGRAPH_WARNING("negative epsilon given, clamping to zero");
    eps = 0;
  }

  /* (1) Initialize data structures */
  IGRAPH_CHECK(igraph_vector_long_init(&match, no_of_nodes));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &match);
  IGRAPH_CHECK(igraph_vector_init(&slack, no_of_edges));
  IGRAPH_FINALLY(igraph_vector_destroy, &slack);
  IGRAPH_VECTOR_INIT_FINALLY(&vec1, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&vec2, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&labels, no_of_nodes);
  IGRAPH_CHECK(igraph_dqueue_long_init(&q, 0));
  IGRAPH_FINALLY(igraph_dqueue_long_destroy, &q);
  IGRAPH_VECTOR_INIT_FINALLY(&parent, no_of_nodes);
  IGRAPH_CHECK(igraph_adjlist_init_empty(&tight_phantom_edges, 
					 (igraph_integer_t) no_of_nodes));
  IGRAPH_FINALLY(igraph_adjlist_destroy, &tight_phantom_edges);
  IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, IGRAPH_ALL));
  IGRAPH_FINALLY(igraph_inclist_destroy, &inclist);

  /* (2) Find which set is the smaller one */
  j = 0;
  for (i = 0; i < no_of_nodes; i++) {
    if (VECTOR(*types)[i] == 0)
      j++;
  }
  smaller_set = (j > no_of_nodes / 2);
  smaller_set_size = smaller_set ? (no_of_nodes - j) : j;

  /* (3) Calculate the initial labeling and the set of tight edges. Use the
   *     smaller set only. Here we can assume that there are no phantom edges
   *     among the tight ones. */
  dual = 0;
  for (i = 0; i < no_of_nodes; i++) {
    igraph_real_t max_weight = 0;

    if (VECTOR(*types)[i] != smaller_set) {
      VECTOR(labels)[i] = 0;
      continue;
    }

    neis = igraph_inclist_get(&inclist, i);
    n = igraph_vector_size(neis);
    for (j = 0, k = 0; j < n; j++) {
      if (VECTOR(*weights)[(long int)VECTOR(*neis)[j]] > max_weight) {
        k = (long int) VECTOR(*neis)[j];
        max_weight = VECTOR(*weights)[k];
      }
    }

    VECTOR(labels)[i] = max_weight;
    dual += max_weight;
  }

  igraph_vector_clear(&vec1);
  IGRAPH_CHECK(igraph_get_edgelist(graph, &vec2, 0));
#define IS_TIGHT(i) (VECTOR(slack)[i] <= eps)
  for (i = 0, j = 0; i < no_of_edges; i++, j+=2) {
    u = (igraph_integer_t) VECTOR(vec2)[j];
    v = (igraph_integer_t) VECTOR(vec2)[j+1];
    VECTOR(slack)[i] = VECTOR(labels)[u] + VECTOR(labels)[v] - VECTOR(*weights)[i];
    if (IS_TIGHT(i)) {
      IGRAPH_CHECK(igraph_vector_push_back(&vec1, u));
      IGRAPH_CHECK(igraph_vector_push_back(&vec1, v));
    }
  }
  igraph_vector_clear(&vec2);

  /* (4) Construct a temporary graph on which the initial maximum matching
   *     will be calculated (only on the subset of tight edges) */
  IGRAPH_CHECK(igraph_create(&newgraph, &vec1,
			     (igraph_integer_t) no_of_nodes, 0));
  IGRAPH_FINALLY(igraph_destroy, &newgraph);
  IGRAPH_CHECK(igraph_maximum_bipartite_matching(&newgraph, types, &msize, 0, &match, 0, 0));
  igraph_destroy(&newgraph);
  IGRAPH_FINALLY_CLEAN(1);

  /* (5) Main loop until the matching becomes maximal */
  while (msize < smaller_set_size) {
    igraph_real_t min_slack, min_slack_2;
    igraph_integer_t min_slack_u, min_slack_v;

    /* (7) Fill the push queue with the unmatched nodes from the smaller set. */
    igraph_vector_clear(&vec1);
    igraph_vector_clear(&vec2);
    igraph_vector_fill(&parent, -1);
    for (i = 0; i < no_of_nodes; i++) {
      if (UNMATCHED(i) && VECTOR(*types)[i] == smaller_set) {
        IGRAPH_CHECK(igraph_dqueue_long_push(&q, i));
        VECTOR(parent)[i] = i;
        IGRAPH_CHECK(igraph_vector_push_back(&vec1, i));
      }
    }

#ifdef MATCHING_DEBUG
    debug("Matching:");
    igraph_vector_long_print(&match);
    debug("Unmatched vertices are marked by non-negative numbers:\n");
    igraph_vector_print(&parent);
    debug("Labeling:");
    igraph_vector_print(&labels);
    debug("Slacks:");
    igraph_vector_print(&slack);
#endif

    /* (8) Run the BFS */
    alternating_path_endpoint = -1;
    while (!igraph_dqueue_long_empty(&q)) {
      v = (int) igraph_dqueue_long_pop(&q);

      debug("Considering vertex %ld\n", (long int)v);

      /* v is always in the smaller set. Find the neighbors of v, which
       * are all in the larger set. Find the pairs of these nodes in
       * the smaller set and push them to the queue. Mark the traversed
       * nodes as seen.
       *
       * Here we have to be careful as there are two types of incident
       * edges on v: real edges and phantom ones. Real edges are
       * given by igraph_inclist_get. Phantom edges are not given so we
       * (ab)use an adjacency list data structure that lists the
       * vertices connected to v by phantom edges only. */
      neis = igraph_inclist_get(&inclist, v);
      n = igraph_vector_size(neis);
      for (i = 0; i < n; i++) {
        j = (long int) VECTOR(*neis)[i];
        /* We only care about tight edges */
        if (!IS_TIGHT(j))
          continue;
        /* Have we seen the other endpoint already? */
        u = IGRAPH_OTHER(graph, j, v);
        if (VECTOR(parent)[u] >= 0)
          continue;
        debug("  Reached vertex %ld via edge %ld\n", (long)u, (long)j);
        VECTOR(parent)[u] = v;
        IGRAPH_CHECK(igraph_vector_push_back(&vec2, u));
        w = (int) VECTOR(match)[u];
        if (w == -1) {
          /* u is unmatched and it is in the larger set. Therefore, we
           * could improve the matching by following the parents back
           * from u to the root.
           */
          alternating_path_endpoint = u;
          break;  /* since we don't need any more endpoints that come from v */
        } else {
          IGRAPH_CHECK(igraph_dqueue_long_push(&q, w));
          VECTOR(parent)[w] = u;
        }
        IGRAPH_CHECK(igraph_vector_push_back(&vec1, w));
      }

      /* Now do the same with the phantom edges */
      neis2 = igraph_adjlist_get(&tight_phantom_edges, v);
      n = igraph_vector_int_size(neis2);
      for (i = 0; i < n; i++) {
        u = (igraph_integer_t) VECTOR(*neis2)[i];
        /* Have we seen u already? */
        if (VECTOR(parent)[u] >= 0)
          continue;
        /* Check if the edge is really tight; it might have happened that the
         * edge became non-tight in the meanwhile. We do not remove these from
         * tight_phantom_edges at the moment, so we check them once again here.
         */
        if (fabs(VECTOR(labels)[(long int)v] + VECTOR(labels)[(long int)u]) > eps)
          continue;
        debug("  Reached vertex %ld via tight phantom edge\n", (long)u);
        VECTOR(parent)[u] = v;
        IGRAPH_CHECK(igraph_vector_push_back(&vec2, u));
        w = (int) VECTOR(match)[u];
        if (w == -1) {
          /* u is unmatched and it is in the larger set. Therefore, we
           * could improve the matching by following the parents back
           * from u to the root.
           */
          alternating_path_endpoint = u;
          break;  /* since we don't need any more endpoints that come from v */
        } else {
          IGRAPH_CHECK(igraph_dqueue_long_push(&q, w));
          VECTOR(parent)[w] = u;
        }
        IGRAPH_CHECK(igraph_vector_push_back(&vec1, w));
      }
    }

    /* Okay; did we have an alternating path? */
    if (alternating_path_endpoint != -1) {
#ifdef MATCHING_DEBUG
      debug("BFS parent tree:");
      igraph_vector_print(&parent);
#endif
      /* Increase the size of the matching with the alternating path. */
      v = alternating_path_endpoint;
      u = (igraph_integer_t) VECTOR(parent)[v];
      debug("Extending matching with alternating path ending in %ld.\n", (long int)v);

      while (u != v) {
        w = (int) VECTOR(match)[v];
        if (w != -1)
          VECTOR(match)[w] = -1;
        VECTOR(match)[v] = u;

        VECTOR(match)[v] = u;
        w = (int) VECTOR(match)[u];
        if (w != -1)
          VECTOR(match)[w] = -1;
        VECTOR(match)[u] = v;

        v = (igraph_integer_t) VECTOR(parent)[u];
	u = (igraph_integer_t) VECTOR(parent)[v];
      }

      msize++;

#ifdef MATCHING_DEBUG
      debug("New matching after update:");
      igraph_vector_long_print(&match);
      debug("Matching size is now: %ld\n", (long)msize);
#endif
      continue;
    }

#ifdef MATCHING_DEBUG
    debug("Vertices reachable from unmatched ones via tight edges:\n");
    igraph_vector_print(&vec1);
    igraph_vector_print(&vec2);
#endif

    /* At this point, vec1 contains the nodes in the smaller set (A)
     * reachable from unmatched nodes in A via tight edges only, while vec2
     * contains the nodes in the larger set (B) reachable from unmatched
     * nodes in A via tight edges only. Also, parent[i] >= 0 if node i
     * is reachable */

    /* Check the edges between reachable nodes in A and unreachable
     * nodes in B, and find the minimum slack on them.
     *
     * Since the weights are positive, we do no harm if we first
     * assume that there are no "real" edges between the two sets
     * mentioned above and determine an upper bound for min_slack
     * based on this. */
    min_slack = IGRAPH_INFINITY;
    min_slack_u = min_slack_v = 0;
    n = igraph_vector_size(&vec1);
    for (i = 0; i < no_of_nodes; i++) {
      if (VECTOR(*types)[i] == smaller_set)
        continue;
      if (VECTOR(labels)[i] < min_slack) {
        min_slack = VECTOR(labels)[i];
        min_slack_v = (igraph_integer_t) i;
      }
    }
    min_slack_2 = IGRAPH_INFINITY;
    for (i = 0; i < n; i++) {
      u = (igraph_integer_t) VECTOR(vec1)[i];
      /* u is surely from the smaller set, but we are interested in it
       * only if it is reachable from an unmatched vertex */
      if (VECTOR(parent)[u] < 0)
        continue;
      if (VECTOR(labels)[u] < min_slack_2) {
        min_slack_2 = VECTOR(labels)[u];
        min_slack_u = u;
      }
    }
    min_slack += min_slack_2;
    debug("Starting approximation for min_slack = %.4f (based on vertex pair %ld--%ld)\n",
        min_slack, (long int)min_slack_u, (long int)min_slack_v);

    n = igraph_vector_size(&vec1);
    for (i = 0; i < n; i++) {
      u = (igraph_integer_t) VECTOR(vec1)[i];
      /* u is a reachable node in A; get its incident edges.
       *
       * There are two types of incident edges: 1) real edges,
       * 2) phantom edges. Phantom edges were treated earlier
       * when we determined the initial value for min_slack. */
      debug("Trying to expand along vertex %ld\n", (long int)u);
      neis = igraph_inclist_get(&inclist, u);
      k = igraph_vector_size(neis);
      for (j = 0; j < k; j++) {
        /* v is the vertex sitting at the other end of an edge incident
         * on u; check whether it was reached */
        v = IGRAPH_OTHER(graph, VECTOR(*neis)[j], u);
        debug("  Edge %ld -- %ld (ID=%ld)\n", (long int)u, (long int)v, (long int)VECTOR(*neis)[j]);
        if (VECTOR(parent)[v] >= 0) {
          /* v was reached, so we are not interested in it */
          debug("    %ld was reached, so we are not interested in it\n", (long int)v);
          continue;
        }
        /* v is the ID of the edge from now on */
        v = (igraph_integer_t) VECTOR(*neis)[j];
        if (VECTOR(slack)[v] < min_slack) {
          min_slack = VECTOR(slack)[v];
          min_slack_u = u;
          min_slack_v = IGRAPH_OTHER(graph, v, u);
        }
        debug("    Slack of this edge: %.4f, min slack is now: %.4f\n",
            VECTOR(slack)[v], min_slack);
      }
    }
    debug("Minimum slack: %.4f on edge %d--%d\n", min_slack, (int)min_slack_u, (int)min_slack_v);

    if (min_slack > 0) {
      /* Decrease the label of reachable nodes in A by min_slack.
       * Also update the dual solution */
      n = igraph_vector_size(&vec1);
      for (i = 0; i < n; i++) {
        u = (igraph_integer_t) VECTOR(vec1)[i];
        VECTOR(labels)[u] -= min_slack;
        neis = igraph_inclist_get(&inclist, u);
        k = igraph_vector_size(neis);
        for (j = 0; j < k; j++) {
          debug("  Decreasing slack of edge %ld (%ld--%ld) by %.4f\n",
              (long)VECTOR(*neis)[j], (long)u,
              (long)IGRAPH_OTHER(graph, VECTOR(*neis)[j], u), min_slack);
          VECTOR(slack)[(long int)VECTOR(*neis)[j]] -= min_slack;
        }
        dual -= min_slack;
      }

      /* Increase the label of reachable nodes in B by min_slack.
       * Also update the dual solution */
      n = igraph_vector_size(&vec2);
      for (i = 0; i < n; i++) {
        u = (igraph_integer_t) VECTOR(vec2)[i];
        VECTOR(labels)[u] += min_slack;
        neis = igraph_inclist_get(&inclist, u);
        k = igraph_vector_size(neis);
        for (j = 0; j < k; j++) {
          debug("  Increasing slack of edge %ld (%ld--%ld) by %.4f\n",
              (long)VECTOR(*neis)[j], (long)u,
              (long)IGRAPH_OTHER(graph, (long)VECTOR(*neis)[j], u), min_slack);
          VECTOR(slack)[(long int)VECTOR(*neis)[j]] += min_slack;
        }
        dual += min_slack;
      }
    }

    /* Update the set of tight phantom edges.
     * Note that we must do it even if min_slack is zero; the reason is that
     * it can happen that min_slack is zero in the first step if there are
     * isolated nodes in the input graph.
     *
     * TODO: this is O(n^2) here. Can we do it faster? */
    for (u = 0; u < no_of_nodes; u++) {
      if (VECTOR(*types)[u] != smaller_set)
        continue;

      for (v = 0; v < no_of_nodes; v++) {
        if (VECTOR(*types)[v] == smaller_set)
          continue;

        if (VECTOR(labels)[(long int)u] + VECTOR(labels)[(long int)v] <= eps) {
          /* Tight phantom edge found. Note that we don't have to check whether
           * u and v are connected; if they were, then the slack of this edge
           * would be negative. */
          neis2 = igraph_adjlist_get(&tight_phantom_edges, u);
          if (!igraph_vector_int_binsearch(neis2, v, &i)) {
            debug("New tight phantom edge: %ld -- %ld\n", (long)u, (long)v);
            IGRAPH_CHECK(igraph_vector_int_insert(neis2, i, v));
          }
        }
      }
    }

#ifdef MATCHING_DEBUG
    debug("New labels:");
    igraph_vector_print(&labels);
    debug("Slacks after updating with min_slack:");
    igraph_vector_print(&slack);
#endif
  }

  /* Cleanup: remove phantom edges from the matching */
  for (i = 0; i < no_of_nodes; i++) {
    if (VECTOR(*types)[i] != smaller_set)
      continue;

    if (VECTOR(match)[i] != -1) {
      j = VECTOR(match)[i];
      neis2 = igraph_adjlist_get(&tight_phantom_edges, i);
      if (igraph_vector_int_binsearch(neis2, j, 0)) {
        VECTOR(match)[i] = VECTOR(match)[j] = -1;
        msize--;
      }
    }
  }

  /* Fill the output parameters */
  if (matching != 0) {
    IGRAPH_CHECK(igraph_vector_long_update(matching, &match));
  }
  if (matching_size != 0) {
    *matching_size = msize;
  }
  if (matching_weight != 0) {
    *matching_weight = 0;
    for (i = 0; i < no_of_edges; i++) {
      if (IS_TIGHT(i)) {
        IGRAPH_CHECK(igraph_edge(graph, (igraph_integer_t) i, &u, &v));
        if (VECTOR(match)[u] == v)
          *matching_weight += VECTOR(*weights)[i];
      }
    }
  }

  /* Release everything */
#undef IS_TIGHT
  igraph_inclist_destroy(&inclist);
  igraph_adjlist_destroy(&tight_phantom_edges);
  igraph_vector_destroy(&parent);
  igraph_dqueue_long_destroy(&q);
  igraph_vector_destroy(&labels);
  igraph_vector_destroy(&vec1);
  igraph_vector_destroy(&vec2);
  igraph_vector_destroy(&slack);
  igraph_vector_long_destroy(&match);
  IGRAPH_FINALLY_CLEAN(9);

  return IGRAPH_SUCCESS;
}