示例#1
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;
}
示例#2
0
int igraph_2dgrid_neighbors(igraph_2dgrid_t *grid, igraph_vector_t *eids,
                            igraph_integer_t vid, igraph_real_t r) {
    igraph_real_t xc=MATRIX(*grid->coords, (long int)vid, 0);
    igraph_real_t yc=MATRIX(*grid->coords, (long int)vid, 1);
    long int x, y;
    igraph_vector_clear(eids);

    igraph_2dgrid_which(grid, xc, yc, &x, &y);

    /* this cell */
    igraph_i_2dgrid_addvertices(grid, eids, vid, r, x, y);

    /* left */
    if (x!=0) {
        igraph_i_2dgrid_addvertices(grid, eids, vid, r, x-1, y);
    }
    /* right */
    if (x!=grid->stepsx-1) {
        igraph_i_2dgrid_addvertices(grid, eids, vid, r, x+1, y);
    }
    /* up */
    if (y!=0) {
        igraph_i_2dgrid_addvertices(grid, eids, vid, r, x, y-1);
    }
    /* down */
    if (y!=grid->stepsy-1) {
        igraph_i_2dgrid_addvertices(grid, eids, vid, r, x, y+1);
    }
    /* up & left */
    if (x != 0 && y != 0) {
        igraph_i_2dgrid_addvertices(grid, eids, vid, r, x-1, y-1);
    }
    /* up & right */
    if (x != grid->stepsx-1 && y != 0) {
        igraph_i_2dgrid_addvertices(grid, eids, vid, r, x+1, y-1);
    }
    /* down & left */
    if (x != 0 && y != grid->stepsy-1) {
        igraph_i_2dgrid_addvertices(grid, eids, vid, r, x-1, y+1);
    }
    /* down & right */
    if (x != grid->stepsx-1 && y != grid->stepsy-1) {
        igraph_i_2dgrid_addvertices(grid, eids, vid, r, x-1, y+1);
    }

    return 0;
}
示例#3
0
文件: vector.c 项目: pombredanne/RCA
int igraph_vector_order2(igraph_vector_t *v) {

  igraph_indheap_t heap;
  
  igraph_indheap_init_array(&heap, VECTOR(*v), igraph_vector_size(v));
  IGRAPH_FINALLY(igraph_indheap_destroy, &heap);

  igraph_vector_clear(v);
  while (!igraph_indheap_empty(&heap)) {
    IGRAPH_CHECK(igraph_vector_push_back(v, igraph_indheap_max_index(&heap)-1));
    igraph_indheap_delete_max(&heap);
  }
  
  igraph_indheap_destroy(&heap);
  IGRAPH_FINALLY_CLEAN(1);
  return 0;
}
示例#4
0
int igraph_bridges(const igraph_t *graph, igraph_vector_t *bridges) {
    igraph_inclist_t il;
    igraph_vector_bool_t visited;
    igraph_vector_int_t disc, low;
    igraph_vector_int_t parent;
    long n;
    long i;
    igraph_integer_t time;

    n = igraph_vcount(graph);

    IGRAPH_CHECK(igraph_inclist_init(graph, &il, IGRAPH_ALL));
    IGRAPH_FINALLY(igraph_inclist_destroy, &il);

    IGRAPH_CHECK(igraph_vector_bool_init(&visited, n));
    IGRAPH_FINALLY(igraph_vector_bool_destroy, &visited);

    IGRAPH_CHECK(igraph_vector_int_init(&disc, n));
    IGRAPH_FINALLY(igraph_vector_int_destroy, &disc);

    IGRAPH_CHECK(igraph_vector_int_init(&low, n));
    IGRAPH_FINALLY(igraph_vector_int_destroy, &low);

    IGRAPH_CHECK(igraph_vector_int_init(&parent, n));
    IGRAPH_FINALLY(igraph_vector_int_destroy, &parent);
    for (i=0; i < n; ++i)
        VECTOR(parent)[i] = -1;

    igraph_vector_clear(bridges);

    time = 0;
    for (i=0; i < n; ++i)
        if (! VECTOR(visited)[i])
            IGRAPH_CHECK(igraph_i_bridges_rec(graph, &il, i, &time, bridges, &visited, &disc, &low, &parent));

    igraph_vector_int_destroy(&parent);
    igraph_vector_int_destroy(&low);
    igraph_vector_int_destroy(&disc);
    igraph_vector_bool_destroy(&visited);
    igraph_inclist_destroy(&il);
    IGRAPH_FINALLY_CLEAN(5);

    return IGRAPH_SUCCESS;
}
示例#5
0
int igraph_i_clusters_leaveout(const igraph_adjlist_t *adjlist, 
			       igraph_vector_t *components, 
			       igraph_vector_t *leaveout, 
			       unsigned long int *mark,
			       igraph_dqueue_t *Q) {

  /* Another trick: we use the same 'leaveout' vector to mark the
   * vertices that were already found in the BFS 
   */

  long int i, no_of_nodes=igraph_adjlist_size(adjlist);
  
  igraph_dqueue_clear(Q);
  igraph_vector_clear(components);

  for (i=0; i<no_of_nodes; i++) {

    if (VECTOR(*leaveout)[i] == *mark) continue;

    VECTOR(*leaveout)[i]= *mark;
    igraph_dqueue_push(Q, i);
    igraph_vector_push_back(components, i);
    
    while (!igraph_dqueue_empty(Q)) {
      long int act_node=(long int) igraph_dqueue_pop(Q);
      igraph_vector_int_t *neis=igraph_adjlist_get(adjlist, act_node);
      long int j, n=igraph_vector_int_size(neis);
      for (j=0; j<n; j++) {
	long int nei=(long int) VECTOR(*neis)[j];
	if (VECTOR(*leaveout)[nei]== *mark) continue;
	IGRAPH_CHECK(igraph_dqueue_push(Q, nei));
	VECTOR(*leaveout)[nei]= *mark;
	igraph_vector_push_back(components, nei);
      }
    }
    
    igraph_vector_push_back(components, -1);
  }
  
  UPDATEMARK();
  
  return 0;
}
示例#6
0
int igraph_i_cliquer_histogram(const igraph_t *graph, igraph_vector_t *hist,
                        igraph_integer_t min_size, igraph_integer_t max_size)
{
    graph_t *g;
    int i;
    igraph_integer_t vcount = igraph_vcount(graph);

    if (vcount == 0) {
        igraph_vector_clear(hist);
        return IGRAPH_SUCCESS;
    }

    if (min_size <= 0) min_size = 1;
    if (max_size <= 0) max_size = vcount; /* also used for initial hist vector size, do not set to zero */

    if (max_size < min_size)
        IGRAPH_ERROR("max_size must not be smaller than min_size", IGRAPH_EINVAL);

    igraph_to_cliquer(graph, &g);
    IGRAPH_FINALLY(graph_free, g);

    igraph_vector_resize(hist, max_size);
    igraph_vector_null(hist);
    igraph_cliquer_opt.user_data = hist;
    igraph_cliquer_opt.user_function = &count_cliques_callback;

    CLIQUER_INTERRUPTABLE(clique_unweighted_find_all(g, min_size, max_size, /* maximal= */ FALSE, &igraph_cliquer_opt));

    for (i=max_size; i > 0; --i)
        if (VECTOR(*hist)[i-1] > 0)
            break;
    igraph_vector_resize(hist, i);
    igraph_vector_resize_min(hist);

    graph_free(g);
    IGRAPH_FINALLY_CLEAN(1);

    return IGRAPH_SUCCESS;
}
示例#7
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;
}
示例#8
0
int igraph_random_sample(igraph_vector_t *res, igraph_integer_t l, igraph_integer_t h, 
			 igraph_integer_t length) {
  igraph_real_t N=h-l+1;
  igraph_real_t n=length;
  int retval;

  igraph_real_t nreal=length;
  igraph_real_t ninv=1.0/nreal;
  igraph_real_t Nreal=N;
  igraph_real_t Vprime;
  igraph_real_t qu1=-n+1+N;
  igraph_real_t qu1real=-nreal+1.0+Nreal;
  igraph_real_t negalphainv=-13;
  igraph_real_t threshold=-negalphainv*n;
  igraph_real_t S;
  
  igraph_vector_clear(res);
  IGRAPH_CHECK(igraph_vector_reserve(res, length));  

  RNG_BEGIN();
  
  Vprime=exp(log(RNG_UNIF01())*ninv);

  while (n>1 && threshold < N) {
    igraph_real_t X, U;
    igraph_real_t limit, t;
    igraph_real_t negSreal, y1, y2, top, bottom;
    igraph_real_t nmin1inv=1.0/(-1.0+nreal);
    while (1) {
      while(1) {
	X=Nreal*(-Vprime+1.0);
	S=floor(X);
	if (S==0) { S=1; }
	if (S <qu1) { break; }
	Vprime = exp(log(RNG_UNIF01())*ninv);
      }
      U=RNG_UNIF01();
      negSreal=-S;
      
      y1=exp(log(U*Nreal/qu1real)*nmin1inv);
      Vprime=y1*(-X/Nreal+1.0)*(qu1real/(negSreal+qu1real));
      if (Vprime <= 1.0) { break; }
      
      y2=1.0;
      top=-1.0+Nreal;
      if (-1+n > S) {
	bottom=-nreal+Nreal; 
	limit=-S+N;
      } else {
	bottom=-1.0+negSreal+Nreal;
	limit=qu1;
      }
      for (t=-1+N; t>=limit; t--) {
	y2=(y2*top)/bottom;
	top=-1.0+top;
	bottom=-1.0+bottom;
      }
      if (Nreal/(-X+Nreal) >= y1*exp(log(y2)*nmin1inv)) {
	Vprime=exp(log(RNG_UNIF01())*nmin1inv);
	break;
      }
      Vprime=exp(log(RNG_UNIF01())*ninv);
    }
        
    l+=S;
    igraph_vector_push_back(res, l);	/* allocated */
    N=-S+(-1+N);   Nreal=negSreal+(-1.0+Nreal);
    n=-1+n;   nreal=-1.0+nreal; ninv=nmin1inv;
    qu1=-S+qu1; qu1real=negSreal+qu1real;
    threshold=threshold+negalphainv;
  }
  
  if (n>1) {
    retval=igraph_random_sample_alga(res, l, h, n);
  } else {
    retval=0;
    S=floor(N*Vprime);
    l+=S;
    igraph_vector_push_back(res, l);	/* allocated */
  }

  RNG_END();
  
  return retval;
}
示例#9
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;
}
示例#10
0
int igraph_decompose(const igraph_t *graph, igraph_vector_ptr_t *components, 
		     igraph_connectedness_t mode,
		     long int maxcompno, long int minelements) {

  long int actstart;
  long int no_of_nodes=igraph_vcount(graph);
  long int resco=0;		/* number of graphs created so far */ 
  char *already_added;
  igraph_dqueue_t q;
  igraph_vector_t verts;
  igraph_vector_t neis;
  long int i;
  igraph_t *newg;

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

  if (mode != IGRAPH_WEAK) {
    IGRAPH_ERROR("only 'IGRAPH_WEAK' is implemented", IGRAPH_EINVAL);
  }

  if (maxcompno<0) {
    maxcompno=LONG_MAX;
  }

  igraph_vector_ptr_clear(components);
  IGRAPH_FINALLY(igraph_decompose_destroy, components);

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

  IGRAPH_CHECK(igraph_dqueue_init(&q, 100));
  IGRAPH_FINALLY(igraph_dqueue_destroy, &q);
  IGRAPH_VECTOR_INIT_FINALLY(&verts, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
  
  for(actstart=0; resco<maxcompno && actstart < no_of_nodes; actstart++) {
    
    if (already_added[actstart]) { continue; }
    IGRAPH_ALLOW_INTERRUPTION();
    
    igraph_vector_clear(&verts);
    already_added[actstart]=1;
    IGRAPH_CHECK(igraph_vector_push_back(&verts, actstart));
    IGRAPH_CHECK(igraph_dqueue_push(&q, actstart));
    
    while (!igraph_dqueue_empty(&q) ) {
      long int actvert=(long int) igraph_dqueue_pop(&q);
      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) actvert,
				    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));
	IGRAPH_CHECK(igraph_vector_push_back(&verts, neighbor));
	already_added[neighbor]=1;
      }
    }
    
    /* ok, we have a component */
    if (igraph_vector_size(&verts)<minelements) { continue; }

    newg=igraph_Calloc(1, igraph_t);
    if (newg==0) {
      IGRAPH_ERROR("Cannot decompose graph", IGRAPH_ENOMEM);
    }
    IGRAPH_CHECK(igraph_vector_ptr_push_back(components, newg));
    IGRAPH_CHECK(igraph_induced_subgraph(graph, newg, 
					 igraph_vss_vector(&verts), 
					 IGRAPH_SUBGRAPH_AUTO));
    resco++;
    
  } /* for actstart++ */

  igraph_vector_destroy(&neis);
  igraph_vector_destroy(&verts);
  igraph_dqueue_destroy(&q);
  igraph_free(already_added);
  IGRAPH_FINALLY_CLEAN(5);	/* + components */
  
  return 0;
}
示例#11
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;
}
示例#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;
}
示例#13
0
/**
 * \function igraph_adjlist_clear
 * Removes all edges from an adjacency list.
 *
 * \param al The 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_adjlist_clear(igraph_adjlist_t *al) {
  long int i;
  for (i=0; i<al->length; i++) {
    igraph_vector_clear(&al->adjs[i]);
  }
}
示例#14
0
int igraph_clusters_strong(const igraph_t *graph, igraph_vector_t *membership,
			   igraph_vector_t *csize, igraph_integer_t *no) {

  long int no_of_nodes=igraph_vcount(graph);
  igraph_vector_t next_nei=IGRAPH_VECTOR_NULL;
  
  long int i, n, num_seen;
  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
  
  long int no_of_clusters=1;
  long int act_cluster_size;

  igraph_vector_t out=IGRAPH_VECTOR_NULL;
  const igraph_vector_int_t* tmp;

  igraph_adjlist_t adjlist;

  /* The result */

  IGRAPH_VECTOR_INIT_FINALLY(&next_nei, no_of_nodes);
  IGRAPH_VECTOR_INIT_FINALLY(&out, 0);
  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);

  if (membership) {
    IGRAPH_CHECK(igraph_vector_resize(membership, no_of_nodes));
  }
  IGRAPH_CHECK(igraph_vector_reserve(&out, no_of_nodes));

  igraph_vector_null(&out);
  if (csize) {
    igraph_vector_clear(csize);
  }

  IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_OUT));
  IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);

  num_seen = 0;
  for (i=0; i<no_of_nodes; i++) {
    IGRAPH_ALLOW_INTERRUPTION();

    tmp = igraph_adjlist_get(&adjlist, i);
    if (VECTOR(next_nei)[i] > igraph_vector_int_size(tmp)) {
      continue;
    }
    
    IGRAPH_CHECK(igraph_dqueue_push(&q, i));
    while (!igraph_dqueue_empty(&q)) {
      long int act_node=(long int) igraph_dqueue_back(&q);
      tmp = igraph_adjlist_get(&adjlist, act_node);
      if (VECTOR(next_nei)[act_node]==0) {
	/* this is the first time we've met this vertex */
	VECTOR(next_nei)[act_node]++;
      } else if (VECTOR(next_nei)[act_node] <= igraph_vector_int_size(tmp)) {
	/* we've already met this vertex but it has more children */
	long int neighbor=(long int) VECTOR(*tmp)[(long int)
						  VECTOR(next_nei)[act_node]-1];
	if (VECTOR(next_nei)[neighbor] == 0) {
	  IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
	}
	VECTOR(next_nei)[act_node]++;
      } else {
	/* we've met this vertex and it has no more children */
	IGRAPH_CHECK(igraph_vector_push_back(&out, act_node));
	igraph_dqueue_pop_back(&q);
	num_seen++;

	if (num_seen % 10000 == 0) {
	  /* time to report progress and allow the user to interrupt */
	  IGRAPH_PROGRESS("Strongly connected components: ",
	      num_seen * 50.0 / no_of_nodes, NULL);
	  IGRAPH_ALLOW_INTERRUPTION();
	}
      }
    } /* while q */
  }  /* for */

  IGRAPH_PROGRESS("Strongly connected components: ", 50.0, NULL);

  igraph_adjlist_destroy(&adjlist);
  IGRAPH_FINALLY_CLEAN(1);

  IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_IN));
  IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);

  /* OK, we've the 'out' values for the nodes, let's use them in
     decreasing order with the help of a heap */

  igraph_vector_null(&next_nei);             /* mark already added vertices */
  num_seen = 0;

  while (!igraph_vector_empty(&out)) {
    long int grandfather=(long int) igraph_vector_pop_back(&out);

    if (VECTOR(next_nei)[grandfather] != 0) { continue; }
    VECTOR(next_nei)[grandfather]=1;
    act_cluster_size=1;
    if (membership) {
      VECTOR(*membership)[grandfather]=no_of_clusters-1;
    }
    IGRAPH_CHECK(igraph_dqueue_push(&q, grandfather));
    
    num_seen++;
    if (num_seen % 10000 == 0) {
      /* time to report progress and allow the user to interrupt */
      IGRAPH_PROGRESS("Strongly connected components: ",
	  50.0 + num_seen * 50.0 / no_of_nodes, NULL);
      IGRAPH_ALLOW_INTERRUPTION();
    }

    while (!igraph_dqueue_empty(&q)) {
      long int act_node=(long int) igraph_dqueue_pop_back(&q);
      tmp = igraph_adjlist_get(&adjlist, act_node);
      n = igraph_vector_int_size(tmp);
      for (i=0; i<n; i++) {
	long int neighbor=(long int) VECTOR(*tmp)[i];
	if (VECTOR(next_nei)[neighbor] != 0) { continue; }
	IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
	VECTOR(next_nei)[neighbor]=1;
	act_cluster_size++;
	if (membership) {
	  VECTOR(*membership)[neighbor]=no_of_clusters-1;
	}

	num_seen++;
	if (num_seen % 10000 == 0) {
	  /* time to report progress and allow the user to interrupt */
	  IGRAPH_PROGRESS("Strongly connected components: ",
	      50.0 + num_seen * 50.0 / no_of_nodes, NULL);
	  IGRAPH_ALLOW_INTERRUPTION();
	}
      }
    }

    no_of_clusters++;
    if (csize) {
      IGRAPH_CHECK(igraph_vector_push_back(csize, act_cluster_size));
    }
  }
  
  IGRAPH_PROGRESS("Strongly connected components: ", 100.0, NULL);

  if (no) { *no=(igraph_integer_t) no_of_clusters-1; }

  /* Clean up, return */

  igraph_adjlist_destroy(&adjlist);
  igraph_vector_destroy(&out);
  igraph_dqueue_destroy(&q);
  igraph_vector_destroy(&next_nei);
  IGRAPH_FINALLY_CLEAN(4);

  return 0;
}
示例#15
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;
}
示例#16
0
int igraph_biconnected_components(const igraph_t *graph,
                                  igraph_integer_t *no,
                                  igraph_vector_ptr_t *components,
                                  igraph_vector_t *articulation_points) {

    long int no_of_nodes=igraph_vcount(graph);
    igraph_vector_long_t nextptr;
    igraph_vector_long_t num, low;
    igraph_vector_bool_t found;
    igraph_vector_t *adjedges;
    igraph_stack_t path;
    igraph_vector_t edgestack;
    igraph_adjedgelist_t adjedgelist;
    long int i, counter, rootdfs=0;

    IGRAPH_CHECK(igraph_vector_long_init(&nextptr, no_of_nodes));
    IGRAPH_FINALLY(igraph_vector_long_destroy, &nextptr);
    IGRAPH_CHECK(igraph_vector_long_init(&num, no_of_nodes));
    IGRAPH_FINALLY(igraph_vector_long_destroy, &num);
    IGRAPH_CHECK(igraph_vector_long_init(&low, no_of_nodes));
    IGRAPH_FINALLY(igraph_vector_long_destroy, &low);
    IGRAPH_CHECK(igraph_vector_bool_init(&found, no_of_nodes));
    IGRAPH_FINALLY(igraph_vector_bool_destroy, &found);

    IGRAPH_CHECK(igraph_stack_init(&path, 100));
    IGRAPH_FINALLY(igraph_stack_destroy, &path);
    IGRAPH_VECTOR_INIT_FINALLY(&edgestack, 0);
    IGRAPH_CHECK(igraph_vector_reserve(&edgestack, 100));

    IGRAPH_CHECK(igraph_adjedgelist_init(graph, &adjedgelist, IGRAPH_ALL));
    IGRAPH_FINALLY(igraph_adjedgelist_destroy, &adjedgelist);

    if (no) {
        *no=0;
    }
    if (components) {
        igraph_vector_ptr_clear(components);
    }
    if (articulation_points) {
        igraph_vector_clear(articulation_points);
    }

    for (i=0; i<no_of_nodes; i++) {

        if (VECTOR(low)[i] != 0) {
            continue;    /* already visited */
        }

        IGRAPH_ALLOW_INTERRUPTION();

        IGRAPH_CHECK(igraph_stack_push(&path, i));
        counter=1;
        rootdfs=0;
        VECTOR(low)[i]=VECTOR(num)[i]=counter++;
        while (!igraph_stack_empty(&path)) {
            long int n;
            long int act=igraph_stack_top(&path);
            long int actnext=VECTOR(nextptr)[act];

            adjedges=igraph_adjedgelist_get(&adjedgelist, act);
            n=igraph_vector_size(adjedges);
            if (actnext < n) {
                /* Step down (maybe) */
                long int edge=VECTOR(*adjedges)[actnext];
                long int nei=IGRAPH_OTHER(graph, edge, act);
                if (VECTOR(low)[nei] == 0) {
                    if (act==i) {
                        rootdfs++;
                    }
                    IGRAPH_CHECK(igraph_vector_push_back(&edgestack, edge));
                    IGRAPH_CHECK(igraph_stack_push(&path, nei));
                    VECTOR(low)[nei] = VECTOR(num)[nei]=counter++;
                } else {
                    /* Update low value if needed */
                    if (VECTOR(num)[nei] < VECTOR(low)[act]) {
                        VECTOR(low)[act]=VECTOR(num)[nei];
                    }
                }
                VECTOR(nextptr)[act] += 1;
            } else {
                /* Step up */
                igraph_stack_pop(&path);
                if (!igraph_stack_empty(&path)) {
                    long int prev=igraph_stack_top(&path);
                    /* Update LOW value if needed */
                    if (VECTOR(low)[act] < VECTOR(low)[prev]) {
                        VECTOR(low)[prev] = VECTOR(low)[act];
                    }
                    /* Check for articulation point */
                    if (VECTOR(low)[act] >= VECTOR(num)[prev]) {
                        if (articulation_points && !VECTOR(found)[prev]
                                && prev != i /* the root */) {
                            IGRAPH_CHECK(igraph_vector_push_back(articulation_points, prev));
                            VECTOR(found)[prev] = 1;
                        }
                        if (no) {
                            *no += 1;
                        }
                        if (components) {
                            igraph_vector_t *v=igraph_Calloc(1, igraph_vector_t);
                            IGRAPH_CHECK(igraph_vector_init(v, 0));
                            while (!igraph_vector_empty(&edgestack)) {
                                long int e=igraph_vector_pop_back(&edgestack);
                                IGRAPH_CHECK(igraph_vector_push_back(v, e));
                                if (IGRAPH_FROM(graph,e)==prev || IGRAPH_TO(graph,e)==prev) {
                                    break;
                                }
                            }
                            IGRAPH_CHECK(igraph_vector_ptr_push_back(components, v));
                        }
                    }
                } /* !igraph_stack_empty(&path) */
            }

        } /* !igraph_stack_empty(&path) */

        if (articulation_points && rootdfs >= 2) {
            IGRAPH_CHECK(igraph_vector_push_back(articulation_points, i));
        }

    } /* i < no_of_nodes */

    igraph_adjedgelist_destroy(&adjedgelist);
    igraph_vector_destroy(&edgestack);
    igraph_stack_destroy(&path);
    igraph_vector_bool_destroy(&found);
    igraph_vector_long_destroy(&low);
    igraph_vector_long_destroy(&num);
    igraph_vector_long_destroy(&nextptr);
    IGRAPH_FINALLY_CLEAN(7);

    return 0;
}
示例#17
0
/**
 * Given a graph, a community structure and a vertex ID, this method
 * calculates:
 *
 * - edges: the list of edge IDs that are incident on the vertex
 * - weight_all: the total weight of these edges
 * - weight_inside: the total weight of edges that stay within the same
 *   community where the given vertex is right now, excluding loop edges
 * - weight_loop: the total weight of loop edges
 * - links_community and links_weight: together these two vectors list the
 *   communities incident on this vertex and the total weight of edges
 *   pointing to these communities
 */
int igraph_i_multilevel_community_links(const igraph_t *graph,
  const igraph_i_multilevel_community_list *communities,
  igraph_integer_t vertex, igraph_vector_t *edges,
  igraph_real_t *weight_all, igraph_real_t *weight_inside, igraph_real_t *weight_loop,
  igraph_vector_t *links_community, igraph_vector_t *links_weight) {
  
  long int i, n, last = -1, c = -1;
  igraph_real_t weight = 1;
  long int to, to_community;
  long int community = (long int) VECTOR(*(communities->membership))[(long int)vertex];
  igraph_i_multilevel_community_link *links;

  *weight_all = *weight_inside = *weight_loop = 0;

  igraph_vector_clear(links_community);
  igraph_vector_clear(links_weight);

  /* Get the list of incident edges */
  igraph_incident(graph, edges, vertex, IGRAPH_ALL);

  n = igraph_vector_size(edges);
  links = igraph_Calloc(n, igraph_i_multilevel_community_link);
  if (links == 0) {
    IGRAPH_ERROR("multi-level community structure detection failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, links);

  for (i = 0; i < n; i++) {
    long int eidx = (long int) VECTOR(*edges)[i];
    weight = VECTOR(*communities->weights)[eidx];

    to = IGRAPH_OTHER(graph, eidx, vertex);

    *weight_all += weight;
    if (to == vertex) {
      *weight_loop += weight;
      
      links[i].community = community;
      links[i].weight = 0;
      continue;
    }

    to_community = (long int)VECTOR(*(communities->membership))[to];
    if (community == to_community)
      *weight_inside += weight;

    /* debug("Link %ld (C: %ld) <-> %ld (C: %ld)\n", vertex, community, to, to_community); */
    
    links[i].community = to_community;
    links[i].weight = weight;
  }
 
  /* Sort links by community ID and merge the same */
  qsort((void*)links, (size_t) n, sizeof(igraph_i_multilevel_community_link),
      igraph_i_multilevel_community_link_cmp);
   for (i = 0; i < n; i++) {
    to_community = links[i].community;
    if (to_community != last) {
      igraph_vector_push_back(links_community, to_community);
      igraph_vector_push_back(links_weight, links[i].weight);
      last = to_community;
      c++;
    } else {    
      VECTOR(*links_weight)[c] += links[i].weight;
    }
  }

  igraph_free(links);
  IGRAPH_FINALLY_CLEAN(1);

  return 0;
}
示例#18
0
/**
 * \function igraph_inclist_clear
 * Removes all edges from an incidence list.
 *
 * \param il The 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_inclist_clear(igraph_inclist_t *il) {
  long int i;
  for (i=0; i<il->length; i++) {
    igraph_vector_clear(&il->incs[i]);
  }
}
示例#19
0
int igraph_i_bipartite_projection(const igraph_t *graph,
				  const igraph_vector_bool_t *types,
				  igraph_t *proj,
				  int which,
				  igraph_vector_t *multiplicity) {
  
  long int no_of_nodes=igraph_vcount(graph);
  long int i, j, k;
  igraph_integer_t remaining_nodes=0;
  igraph_vector_t vertex_perm, vertex_index;
  igraph_vector_t edges;
  igraph_adjlist_t adjlist;
  igraph_vector_int_t *neis1, *neis2;
  long int neilen1, neilen2;
  igraph_vector_long_t added;
  igraph_vector_t mult;

  if (which < 0) { return 0; }
  
  IGRAPH_VECTOR_INIT_FINALLY(&vertex_perm, 0);
  IGRAPH_CHECK(igraph_vector_reserve(&vertex_perm, no_of_nodes));
  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&vertex_index, no_of_nodes);
  IGRAPH_CHECK(igraph_vector_long_init(&added, no_of_nodes));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &added);
  IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL));
  IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
  if (multiplicity) { 
    IGRAPH_VECTOR_INIT_FINALLY(&mult, no_of_nodes); 
    igraph_vector_clear(multiplicity);
  }
  
  for (i=0; i<no_of_nodes; i++) {
    if (VECTOR(*types)[i] == which) {
      VECTOR(vertex_index)[i] = ++remaining_nodes;
      igraph_vector_push_back(&vertex_perm, i);
    }
  }

  for (i=0; i<no_of_nodes; i++) {
    if (VECTOR(*types)[i] == which) {
      long int new_i=(long int) VECTOR(vertex_index)[i]-1;
      long int iedges=0;
      neis1=igraph_adjlist_get(&adjlist, i);
      neilen1=igraph_vector_int_size(neis1);
      for (j=0; j<neilen1; j++) {
	long int nei=(long int) VECTOR(*neis1)[j];
	if (IGRAPH_UNLIKELY(VECTOR(*types)[i] == VECTOR(*types)[nei])) {
	  IGRAPH_ERROR("Non-bipartite edge found in bipartite projection",
		       IGRAPH_EINVAL);
	}
	neis2=igraph_adjlist_get(&adjlist, nei);
	neilen2=igraph_vector_int_size(neis2);
	for (k=0; k<neilen2; k++) {
	  long int nei2=(long int) VECTOR(*neis2)[k], new_nei2;
	  if (nei2 <= i) { continue; }
	  if (VECTOR(added)[nei2] == i+1) { 
	    if (multiplicity) { VECTOR(mult)[nei2]+=1; }
	    continue; 
	  }
	  VECTOR(added)[nei2] = i+1;
	  if (multiplicity) { VECTOR(mult)[nei2]=1; }
	  iedges++;

	  IGRAPH_CHECK(igraph_vector_push_back(&edges, new_i));
	  if (multiplicity) { 
	    /* If we need the multiplicity as well, then we put in the
	       old vertex ids here and rewrite it later */
	    IGRAPH_CHECK(igraph_vector_push_back(&edges, nei2));
	  } else { 
	    new_nei2=(long int) VECTOR(vertex_index)[nei2]-1;
	    IGRAPH_CHECK(igraph_vector_push_back(&edges, new_nei2));
	  }
	}
      }
      if (multiplicity) {
	/* OK, we need to go through all the edges added for vertex new_i 
	   and check their multiplicity */
	long int now=igraph_vector_size(&edges);
	long int from=now-iedges*2;
	for (j=from; j<now; j+=2) {
	  long int nei2=(long int) VECTOR(edges)[j+1];
	  long int new_nei2=(long int) VECTOR(vertex_index)[nei2]-1;
	  long int m=(long int) VECTOR(mult)[nei2];
	  VECTOR(edges)[j+1]=new_nei2;
	  IGRAPH_CHECK(igraph_vector_push_back(multiplicity, m));
	}
      }
    } /* if VECTOR(*type)[i] == which */
  }

  if (multiplicity) { 
    igraph_vector_destroy(&mult);
    IGRAPH_FINALLY_CLEAN(1);
  }
  igraph_adjlist_destroy(&adjlist);
  igraph_vector_long_destroy(&added);
  igraph_vector_destroy(&vertex_index);
  IGRAPH_FINALLY_CLEAN(3);
  
  IGRAPH_CHECK(igraph_create(proj, &edges, remaining_nodes, 
			     /*directed=*/ 0));
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  IGRAPH_FINALLY(igraph_destroy, proj);
  
  IGRAPH_I_ATTRIBUTE_DESTROY(proj);
  IGRAPH_I_ATTRIBUTE_COPY(proj, graph, 1, 0, 0);
  IGRAPH_CHECK(igraph_i_attribute_permute_vertices(graph, proj, &vertex_perm));
  igraph_vector_destroy(&vertex_perm);
  IGRAPH_FINALLY_CLEAN(2);
  
  return 0;
}
示例#20
0
int main() {
  igraph_matrix_t m, m2;
  igraph_vector_t v;
  long int i, j, i2, j2;
  igraph_real_t r1, r2;

  igraph_matrix_init(&m, 4, 3);
  byrow(&m);
  
  /* igraph_matrix_e */
  printf("igraph_matrix_e\n");
  apply(m, printf("%i ", (int)igraph_matrix_e(&m, i, j)), printf("\n"));

  /* igraph_matrix_e_ptr */
  printf("igraph_matrix_e_ptr\n");
  apply(m, printf("%i ", (int)igraph_matrix_e_ptr(&m, i, j)[0]), printf("\n"));

  /* igraph_matrix_set */
  printf("igraph_matrix_set\n");
  apply(m, igraph_matrix_set(&m, i, j, i), (void) 0 );
  print_matrix(&m);
  apply(m, igraph_matrix_set(&m, i, j, j), (void) 0 );
  print_matrix(&m);

  /* igraph_matrix_fill */
  printf("igraph_matrix_fill\n");
  igraph_matrix_fill(&m, 42);
  print_matrix(&m);
  igraph_matrix_fill(&m, -42.1);
  print_matrix(&m);
  
  /* igraph_matrix_update */
  printf("igraph_matrix_update\n");
  igraph_matrix_init(&m2, 0, 0);
  byrow(&m);
  igraph_matrix_update(&m2, &m);
  print_matrix(&m2);

  /* igraph_matrix_rbind */
  printf("igraph_matrix_rbind\n");
  igraph_matrix_rbind(&m2, &m);
  print_matrix(&m2);
  printf("\n");
  igraph_matrix_resize(&m, 0, igraph_matrix_ncol(&m2));
  igraph_matrix_rbind(&m2, &m);
  print_matrix(&m2);
  printf("\n");
  igraph_matrix_rbind(&m, &m2);
  print_matrix(&m);

  /* igraph_matrix_cbind */
  printf("igraph_matrix_cbind\n");
  igraph_matrix_resize(&m, 4, 3);
  igraph_matrix_resize(&m2, 4, 2);
  byrow(&m);
  byrow(&m2);
  igraph_matrix_cbind(&m, &m2);
  print_matrix(&m);

  /* igraph_matrix_swap */
  printf("igraph_matrix_swap\n");
  igraph_matrix_update(&m, &m2);
  igraph_matrix_null(&m);
  igraph_matrix_swap(&m, &m2);
  print_matrix(&m);
  print_matrix(&m2);
  
  /* igraph_matrix_get_row */
  /* igraph_matrix_set_row */
  printf("igraph_matrix_get_row\n");
  printf("igraph_matrix_set_row\n");
  igraph_vector_init(&v, 0);
  for (i=0; i<igraph_matrix_nrow(&m); i++) {
    igraph_matrix_get_row(&m, &v, i);
    igraph_matrix_set_row(&m2, &v, i);
  }
  print_matrix(&m2);

  /* igraph_matrix_set_col */
  printf("igraph_matrix_set_col\n");
  igraph_matrix_null(&m2);
  for (i=0; i<igraph_matrix_ncol(&m); i++) {
    igraph_matrix_get_col(&m, &v, i);
    igraph_matrix_set_col(&m2, &v, i);
  }
  print_matrix(&m2);
  
  /* igraph_matrix_swap_rows */
  printf("igraph_matrix_swap_rows\n");
  igraph_matrix_swap_rows(&m2, 0, 0);
  igraph_matrix_swap_rows(&m2, 0, 2);
  print_matrix(&m2);
  
  /* igraph_matrix_swap_cols */
  printf("igraph_matrix_swap_cols\n");
  igraph_matrix_swap_cols(&m2, 0, 0);
  igraph_matrix_swap_cols(&m2, 0, 1);
  print_matrix(&m2);

  /* igraph_matrix_add_constant */
  printf("igraph_matrix_add_constant\n");
  igraph_matrix_add_constant(&m2, 0);
  print_matrix(&m2);  
  igraph_matrix_add_constant(&m2, -1);
  print_matrix(&m2);
  
  /* igraph_matrix_add */
  printf("igraph_matrix_add\n");
  byrow(&m2);
  byrow(&m);
  igraph_matrix_add(&m2, &m);
  print_matrix(&m2);

  /* igraph_matrix_sub */
  printf("igraph_matrix_sub\n");
  igraph_matrix_sub(&m2, &m);
  print_matrix(&m2);

  /* igraph_matrix_mul_elements */
  printf("igraph_matrix_mul_elements\n");
  igraph_matrix_mul_elements(&m2, &m);
  print_matrix(&m2);

  /* igraph_matrix_div_elements */
  printf("igraph_matrix_div_elements\n");
  igraph_matrix_fill(&m, 2);
  igraph_matrix_div_elements(&m2, &m);
  print_matrix(&m2);

  /* igraph_matrix_min */
  printf("igraph_matrix_min\n");
  if (igraph_matrix_min(&m2) != 0) {
    return 1;
  }
  if (igraph_matrix_min(&m) != 2) {
    return 1;
  }

  /* igraph_matrix_which_min */
  printf("igraph_matrix_which_min\n");
  igraph_matrix_which_min(&m2, &i, &j);
  if (i != 0 || j != 0) { return 2; }
  MATRIX(m2,0,1) = -1;
  igraph_matrix_which_min(&m2, &i, &j);
  if (i != 0 || j != 1) { return 2; }
  MATRIX(m2,3,1) = -2;
  igraph_matrix_which_min(&m2, &i, &j);
  if (i != 3 || j != 1) { return 2; }

  /* igraph_matrix_which_max */
  printf("igraph_matrix_which_max\n");
  MATRIX(m2,3,0) = 100;
  igraph_matrix_which_max(&m2, &i, &j);
  if (i != 3 || j != 0) { return 3; }
  
  /* igraph_matrix_minmax */
  printf("igraph_matrix_minmax\n");
  igraph_matrix_minmax(&m2, &r1, &r2);
  printf("%g %g\n", r1, r2);
  
  /* igraph_matrix_which_minmax */
  printf("igraph_matrix_which_minmax\n");
  igraph_matrix_which_minmax(&m2, &i, &j, &i2, &j2);
  if (i != 3 || j != 1 || i2 != 3 || j2 != 0) { return 4; }

  /* igraph_matrix_isnull */
  printf("igraph_matrix_isnull\n");
  if (igraph_matrix_isnull(&m2)) { return 5; }
  igraph_matrix_null(&m);
  if (!igraph_matrix_isnull(&m)) { return 5; }
  igraph_matrix_resize(&m2, 5, 0);
  if (!igraph_matrix_isnull(&m2)) { return 5; }  
  
  /* igraph_matrix_empty */
  printf("igraph_matrix_empty\n");
  if (!igraph_matrix_empty(&m2)) { return 6; }
  igraph_matrix_resize(&m2, 5, 5);
  if (igraph_matrix_empty(&m2)) { return 6; }

  /* igraph_matrix_is_symmetric */
  printf("igraph_matrix_is_symmetric\n");
  byrow(&m2);
  if (igraph_matrix_is_symmetric(&m2)) { return 7; }
  igraph_matrix_update(&m, &m2);
  igraph_matrix_transpose(&m);
  igraph_matrix_add(&m, &m2);
  if (!igraph_matrix_is_symmetric(&m)) { return 7; }

  /* igraph_matrix_prod */
  printf("igraph_matrix_prod\n");
  igraph_matrix_resize(&m, 3,2);
  byrow(&m);
  igraph_matrix_add_constant(&m, 1);
  print_matrix(&m);
  printf("product: %g\n", igraph_matrix_prod(&m));

  /* igraph_matrix_rowsum */
  printf("igraph_matrix_rowsum\n");
  igraph_matrix_rowsum(&m, &v);
  print_vector(&v);

  /* igraph_matrix_colsum */
  printf("igraph_matrix_colsum\n");
  igraph_matrix_colsum(&m, &v);
  print_vector(&v);

  /* igraph_matrix_contains */
  printf("igraph_matrix_contains\n");
  if (igraph_matrix_contains(&m, 0)) { return 8; }
  if (igraph_matrix_contains(&m, 6.0001)) { return 8; }
  if (igraph_matrix_contains(&m, 7)) { return 8; }
  if (!igraph_matrix_contains(&m, 1)) { return 8; }
  if (!igraph_matrix_contains(&m, 6)) { return 8; }
  
  /* igraph_matrix_search */
  printf("igraph_matrix_search\n");
  if (!igraph_matrix_search(&m, 0, 6.0, &i2, &i, &j)) { return 9; }
  if (i2 != 5 || i != 2 || j != 1) { return 9; }
  
  /* igraph_matrix_remove_row */
  printf("igraph_matrix_remove_row\n");
  igraph_matrix_remove_row(&m, 1);
  print_matrix(&m);
  igraph_matrix_resize(&m,5,4);
  byrow(&m);
  igraph_matrix_remove_row(&m, 4);
  print_matrix(&m);
  igraph_matrix_remove_row(&m, 0);
  print_matrix(&m);

  /* igraph_matrix_select_cols */
  printf("igraph_matrix_select_cols\n");
  igraph_matrix_resize(&m, 6, 5);
  apply(m, igraph_matrix_set(&m, i, j, j), (void) 0 );
  igraph_vector_resize(&v, 3);
  VECTOR(v)[0]=0; VECTOR(v)[1]=4; VECTOR(v)[2]=2;
  igraph_matrix_select_cols(&m, &m2, &v);
  print_matrix(&m2);
  igraph_vector_resize(&v, 1);
  igraph_matrix_select_cols(&m, &m2, &v);
  print_matrix(&m2);
  igraph_vector_clear(&v);
  igraph_matrix_select_cols(&m, &m2, &v);
  if (!igraph_matrix_empty(&m2)) { return 9; }

  igraph_vector_destroy(&v);
  igraph_matrix_destroy(&m2);
  igraph_matrix_destroy(&m);

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

  return 0;
}
示例#21
0
int igraph_clusters_strong(const igraph_t *graph, igraph_vector_t *membership,
			   igraph_vector_t *csize, igraph_integer_t *no) {

  long int no_of_nodes=igraph_vcount(graph);
  igraph_vector_t next_nei=IGRAPH_VECTOR_NULL;
  
  long int i;
  igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
  
  long int no_of_clusters=1;
  long int act_cluster_size;

  igraph_vector_t out=IGRAPH_VECTOR_NULL;
  igraph_vector_t tmp=IGRAPH_VECTOR_NULL;

  /* The result */

  IGRAPH_VECTOR_INIT_FINALLY(&next_nei, no_of_nodes);
  IGRAPH_VECTOR_INIT_FINALLY(&out, 0);
  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
  IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0);

  if (membership) {
    IGRAPH_CHECK(igraph_vector_resize(membership, no_of_nodes));
  }
  IGRAPH_CHECK(igraph_vector_reserve(&out, no_of_nodes));

  igraph_vector_null(&out);
  if (csize) {
    igraph_vector_clear(csize);
  }
  
  for (i=0; i<no_of_nodes; i++) {
    IGRAPH_ALLOW_INTERRUPTION();
    IGRAPH_CHECK(igraph_neighbors(graph, &tmp, (igraph_integer_t) i,
				  IGRAPH_OUT));
    if (VECTOR(next_nei)[i] > igraph_vector_size(&tmp)) { continue; }
    
    IGRAPH_CHECK(igraph_dqueue_push(&q, i));
    while (!igraph_dqueue_empty(&q)) {
      long int act_node=(long int) igraph_dqueue_back(&q);
      IGRAPH_CHECK(igraph_neighbors(graph, &tmp, (igraph_integer_t) act_node,
				    IGRAPH_OUT));
      if (VECTOR(next_nei)[act_node]==0) {
	/* this is the first time we've met this vertex */
	VECTOR(next_nei)[act_node]++;
      } else if (VECTOR(next_nei)[act_node] <= igraph_vector_size(&tmp)) {
	/* we've already met this vertex but it has more children */
	long int neighbor=(long int) VECTOR(tmp)[(long int)
						 VECTOR(next_nei)[act_node]-1];
	if (VECTOR(next_nei)[neighbor] == 0) {
	  IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
	}
	VECTOR(next_nei)[act_node]++;
      } else {
	/* we've met this vertex and it has no more children */
	IGRAPH_CHECK(igraph_vector_push_back(&out, act_node));
	igraph_dqueue_pop_back(&q);
      }
    } /* while q */
  }  /* for */

  /* OK, we've the 'out' values for the nodes, let's use them in
     decreasing order with the help of a heap */

  igraph_vector_null(&next_nei);                            /* mark already
							added vertices */
  while (!igraph_vector_empty(&out)) {
    long int grandfather=(long int) igraph_vector_pop_back(&out);
    IGRAPH_ALLOW_INTERRUPTION();
    if (VECTOR(next_nei)[grandfather] != 0) { continue; }
    VECTOR(next_nei)[grandfather]=1;
    act_cluster_size=1;
    if (membership) {
      VECTOR(*membership)[grandfather]=no_of_clusters-1;
    }
    IGRAPH_CHECK(igraph_dqueue_push(&q, grandfather));
    
    while (!igraph_dqueue_empty(&q)) {
      long int act_node=(long int) igraph_dqueue_pop_back(&q);
      IGRAPH_CHECK(igraph_neighbors(graph, &tmp, (igraph_integer_t) act_node, 
				    IGRAPH_IN));
      for (i=0; i<igraph_vector_size(&tmp); i++) {
	long int neighbor=(long int) VECTOR(tmp)[i];
	if (VECTOR(next_nei)[neighbor] != 0) { continue; }
	IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
	VECTOR(next_nei)[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));
    }
  }
  
  if (no) { *no=(igraph_integer_t) no_of_clusters-1; }

  /* Clean up, return */

  igraph_vector_destroy(&out);
  igraph_vector_destroy(&tmp);
  igraph_dqueue_destroy(&q);
  igraph_vector_destroy(&next_nei);
  IGRAPH_FINALLY_CLEAN(4);

  return 0;
}
示例#22
0
int igraph_compose(igraph_t *res, const igraph_t *g1, const igraph_t *g2,
		   igraph_vector_t *edge_map1, igraph_vector_t *edge_map2) {
  
  long int no_of_nodes_left=igraph_vcount(g1);
  long int no_of_nodes_right=igraph_vcount(g2);
  long int no_of_nodes;
  igraph_bool_t directed=igraph_is_directed(g1);
  igraph_vector_t edges;
  igraph_vector_t neis1, neis2;
  long int i;

  if (directed != igraph_is_directed(g2)) {
    IGRAPH_ERROR("Cannot compose directed and undirected graph",
		 IGRAPH_EINVAL);
  }

  no_of_nodes= no_of_nodes_left > no_of_nodes_right ? 
    no_of_nodes_left : no_of_nodes_right;

  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&neis1, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&neis2, 0);

  if (edge_map1) { igraph_vector_clear(edge_map1); }
  if (edge_map2) { igraph_vector_clear(edge_map2); }

  for (i=0; i<no_of_nodes_left; i++) {
    IGRAPH_ALLOW_INTERRUPTION();
    IGRAPH_CHECK(igraph_incident(g1, &neis1, (igraph_integer_t) i,
				 IGRAPH_OUT));
    while (!igraph_vector_empty(&neis1)) {
      long int con=(long int) igraph_vector_pop_back(&neis1);
      long int v1=IGRAPH_OTHER(g1, con, i);
      if (v1 < no_of_nodes_right) {
	IGRAPH_CHECK(igraph_incident(g2, &neis2, (igraph_integer_t) v1,
				     IGRAPH_OUT));
      } else {
	continue;
      }
      while (!igraph_vector_empty(&neis2)) {
	long int con2=igraph_vector_pop_back(&neis2);
	long int v2=IGRAPH_OTHER(g2, con2, v1);
	IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
	IGRAPH_CHECK(igraph_vector_push_back(&edges, v2));
	if (edge_map1) {
	  IGRAPH_CHECK(igraph_vector_push_back(edge_map1, con));
	}
	if (edge_map2) {
	  IGRAPH_CHECK(igraph_vector_push_back(edge_map2, con2));
	}
      }
    }
  }

  igraph_vector_destroy(&neis1);
  igraph_vector_destroy(&neis2);
  IGRAPH_FINALLY_CLEAN(2);

  IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) no_of_nodes,
			     directed));

  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  return 0;
}
示例#23
0
int igraph_biconnected_components(const igraph_t *graph,
				  igraph_integer_t *no,
				  igraph_vector_ptr_t *tree_edges,
				  igraph_vector_ptr_t *component_edges,
				  igraph_vector_ptr_t *components,
				  igraph_vector_t *articulation_points) {

  long int no_of_nodes=igraph_vcount(graph);
  igraph_vector_long_t nextptr;
  igraph_vector_long_t num, low;
  igraph_vector_bool_t found;
  igraph_vector_int_t *adjedges;
  igraph_stack_t path;
  igraph_vector_t edgestack;
  igraph_inclist_t inclist;
  long int i, counter, rootdfs=0;  
  igraph_vector_long_t vertex_added;
  long int comps=0;
  igraph_vector_ptr_t *mycomponents=components, vcomponents;

  IGRAPH_CHECK(igraph_vector_long_init(&nextptr, no_of_nodes));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &nextptr);
  IGRAPH_CHECK(igraph_vector_long_init(&num, no_of_nodes));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &num);
  IGRAPH_CHECK(igraph_vector_long_init(&low, no_of_nodes));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &low);
  IGRAPH_CHECK(igraph_vector_bool_init(&found, no_of_nodes));
  IGRAPH_FINALLY(igraph_vector_bool_destroy, &found);

  IGRAPH_CHECK(igraph_stack_init(&path, 100));
  IGRAPH_FINALLY(igraph_stack_destroy, &path);
  IGRAPH_VECTOR_INIT_FINALLY(&edgestack, 0);
  IGRAPH_CHECK(igraph_vector_reserve(&edgestack, 100));

  IGRAPH_CHECK(igraph_inclist_init(graph, &inclist, IGRAPH_ALL));
  IGRAPH_FINALLY(igraph_inclist_destroy, &inclist);

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

  if (no) {
    *no=0;
  }
  if (tree_edges) {
    igraph_vector_ptr_clear(tree_edges);
  }
  if (components) {
    igraph_vector_ptr_clear(components);
  }
  if (component_edges) {
    igraph_vector_ptr_clear(component_edges);
  }
  if (articulation_points) {
    igraph_vector_clear(articulation_points);
  }
  if (component_edges && !components) {
    mycomponents=&vcomponents;
    IGRAPH_CHECK(igraph_vector_ptr_init(mycomponents, 0));
    IGRAPH_FINALLY(igraph_i_free_vectorlist, mycomponents);
  }

  for (i=0; i<no_of_nodes; i++) {
    
    if (VECTOR(low)[i] != 0) { continue; } /* already visited */

    IGRAPH_ALLOW_INTERRUPTION();

    IGRAPH_CHECK(igraph_stack_push(&path, i));
    counter=1; 
    rootdfs=0;
    VECTOR(low)[i]=VECTOR(num)[i]=counter++;
    while (!igraph_stack_empty(&path)) {
      long int n;
      long int act=(long int) igraph_stack_top(&path);
      long int actnext=VECTOR(nextptr)[act];
      
      adjedges=igraph_inclist_get(&inclist, act);
      n=igraph_vector_int_size(adjedges);
      if (actnext < n) {
	/* Step down (maybe) */
	long int edge=(long int) VECTOR(*adjedges)[actnext];
	long int nei=IGRAPH_OTHER(graph, edge, act);
	if (VECTOR(low)[nei] == 0) {
	  if (act==i) { rootdfs++; }
	  IGRAPH_CHECK(igraph_vector_push_back(&edgestack, edge));
	  IGRAPH_CHECK(igraph_stack_push(&path, nei));
	  VECTOR(low)[nei] = VECTOR(num)[nei]=counter++;
	} else {
	  /* Update low value if needed */
	  if (VECTOR(num)[nei] < VECTOR(low)[act]) {
	    VECTOR(low)[act]=VECTOR(num)[nei];
	  }
	}
	VECTOR(nextptr)[act] += 1;
      } else {
	/* Step up */
	igraph_stack_pop(&path);
	if (!igraph_stack_empty(&path)) {
	  long int prev=(long int) igraph_stack_top(&path);
	  /* Update LOW value if needed */
	  if (VECTOR(low)[act] < VECTOR(low)[prev]) {
	    VECTOR(low)[prev] = VECTOR(low)[act];
	  }
	  /* Check for articulation point */
	  if (VECTOR(low)[act] >= VECTOR(num)[prev]) {
	    if (articulation_points && !VECTOR(found)[prev] 
		&& prev != i /* the root */) {
	      IGRAPH_CHECK(igraph_vector_push_back(articulation_points, prev));
	      VECTOR(found)[prev] = 1;
	    }
	    if (no) { *no += 1; }

	    /*------------------------------------*/
	    /* Record the biconnected component just found */
	    if (tree_edges || mycomponents) {
	      igraph_vector_t *v = 0, *v2 = 0;
	      comps++;
	      if (tree_edges) { 
		v=igraph_Calloc(1, igraph_vector_t);
		if (!v) { IGRAPH_ERROR("Out of memory", IGRAPH_ENOMEM); }
		IGRAPH_CHECK(igraph_vector_init(v, 0));
		IGRAPH_FINALLY(igraph_vector_destroy, v);
	      }
	      if (mycomponents) {
		v2=igraph_Calloc(1, igraph_vector_t);
		if (!v2) { IGRAPH_ERROR("Out of memory", IGRAPH_ENOMEM); }
		IGRAPH_CHECK(igraph_vector_init(v2, 0));
		IGRAPH_FINALLY(igraph_vector_destroy, v2);
	      }
	      
	      while (!igraph_vector_empty(&edgestack)) {
		long int e=(long int) igraph_vector_pop_back(&edgestack);
		long int from=IGRAPH_FROM(graph,e);
		long int to=IGRAPH_TO(graph,e);
		if (tree_edges) { 
		  IGRAPH_CHECK(igraph_vector_push_back(v, e));
		}
		if (mycomponents) {
		  if (VECTOR(vertex_added)[from] != comps) { 
		    VECTOR(vertex_added)[from] = comps;
		    IGRAPH_CHECK(igraph_vector_push_back(v2, from));
		  }
		  if (VECTOR(vertex_added)[to] != comps) {
		    VECTOR(vertex_added)[to] = comps;
		    IGRAPH_CHECK(igraph_vector_push_back(v2, to));
		  }
		}
		if (from==prev || to==prev) {
		  break;
		}
	      }
	      
	      if (mycomponents) {
		IGRAPH_CHECK(igraph_vector_ptr_push_back(mycomponents, v2));
		IGRAPH_FINALLY_CLEAN(1);
	      }
	      if (tree_edges) { 
		IGRAPH_CHECK(igraph_vector_ptr_push_back(tree_edges, v));
		IGRAPH_FINALLY_CLEAN(1);
	      }
	      if (component_edges) {
		igraph_vector_t *nodes=VECTOR(*mycomponents)[comps-1];
		igraph_vector_t *vv=igraph_Calloc(1, igraph_vector_t);
		long int ii, no_vert=igraph_vector_size(nodes);
		if (!vv) { IGRAPH_ERROR("Out of memory", IGRAPH_ENOMEM); }
		IGRAPH_CHECK(igraph_vector_init(vv, 0));
		IGRAPH_FINALLY(igraph_vector_destroy, vv);
		for (ii=0; ii<no_vert; ii++) {
		  long int vert=(long int) VECTOR(*nodes)[ii];
		  igraph_vector_int_t *edges=igraph_inclist_get(&inclist, 
								vert);
		  long int j, nn=igraph_vector_int_size(edges);
		  for (j=0; j<nn; j++) {
		    long int e=(long int) VECTOR(*edges)[j];
		    long int nei=IGRAPH_OTHER(graph, e, vert);
		    if (VECTOR(vertex_added)[nei] == comps && nei<vert) {
		      IGRAPH_CHECK(igraph_vector_push_back(vv, e));
		    }
		  }
		}
		IGRAPH_CHECK(igraph_vector_ptr_push_back(component_edges, vv));
		IGRAPH_FINALLY_CLEAN(1);
	      }
	    } /* record component if requested */
	    /*------------------------------------*/

	  }
	} /* !igraph_stack_empty(&path) */
      }
      
    } /* !igraph_stack_empty(&path) */
    
    if (articulation_points && rootdfs >= 2) {
      IGRAPH_CHECK(igraph_vector_push_back(articulation_points, i));
    }

  } /* i < no_of_nodes */

  if (mycomponents != components) {
    igraph_i_free_vectorlist(mycomponents);
    IGRAPH_FINALLY_CLEAN(1);
  }

  igraph_vector_long_destroy(&vertex_added);
  igraph_inclist_destroy(&inclist);
  igraph_vector_destroy(&edgestack);
  igraph_stack_destroy(&path);
  igraph_vector_bool_destroy(&found);
  igraph_vector_long_destroy(&low);
  igraph_vector_long_destroy(&num);
  igraph_vector_long_destroy(&nextptr);
  IGRAPH_FINALLY_CLEAN(8);

  return 0;
}
示例#24
0
int igraph_i_merge(igraph_t *res, int mode, 
		   const igraph_t *left, const igraph_t *right, 
		   igraph_vector_t *edge_map1, igraph_vector_t *edge_map2) {
  
  long int no_of_nodes_left=igraph_vcount(left);
  long int no_of_nodes_right=igraph_vcount(right);
  long int no_of_nodes;
  long int no_edges_left=igraph_ecount(left);
  long int no_edges_right=igraph_ecount(right);
  igraph_bool_t directed=igraph_is_directed(left);
  igraph_vector_t edges;
  igraph_vector_t edges1, edges2;
  igraph_vector_long_t order1, order2;
  long int i, j, eptr=0;
  long int idx1, idx2, edge1=-1, edge2=-1, from1=-1, from2=-1, to1=-1, to2=-1;
  igraph_bool_t l;

  if (directed != igraph_is_directed(right)) {
    IGRAPH_ERROR("Cannot make union or intersection of directed "
		 "and undirected graph", IGRAPH_EINVAL);
  }
  
  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&edges1, no_edges_left*2);
  IGRAPH_VECTOR_INIT_FINALLY(&edges2, no_edges_right*2);
  IGRAPH_CHECK(igraph_vector_long_init(&order1, no_edges_left));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &order1);
  IGRAPH_CHECK(igraph_vector_long_init(&order2, no_edges_right));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &order2);
  
  if (edge_map1) { 
    switch (mode) {
    case IGRAPH_MODE_UNION:
      IGRAPH_CHECK(igraph_vector_resize(edge_map1, no_edges_left));
      break;
    case IGRAPH_MODE_INTERSECTION:
      igraph_vector_clear(edge_map1);
      break;
    }
  }
  if (edge_map2) { 
    switch (mode) {
    case IGRAPH_MODE_UNION:
      IGRAPH_CHECK(igraph_vector_resize(edge_map2, no_edges_right));
      break;
    case IGRAPH_MODE_INTERSECTION:
      igraph_vector_clear(edge_map2);
      break;
    }
  }

  no_of_nodes=no_of_nodes_left > no_of_nodes_right ?
    no_of_nodes_left : no_of_nodes_right;

  /* We merge the two edge lists. We need to sort them first.
     For undirected graphs, we also need to make sure that 
     for every edge, that larger (non-smaller) vertex id is in the
     second column. */

  IGRAPH_CHECK(igraph_get_edgelist(left, &edges1, /*bycol=*/ 0));
  IGRAPH_CHECK(igraph_get_edgelist(right, &edges2, /*bycol=*/ 0));
  if (!directed) {
    for (i=0, j=0; i<no_edges_left; i++, j+=2) {
      if (VECTOR(edges1)[j] > VECTOR(edges1)[j+1]) {
	long int tmp=VECTOR(edges1)[j];
	VECTOR(edges1)[j]=VECTOR(edges1)[j+1];
	VECTOR(edges1)[j+1]=tmp;
      }
    }
    for (i=0, j=0; i<no_edges_right; i++, j+=2) {
      if (VECTOR(edges2)[j] > VECTOR(edges2)[j+1]) {
	long int tmp=VECTOR(edges2)[j];
	VECTOR(edges2)[j]=VECTOR(edges2)[j+1];
	VECTOR(edges2)[j+1]=tmp;
      }
    }
  }

  for (i=0; i<no_edges_left; i++) {
    VECTOR(order1)[i]=i;
  }
  for (i=0; i<no_edges_right; i++) {
    VECTOR(order2)[i]=i;
  }

  igraph_qsort_r(VECTOR(order1), no_edges_left, sizeof(VECTOR(order1)[0]),
		 &edges1, igraph_i_order_edgelist_cmp);
  igraph_qsort_r(VECTOR(order2), no_edges_right, sizeof(VECTOR(order2)[0]),
		 &edges2, igraph_i_order_edgelist_cmp);

#define INC1() if ( (++idx1) < no_edges_left) {			 \
    edge1 = VECTOR(order1)[idx1];				 \
    from1 = VECTOR(edges1)[2*edge1];				 \
    to1 = VECTOR(edges1)[2*edge1+1];				 \
  }
#define INC2() if ( (++idx2) < no_edges_right) {		 \
    edge2 = VECTOR(order2)[idx2];				 \
    from2 = VECTOR(edges2)[2*edge2];				 \
    to2 = VECTOR(edges2)[2*edge2+1];				 \
  }

  idx1 = idx2 = -1;
  INC1();
  INC2();
  
#define CONT() switch (mode) {				\
 case IGRAPH_MODE_UNION:				\
   l = idx1 < no_edges_left || idx2 < no_edges_right;	\
   break;						\
 case IGRAPH_MODE_INTERSECTION:				\
   l = idx1 < no_edges_left && idx2 < no_edges_right;	\
   break;						\
  }

  CONT();
  while (l) {
    if (idx2 >= no_edges_right || 
	(idx1 < no_edges_left && from1 < from2) || 
	(idx1 < no_edges_left && from1 == from2 && to1 < to2)) {
      /* Edge from first graph */
      if (mode==IGRAPH_MODE_UNION) {
	IGRAPH_CHECK(igraph_vector_push_back(&edges, from1));
	IGRAPH_CHECK(igraph_vector_push_back(&edges, to1));
	if (edge_map1) { VECTOR(*edge_map1)[edge1]=eptr; }
	eptr++;
      }
      INC1();
    } else if (idx1 >= no_edges_left ||
	       (idx2 < no_edges_right && from2 < from1) ||
	       (idx2 < no_edges_right && from1 == from2 && to2 < to1)) {
      /* Edge from second graph */
      if (mode==IGRAPH_MODE_UNION) {
	IGRAPH_CHECK(igraph_vector_push_back(&edges, from2));
	IGRAPH_CHECK(igraph_vector_push_back(&edges, to2));
	if (edge_map2) { VECTOR(*edge_map2)[edge2]=eptr; }
	eptr++;
      }
      INC2();
    } else {
      /* Edge from both */
      IGRAPH_CHECK(igraph_vector_push_back(&edges, from1));
      IGRAPH_CHECK(igraph_vector_push_back(&edges, to1));
      if (mode==IGRAPH_MODE_UNION) {
	if (edge_map1) { VECTOR(*edge_map1)[edge1]=eptr; }
	if (edge_map2) { VECTOR(*edge_map2)[edge2]=eptr; }
      } else if (mode==IGRAPH_MODE_INTERSECTION) {
	if (edge_map1) { 
	  IGRAPH_CHECK(igraph_vector_push_back(edge_map1, edge1));
	}
	if (edge_map2) {
	  IGRAPH_CHECK(igraph_vector_push_back(edge_map2, edge2));
	}
      }
      eptr++;
      INC1();
      INC2();
    }
    CONT();
  }
  
#undef INC1
#undef INC2

  igraph_vector_long_destroy(&order2);
  igraph_vector_long_destroy(&order1);
  igraph_vector_destroy(&edges2);
  igraph_vector_destroy(&edges1);
  IGRAPH_FINALLY_CLEAN(4);
  
  IGRAPH_CHECK(igraph_create(res, &edges, no_of_nodes, directed));
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  return 0;
}
示例#25
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;
}
示例#26
0
文件: other.c 项目: igraph/igraph
/**
 * \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
 * 
 * \example examples/simple/igraph_convex_hull.c
 */
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_vector_t angles, stack, order;
  igraph_real_t px, py, cp;
  
  no_of_nodes=(igraph_integer_t) 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;
  }
    
  IGRAPH_VECTOR_INIT_FINALLY(&angles, no_of_nodes);
  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 */
      VECTOR(angles)[i] = 10;
    } else {
      VECTOR(angles)[i] = atan2(MATRIX(*data, i, 1)-py, MATRIX(*data, i, 0)-px);
    }
  }

  /* Sort points by angles */
  IGRAPH_VECTOR_INIT_FINALLY(&order, no_of_nodes);
  IGRAPH_CHECK(igraph_vector_qsort_ind(&angles, &order, 0));

  /* Check if two points have the same angle. If so, keep only the point that
   * is farthest from the pivot */
  j = 0;
  last_idx = (long int) VECTOR(order)[0];
  pivot_idx = (long int) VECTOR(order)[no_of_nodes - 1];
  for (i=1; i < no_of_nodes; i++) {
    next_idx = (long int) VECTOR(order)[i];
    if (VECTOR(angles)[last_idx] == VECTOR(angles)[next_idx]) {
      /* Keep the vertex that is farther from the pivot, drop the one that is
       * closer */
      px = pow(MATRIX(*data, last_idx, 0) - MATRIX(*data, pivot_idx, 0), 2) +
           pow(MATRIX(*data, last_idx, 1) - MATRIX(*data, pivot_idx, 1), 2);
      py = pow(MATRIX(*data, next_idx, 0) - MATRIX(*data, pivot_idx, 0), 2) +
           pow(MATRIX(*data, next_idx, 1) - MATRIX(*data, pivot_idx, 1), 2);
      if (px > py) {
        VECTOR(order)[i] = -1;
      } else {
        VECTOR(order)[j] = -1;
        last_idx = next_idx;
        j = i;
      }
    } else {
      last_idx = next_idx;
      j = i;
    }
  }

  j=0;
  last_idx=-1;
  before_last_idx=-1;
  while (!igraph_vector_empty(&order)) {
    next_idx=(long int)VECTOR(order)[igraph_vector_size(&order) - 1];
    if (next_idx < 0) {
      /* This vertex should be skipped; was excluded in an earlier step */
      igraph_vector_pop_back(&order);
      continue;
    }
    /* Determine whether we are at a left or right turn */
    if (j < 2) {
      /* Pretend that we are turning into the right direction if we have less
       * than two items in the stack */
      cp=-1;
    } else {
      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: %ld, %ld, %ld, %f [", before_last_idx, last_idx, next_idx, (float)cp);
    for (int k=0; k<j; k++) printf("%ld ", (long)VECTOR(stack)[k]);
    printf("]\n");
	*/
    if (cp < 0) {
      /* We are turning into the right direction */
      igraph_vector_pop_back(&order);
      IGRAPH_CHECK(igraph_vector_push_back(&stack, next_idx));
      before_last_idx = last_idx;
      last_idx = next_idx;
      j++;
    } else {
      /* No, skip back and try again in the next iteration */
      igraph_vector_pop_back(&stack);
      j--;
      last_idx = before_last_idx;
      before_last_idx = (j >= 2) ? (long int) VECTOR(stack)[j-2] : -1;
    }
  }
  
  /* 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(&order);
  igraph_vector_destroy(&stack);
  igraph_vector_destroy(&angles);
  IGRAPH_FINALLY_CLEAN(3);
  
  return 0;
}
示例#27
0
int igraph_cohesive_blocks(const igraph_t *graph,
			   igraph_vector_ptr_t *blocks,
			   igraph_vector_t *cohesion,
			   igraph_vector_t *parent,
			   igraph_t *block_tree) {

  /* Some implementation comments. Everything is relatively
     straightforward, except, that we need to follow the vertex ids
     of the various subgraphs, without having to store two-way
     mappings at each level. The subgraphs can overlap, this
     complicates things a bit.

     The 'Q' vector is used as a double ended queue and it contains
     the subgraphs to work on in the future. Some other vectors are
     associated with it. 'Qparent' gives the parent graph of a graph
     in Q. Qmapping gives the mapping of the vertices from the graph
     to the parent graph. Qcohesion is the vertex connectivity of the 
     graph. 

     Qptr is an integer and points to the next graph to work on.
  */
  
  igraph_vector_ptr_t Q;
  igraph_vector_ptr_t Qmapping;
  igraph_vector_long_t Qparent;
  igraph_vector_long_t Qcohesion;
  igraph_vector_bool_t Qcheck;
  long int Qptr=0;
  igraph_integer_t conn;
  igraph_bool_t is_simple;

  igraph_t *graph_copy;
  
  igraph_vector_ptr_t separators;
  igraph_vector_t compvertices;
  igraph_vector_long_t components;
  igraph_vector_bool_t marked;

  igraph_vector_long_t compid;
  igraph_dqueue_t bfsQ;
  igraph_vector_t neis;

  if (igraph_is_directed(graph)) {
    IGRAPH_ERROR("Cohesive blocking only works on undirected graphs",
		 IGRAPH_EINVAL);
  }

  IGRAPH_CHECK(igraph_is_simple(graph, &is_simple));
  if (!is_simple) {
    IGRAPH_ERROR("Cohesive blocking only works on simple graphs",
		 IGRAPH_EINVAL);
  }

  IGRAPH_STATUS("Starting cohesive block calculation.\n", 0);

  if (blocks)   { igraph_vector_ptr_clear(blocks); }
  if (cohesion) { igraph_vector_clear(cohesion);   }
  if (parent)   { igraph_vector_clear(parent);     }

  IGRAPH_CHECK(igraph_vector_ptr_init(&Q, 1));
  IGRAPH_FINALLY(igraph_vector_ptr_destroy, &Q);
  IGRAPH_FINALLY(igraph_i_cohesive_blocks_free, &Q);

  IGRAPH_CHECK(igraph_vector_ptr_init(&Qmapping, 1));
  IGRAPH_FINALLY(igraph_vector_ptr_destroy, &Qmapping);
  IGRAPH_FINALLY(igraph_i_cohesive_blocks_free2, &Qmapping);

  IGRAPH_CHECK(igraph_vector_long_init(&Qparent, 1));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &Qparent);

  IGRAPH_CHECK(igraph_vector_long_init(&Qcohesion, 1));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &Qcohesion);

  IGRAPH_CHECK(igraph_vector_bool_init(&Qcheck, 1));
  IGRAPH_FINALLY(igraph_vector_bool_destroy, &Qcheck);
  
  IGRAPH_CHECK(igraph_vector_ptr_init(&separators, 0));
  IGRAPH_FINALLY(igraph_vector_ptr_destroy, &separators);

  IGRAPH_VECTOR_INIT_FINALLY(&compvertices, 0);
  IGRAPH_CHECK(igraph_vector_bool_init(&marked, 0));
  IGRAPH_FINALLY(igraph_vector_bool_destroy, &marked);
  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
  IGRAPH_CHECK(igraph_dqueue_init(&bfsQ, 100));
  IGRAPH_FINALLY(igraph_dqueue_destroy, &bfsQ);
  IGRAPH_CHECK(igraph_vector_long_init(&compid, 0));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &compid);
  IGRAPH_CHECK(igraph_vector_long_init(&components, 0));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &components);
  
  /* Put the input graph in the queue */
  graph_copy=igraph_Calloc(1, igraph_t);
  if (!graph_copy) { 
    IGRAPH_ERROR("Cannot do cohesive blocking", IGRAPH_ENOMEM);
  }
  IGRAPH_CHECK(igraph_copy(graph_copy, graph));
  VECTOR(Q)[0] = graph_copy;
  VECTOR(Qmapping)[0] = 0;	/* Identity mapping */
  VECTOR(Qparent)[0] = -1;	/* Has no parent */
  IGRAPH_CHECK(igraph_vertex_connectivity(graph, &conn, /*checks=*/ 1));
  VECTOR(Qcohesion)[0] = conn;
  VECTOR(Qcheck)[0] = 0;  

  /* Then work until the queue is empty */
  while (Qptr < igraph_vector_ptr_size(&Q)) {
    igraph_t *mygraph=VECTOR(Q)[Qptr];
    igraph_bool_t mycheck=VECTOR(Qcheck)[Qptr];
    long int mynodes=igraph_vcount(mygraph);
    long int i, nsep;
    long int no, kept=0;
    long int cptr=0;
    long int nsepv=0;
    igraph_bool_t addedsep=0;

    IGRAPH_STATUSF(("Candidate %li: %li vertices,", 
		    0, Qptr, mynodes));
    IGRAPH_ALLOW_INTERRUPTION();

    /* Get the separators */
    IGRAPH_CHECK(igraph_minimum_size_separators(mygraph, &separators));
    IGRAPH_FINALLY(igraph_i_cohesive_blocks_free3, &separators);
    nsep=igraph_vector_ptr_size(&separators);
    
    IGRAPH_STATUSF((" %li separators,", 0, nsep));

    /* Remove them from the graph, also mark them */    
    IGRAPH_CHECK(igraph_vector_bool_resize(&marked, mynodes));
    igraph_vector_bool_null(&marked);
    for (i=0; i<nsep; i++) {
      igraph_vector_t *v=VECTOR(separators)[i];
      long int j, n=igraph_vector_size(v);
      for (j=0; j<n; j++) {
	long int vv=(long int) VECTOR(*v)[j];
	if (!VECTOR(marked)[vv]) {
	  nsepv++;
	  VECTOR(marked)[vv] = 1;
	}
      }
    }
    
    /* Find the connected components, omitting the separator vertices, 
       but including the neighboring separator vertices
     */
    IGRAPH_CHECK(igraph_i_cb_components(mygraph, &marked, 
					&components, &no,
					&compid, &bfsQ, &neis));

    /* Add the separator vertices themselves, as another component,
       but only if there is at least one vertex not included in any 
       separator. */
    if (nsepv != mynodes) {
      addedsep=1;
      for (i=0; i<mynodes; i++) {
	if (VECTOR(marked)[i]) {
	  IGRAPH_CHECK(igraph_vector_long_push_back(&components, i));
	}
      }
      IGRAPH_CHECK(igraph_vector_long_push_back(&components, -1));
      no++;
    }

    IGRAPH_STATUSF((" %li new candidates,", 0, no));

    for (i=0; i<no; i++) {
      igraph_vector_t *newmapping;
      igraph_t *newgraph;
      igraph_integer_t maxdeg;

      igraph_vector_clear(&compvertices);
      
      while (1) {
	long int v=VECTOR(components)[cptr++];
	if (v < 0) { break; }
	IGRAPH_CHECK(igraph_vector_push_back(&compvertices, v));
      }
      
      newmapping=igraph_Calloc(1, igraph_vector_t);
      if (!newmapping) {
	IGRAPH_ERROR("Cannot do cohesive blocking", IGRAPH_ENOMEM);
      }
      IGRAPH_FINALLY(igraph_free, newmapping);
      IGRAPH_VECTOR_INIT_FINALLY(newmapping, 0);
      newgraph=igraph_Calloc(1, igraph_t);
      if (!newgraph) { 
	IGRAPH_ERROR("Cannot do cohesive blocking", IGRAPH_ENOMEM);
      }
      IGRAPH_FINALLY(igraph_free, newgraph);
      IGRAPH_CHECK(igraph_induced_subgraph_map(mygraph, newgraph, 
					igraph_vss_vector(&compvertices),
					IGRAPH_SUBGRAPH_AUTO,
					/*map=*/ 0,
					/*invmap=*/ newmapping));
      IGRAPH_FINALLY(igraph_destroy, newgraph);

      IGRAPH_CHECK(igraph_maxdegree(newgraph, &maxdeg, igraph_vss_all(),
				    IGRAPH_ALL, IGRAPH_LOOPS));
      if (maxdeg > VECTOR(Qcohesion)[Qptr]) {
	igraph_integer_t newconn;
	kept++;
	IGRAPH_CHECK(igraph_vector_ptr_push_back(&Q, newgraph));
	IGRAPH_FINALLY_CLEAN(2);
	IGRAPH_CHECK(igraph_vector_ptr_push_back(&Qmapping, newmapping));
	IGRAPH_FINALLY_CLEAN(2);
	IGRAPH_CHECK(igraph_vertex_connectivity(newgraph, &newconn, 
						/*checks=*/ 1));
	IGRAPH_CHECK(igraph_vector_long_push_back(&Qcohesion, newconn));
	IGRAPH_CHECK(igraph_vector_long_push_back(&Qparent, Qptr));
	IGRAPH_CHECK(igraph_vector_bool_push_back(&Qcheck, 
						  mycheck || addedsep));
      } else {
	igraph_destroy(newgraph);
	igraph_free(newgraph);
	igraph_vector_destroy(newmapping);
	igraph_free(newmapping);
	IGRAPH_FINALLY_CLEAN(4);
      }
    }

    IGRAPH_STATUSF((" keeping %li.\n", 0, kept));

    igraph_destroy(mygraph);
    igraph_free(mygraph);
    VECTOR(Q)[Qptr] = 0;
    igraph_i_cohesive_blocks_free3(&separators);
    IGRAPH_FINALLY_CLEAN(1);

    Qptr++;
  }

  igraph_vector_long_destroy(&components);
  igraph_vector_long_destroy(&compid);
  igraph_dqueue_destroy(&bfsQ);
  igraph_vector_destroy(&neis);
  igraph_vector_bool_destroy(&marked);
  igraph_vector_destroy(&compvertices);
  igraph_vector_ptr_destroy(&separators);
  IGRAPH_FINALLY_CLEAN(7);

  if (blocks || cohesion || parent || block_tree) {
    igraph_integer_t noblocks=(igraph_integer_t) Qptr, badblocks=0;
    igraph_vector_bool_t removed;
    long int i, resptr=0;
    igraph_vector_long_t rewritemap;
    
    IGRAPH_CHECK(igraph_vector_bool_init(&removed, noblocks));
    IGRAPH_FINALLY(igraph_vector_bool_destroy, &removed);
    IGRAPH_CHECK(igraph_vector_long_init(&rewritemap, noblocks));
    IGRAPH_FINALLY(igraph_vector_long_destroy, &rewritemap);

    for (i=1; i<noblocks; i++) {
      long int p=VECTOR(Qparent)[i];
      while (VECTOR(removed)[p]) { p=VECTOR(Qparent)[p]; }
      if (VECTOR(Qcohesion)[p] >= VECTOR(Qcohesion)[i]) {
	VECTOR(removed)[i]=1;
	badblocks++;
      }
    }

    /* Rewrite the mappings */
    for (i=1; i<Qptr; i++) {
      long int p=VECTOR(Qparent)[i];
      igraph_vector_t *mapping=VECTOR(Qmapping)[i];
      igraph_vector_t *pmapping=VECTOR(Qmapping)[p];
      long int j, n=igraph_vector_size(mapping);

      if (!pmapping) { continue; }
      for (j=0; j<n; j++) {
	long int v=(long int) VECTOR(*mapping)[j];
	VECTOR(*mapping)[j] = VECTOR(*pmapping)[v];
      }
    }

    /* Because we also put the separator vertices in the queue, it is 
       not ensured that the found blocks are not subsets of each other.
       We check this now. */
    for (i=1; i<noblocks; i++) {
      long int j, ic;
      igraph_vector_t *ivec;
      if (!VECTOR(Qcheck)[i] || VECTOR(removed)[i]) { continue; }
      ivec=VECTOR(Qmapping)[i];
      ic=VECTOR(Qcohesion)[i];
      for (j=1; j<noblocks; j++) {
	igraph_vector_t *jvec;
	long int jc;
	if (j==i || !VECTOR(Qcheck)[j] || VECTOR(removed)[j]) { continue; }
	jvec=VECTOR(Qmapping)[j];
	jc=VECTOR(Qcohesion)[j];
	if (igraph_i_cb_isin(ivec, jvec) && jc >= ic) { 
	  badblocks++; 
	  VECTOR(removed)[i]=1;
	  break;
	}
      }
    }
	  
    noblocks -= badblocks;

    if (blocks) { IGRAPH_CHECK(igraph_vector_ptr_resize(blocks, noblocks)); }
    if (cohesion) { IGRAPH_CHECK(igraph_vector_resize(cohesion, noblocks)); }
    if (parent) { IGRAPH_CHECK(igraph_vector_resize(parent, noblocks)); }

    for (i=0; i<Qptr; i++) {
      if (VECTOR(removed)[i]) { 
	IGRAPH_STATUSF(("Candidate %li ignored.\n", 0, i));
	continue; 
      } else {
	IGRAPH_STATUSF(("Candidate %li is a cohesive (sub)block\n", 0, i));
      }
      VECTOR(rewritemap)[i] = resptr;
      if (cohesion) { VECTOR(*cohesion)[resptr]=VECTOR(Qcohesion)[i]; }
      if (parent || block_tree) {
	long int p=VECTOR(Qparent)[i];
	while (p>=0 && VECTOR(removed)[p]) { p=VECTOR(Qparent)[p]; }
	if (p>=0) { p=VECTOR(rewritemap)[p]; }
	VECTOR(Qparent)[i]=p;
	if (parent) { VECTOR(*parent)[resptr]=p; }
      }
      if (blocks) {
	VECTOR(*blocks)[resptr]=VECTOR(Qmapping)[i];
	VECTOR(Qmapping)[i]=0;
      }
      resptr++;
    }

    /* Plus the original graph */
    if (blocks) {
      igraph_vector_t *orig=igraph_Calloc(1, igraph_vector_t);
      if (!orig) { 
	IGRAPH_ERROR("Cannot do cohesive blocking", IGRAPH_ENOMEM); 
      }
      IGRAPH_FINALLY(igraph_free, orig);
      IGRAPH_CHECK(igraph_vector_init_seq(orig, 0, igraph_vcount(graph)-1));
      VECTOR(*blocks)[0]=orig;
      IGRAPH_FINALLY_CLEAN(1);
    }

    if (block_tree) {
      igraph_vector_t edges;
      long int eptr=0;
      IGRAPH_VECTOR_INIT_FINALLY(&edges, noblocks*2-2);
      for (i=1; i<Qptr; i++) {
	if (VECTOR(removed)[i]) { continue; }
	VECTOR(edges)[eptr++] = VECTOR(Qparent)[i];
	VECTOR(edges)[eptr++] = VECTOR(rewritemap)[i];
      }
      
      IGRAPH_CHECK(igraph_create(block_tree, &edges, noblocks, 
				 IGRAPH_DIRECTED));
      igraph_vector_destroy(&edges);
      IGRAPH_FINALLY_CLEAN(1);
    }

    igraph_vector_long_destroy(&rewritemap);
    igraph_vector_bool_destroy(&removed);
    IGRAPH_FINALLY_CLEAN(2);

  }

  igraph_vector_bool_destroy(&Qcheck);
  igraph_vector_long_destroy(&Qcohesion);
  igraph_vector_long_destroy(&Qparent);
  igraph_i_cohesive_blocks_free2(&Qmapping);
  IGRAPH_FINALLY_CLEAN(4);
  
  igraph_vector_ptr_destroy(&Qmapping);
  igraph_vector_ptr_destroy(&Q);
  IGRAPH_FINALLY_CLEAN(3);  	/* + the elements of Q, they were
				   already destroyed */

  IGRAPH_STATUS("Cohesive blocking done.\n", 0);

  return 0;
}
示例#28
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;
}