예제 #1
0
파일: scan.c 프로젝트: abeham/igraph
int igraph_i_local_scan_1_directed(const igraph_t *graph,
				   igraph_vector_t *res,
				   const igraph_vector_t *weights,
				   igraph_neimode_t mode) {

  int no_of_nodes=igraph_vcount(graph);
  igraph_inclist_t incs;
  int i, node;

  igraph_vector_int_t neis;

  IGRAPH_CHECK(igraph_inclist_init(graph, &incs, mode));
  IGRAPH_FINALLY(igraph_inclist_destroy, &incs);

  igraph_vector_int_init(&neis, no_of_nodes);
  IGRAPH_FINALLY(igraph_vector_int_destroy, &neis);

  igraph_vector_resize(res, no_of_nodes);
  igraph_vector_null(res);

  for (node=0; node < no_of_nodes; node++) {
    igraph_vector_int_t *edges1=igraph_inclist_get(&incs, node);
    int edgeslen1=igraph_vector_int_size(edges1);

    IGRAPH_ALLOW_INTERRUPTION();

    /* Mark neighbors and self*/
    VECTOR(neis)[node] = node+1;
    for (i=0; i<edgeslen1; i++) {
      int e=VECTOR(*edges1)[i];
      int nei=IGRAPH_OTHER(graph, e, node);
      igraph_real_t w= weights ? VECTOR(*weights)[e] : 1;
      VECTOR(neis)[nei] = node+1;
      VECTOR(*res)[node] += w;
    }

    /* Crawl neighbors */
    for (i=0; i<edgeslen1; i++) {
      int e2=VECTOR(*edges1)[i];
      int nei=IGRAPH_OTHER(graph, e2, node);
      igraph_vector_int_t *edges2=igraph_inclist_get(&incs, nei);
      int j, edgeslen2=igraph_vector_int_size(edges2);
      for (j=0; j<edgeslen2; j++) {
	int e2=VECTOR(*edges2)[j];
	int nei2=IGRAPH_OTHER(graph, e2, nei);
	igraph_real_t w2= weights ? VECTOR(*weights)[e2] : 1;
	if (VECTOR(neis)[nei2] == node+1) {
	  VECTOR(*res)[node] += w2;
	}
      }
    }

  } /* node < no_of_nodes */

  igraph_vector_int_destroy(&neis);
  igraph_inclist_destroy(&incs);
  IGRAPH_FINALLY_CLEAN(2);

  return 0;
}
예제 #2
0
int igraph_i_maximal_cliques_select_pivot(const igraph_vector_int_t *PX,
					  int PS, int PE, int XS, int XE,
					  const igraph_vector_int_t *pos,
					  const igraph_adjlist_t *adjlist,
					  int *pivot,
					  igraph_vector_int_t *nextv,
					  int oldPS, int oldXE) {
  igraph_vector_int_t *pivotvectneis;
  int i, pivotvectlen, j, usize=-1;
  int soldPS=oldPS+1, soldXE=oldXE+1, sPS=PS+1, sPE=PE+1;

  /* Choose a pivotvect, and bring up P vertices at the same time */
  for (i=PS; i<=XE; i++) {
    int av=VECTOR(*PX)[i];
    igraph_vector_int_t *avneis=igraph_adjlist_get(adjlist, av);
    int *avp=VECTOR(*avneis);
    int avlen=igraph_vector_int_size(avneis);
    int *ave=avp+avlen;
    int *avnei=avp, *pp=avp;

    for (; avnei < ave; avnei++) {
      int avneipos=VECTOR(*pos)[(int)(*avnei)];
      if (avneipos < soldPS || avneipos > soldXE) { break; }
      if (avneipos >= sPS && avneipos <= sPE) {
	if (pp != avnei) {
	  int tmp=*avnei;
	  *avnei = *pp;
	  *pp = tmp;
	}
	pp++;
      }
    }
    if ((j=pp-avp) > usize) { *pivot = av; usize=j; }
  }

  igraph_vector_int_push_back(nextv, -1);
  pivotvectneis=igraph_adjlist_get(adjlist, *pivot);
  pivotvectlen=igraph_vector_int_size(pivotvectneis);

  for (j=PS; j <= PE; j++) {
    int vcand=VECTOR(*PX)[j];
    igraph_bool_t nei=0;
    int k=0;
    for (k=0; k < pivotvectlen; k++) {
      int unv=VECTOR(*pivotvectneis)[k];
      int unvpos=VECTOR(*pos)[unv];
      if (unvpos < sPS || unvpos > sPE) { break; }
      if (unv == vcand) { nei=1; break; }
    }
    if (!nei) { igraph_vector_int_push_back(nextv, vcand); }
  }

  return 0;
}
예제 #3
0
파일: components.c 프로젝트: igraph/igraph
static int igraph_i_bridges_rec(const igraph_t *graph, const igraph_inclist_t *il, igraph_integer_t u, igraph_integer_t *time, igraph_vector_t *bridges, igraph_vector_bool_t *visited, igraph_vector_int_t *disc, igraph_vector_int_t *low, igraph_vector_int_t *parent) {
    igraph_vector_int_t *incedges;
    long nc; /* neighbour count */
    long i;

    VECTOR(*visited)[u] = 1;

    *time += 1;

    VECTOR(*disc)[u] = *time;
    VECTOR(*low)[u] = *time;

    incedges = igraph_inclist_get(il, u);
    nc = igraph_vector_int_size(incedges);
    for (i=0; i < nc; ++i) {
        long edge = (long) VECTOR(*incedges)[i];
        igraph_integer_t v = IGRAPH_TO(graph, edge) == u ? IGRAPH_FROM(graph, edge) : IGRAPH_TO(graph, edge);

        if (! VECTOR(*visited)[v]) {
            VECTOR(*parent)[v] = u;
            IGRAPH_CHECK(igraph_i_bridges_rec(graph, il, v, time, bridges, visited, disc, low, parent));

            VECTOR(*low)[u] = VECTOR(*low)[u] < VECTOR(*low)[v] ? VECTOR(*low)[u] : VECTOR(*low)[v];

            if (VECTOR(*low)[v] > VECTOR(*disc)[u])
                IGRAPH_CHECK(igraph_vector_push_back(bridges, edge));
        }
        else if (v != VECTOR(*parent)[u]) {
            VECTOR(*low)[u] = VECTOR(*low)[u] < VECTOR(*disc)[v] ? VECTOR(*low)[u] : VECTOR(*disc)[v];
        }
    }

    return IGRAPH_SUCCESS;
}
예제 #4
0
int igraph_i_maximal_cliques_reorder_adjlists(
			      const igraph_vector_int_t *PX,
			      int PS, int PE, int XS, int XE,
			      const igraph_vector_int_t *pos,
			      igraph_adjlist_t *adjlist) {
  int j;
  int sPS=PS+1, sPE=PE+1;

  for (j=PS; j<=XE; j++) {
    int av=VECTOR(*PX)[j];
    igraph_vector_int_t *avneis=igraph_adjlist_get(adjlist, av);
    int *avp=VECTOR(*avneis);
    int avlen=igraph_vector_int_size(avneis);
    int *ave=avp+avlen;
    int *avnei=avp, *pp=avp;

    for (; avnei < ave; avnei++) {
      int avneipos=VECTOR(*pos)[(int)(*avnei)];
      if (avneipos >= sPS && avneipos <= sPE) {
	if (pp != avnei) {
	  int tmp=*avnei;
	  *avnei = *pp;
	  *pp = tmp;
	}
	pp++;
      }
    }
  }
  return 0;
}
예제 #5
0
파일: scan.c 프로젝트: abeham/igraph
int igraph_i_trans4_il_simplify(const igraph_t *graph, igraph_inclist_t *il,
				const igraph_vector_int_t *rank) {

  long int i;
  long int n=il->length;
  igraph_vector_int_t mark;
  igraph_vector_int_init(&mark, n);
  IGRAPH_FINALLY(igraph_vector_int_destroy, &mark);

  for (i=0; i<n; i++) {
    igraph_vector_int_t *v=&il->incs[i];
    int j, l=igraph_vector_int_size(v);
    int irank=VECTOR(*rank)[i];
    VECTOR(mark)[i] = i+1;
    for (j=0; j<l; /* nothing */) {
      long int edge=(long int) VECTOR(*v)[j];
      long int e=IGRAPH_OTHER(graph, edge, i);
      if (VECTOR(*rank)[e] > irank && VECTOR(mark)[e] != i+1) {
	VECTOR(mark)[e]=i+1;
	j++;
      } else {
	VECTOR(*v)[j] = igraph_vector_int_tail(v);
	igraph_vector_int_pop_back(v);
	l--;
      }
    }
  }

  igraph_vector_int_destroy(&mark);
  IGRAPH_FINALLY_CLEAN(1);
  return 0;

}
예제 #6
0
int igraph_i_maximal_cliques_down(igraph_vector_int_t *PX,
				  int PS, int PE, int XS, int XE,
				  igraph_vector_int_t *pos, 
				  igraph_adjlist_t *adjlist, int mynextv, 
				  igraph_vector_int_t *R, 
				  int *newPS, int *newXE) {

  igraph_vector_int_t *vneis=igraph_adjlist_get(adjlist, mynextv);
  int j, vneislen=igraph_vector_int_size(vneis);
  int sPS=PS+1, sPE=PE+1, sXS=XS+1, sXE=XE+1;

  *newPS=PE+1; *newXE=XS-1;
  for (j=0; j<vneislen; j++) {
    int vnei=VECTOR(*vneis)[j];
    int vneipos=VECTOR(*pos)[vnei];
    if (vneipos >= sPS && vneipos <= sPE) {
      (*newPS)--;
      SWAP(vneipos-1, *newPS);
    } else if (vneipos >= sXS && vneipos <= sXE) {
      (*newXE)++;
      SWAP(vneipos-1, *newXE);
    }
  }

  igraph_vector_int_push_back(R, mynextv);
  
  return 0;
}
예제 #7
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;
}
예제 #8
0
int igraph_i_maximal_or_largest_cliques_or_indsets(const igraph_t *graph,
                                        igraph_vector_ptr_t *res,
                                        igraph_integer_t *clique_number,
                                        igraph_bool_t keep_only_largest,
                                        igraph_bool_t complementer) {
  igraph_i_max_ind_vsets_data_t clqdata;
  igraph_integer_t no_of_nodes = (igraph_integer_t) igraph_vcount(graph), i;

  if (igraph_is_directed(graph))
    IGRAPH_WARNING("directionality of edges is ignored for directed graphs");

  clqdata.matrix_size=no_of_nodes;
  clqdata.keep_only_largest=keep_only_largest;

  if (complementer)
    IGRAPH_CHECK(igraph_adjlist_init_complementer(graph, &clqdata.adj_list, IGRAPH_ALL, 0));
  else
    IGRAPH_CHECK(igraph_adjlist_init(graph, &clqdata.adj_list, IGRAPH_ALL));
  IGRAPH_FINALLY(igraph_adjlist_destroy, &clqdata.adj_list);

  clqdata.IS = igraph_Calloc(no_of_nodes, igraph_integer_t);
  if (clqdata.IS == 0)
    IGRAPH_ERROR("igraph_i_maximal_or_largest_cliques_or_indsets failed", IGRAPH_ENOMEM);
  IGRAPH_FINALLY(igraph_free, clqdata.IS);

  IGRAPH_VECTOR_INIT_FINALLY(&clqdata.deg, no_of_nodes);
  for (i=0; i<no_of_nodes; i++)
    VECTOR(clqdata.deg)[i] = igraph_vector_int_size(igraph_adjlist_get(&clqdata.adj_list, i));

  clqdata.buckets = igraph_Calloc(no_of_nodes+1, igraph_set_t);
  if (clqdata.buckets == 0)
    IGRAPH_ERROR("igraph_maximal_or_largest_cliques_or_indsets failed", IGRAPH_ENOMEM);
  IGRAPH_FINALLY(igraph_i_free_set_array, clqdata.buckets);

  for (i=0; i<no_of_nodes; i++)
    IGRAPH_CHECK(igraph_set_init(&clqdata.buckets[i], 0));

  if (res) igraph_vector_ptr_clear(res);
  
  /* Do the show */
  clqdata.largest_set_size=0;
  IGRAPH_CHECK(igraph_i_maximal_independent_vertex_sets_backtrack(graph, res, &clqdata, 0));

  /* Cleanup */
  for (i=0; i<no_of_nodes; i++) igraph_set_destroy(&clqdata.buckets[i]);
  igraph_adjlist_destroy(&clqdata.adj_list);
  igraph_vector_destroy(&clqdata.deg);
  igraph_free(clqdata.IS);
  igraph_free(clqdata.buckets);
  IGRAPH_FINALLY_CLEAN(4);

  if (clique_number) *clique_number = clqdata.largest_set_size;
  return 0;
}
예제 #9
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;
}
예제 #10
0
파일: eigen.c 프로젝트: AlessiaWent/igraph
int igraph_i_eigen_adjacency_arpack_sym_cb(igraph_real_t *to,
					   const igraph_real_t *from,
					   int n, void *extra) {
  igraph_adjlist_t *adjlist = (igraph_adjlist_t *) extra;
  igraph_vector_int_t *neis;
  int i, j, nlen;

  for (i=0; i<n; i++) {
    neis=igraph_adjlist_get(adjlist, i);
    nlen=igraph_vector_int_size(neis);
    to[i] = 0.0;
    for (j=0; j<nlen; j++) {
      int nei = VECTOR(*neis)[j];
      to[i] += from[nei];
    }
  }

  return 0;
}
예제 #11
0
파일: scan.c 프로젝트: abeham/igraph
int igraph_local_scan_k_ecount_them(const igraph_t *us, const igraph_t *them,
				    int k, igraph_vector_t *res,
				    const igraph_vector_t *weights_them,
				    igraph_neimode_t mode) {

  int no_of_nodes=igraph_vcount(us);
  int node;
  igraph_dqueue_int_t Q;
  igraph_vector_int_t marked;
  igraph_stack_int_t ST;
  igraph_inclist_t incs_us, incs_them;

  if (igraph_vcount(them) != no_of_nodes) {
    IGRAPH_ERROR("Number of vertices must match in scan-k", IGRAPH_EINVAL);
  }
  if (igraph_is_directed(us) != igraph_is_directed(them)) {
    IGRAPH_ERROR("Directedness must match in scan-k", IGRAPH_EINVAL);
  }
  if (k < 0) {
    IGRAPH_ERROR("k must be non-negative in k-scan", IGRAPH_EINVAL);
  }
  if (weights_them &&
      igraph_vector_size(weights_them) != igraph_ecount(them)) {
    IGRAPH_ERROR("Invalid weight vector length in k-scan (them)",
		 IGRAPH_EINVAL);
  }

  if (k==0) {
    return igraph_local_scan_0_them(us, them, res, weights_them, mode);
  }
  if (k==1) {
    return igraph_local_scan_1_ecount_them(us, them, res, weights_them, mode);
  }

  /* We mark the nodes in US in a BFS. Then we check the outgoing edges
     of all marked nodes in THEM. */

  IGRAPH_CHECK(igraph_dqueue_int_init(&Q, 100));
  IGRAPH_FINALLY(igraph_dqueue_int_destroy, &Q);
  IGRAPH_CHECK(igraph_vector_int_init(&marked, no_of_nodes));
  IGRAPH_FINALLY(igraph_vector_int_destroy, &marked);
  IGRAPH_CHECK(igraph_inclist_init(us, &incs_us, mode));
  IGRAPH_FINALLY(igraph_inclist_destroy, &incs_us);
  IGRAPH_CHECK(igraph_inclist_init(them, &incs_them, mode));
  IGRAPH_FINALLY(igraph_inclist_destroy, &incs_them);
  IGRAPH_CHECK(igraph_stack_int_init(&ST, 100));
  IGRAPH_FINALLY(igraph_stack_int_destroy, &ST);

  IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes));
  igraph_vector_null(res);

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

    /* BFS to mark the nodes in US */
    IGRAPH_CHECK(igraph_dqueue_int_push(&Q, node));
    IGRAPH_CHECK(igraph_dqueue_int_push(&Q, 0));
    IGRAPH_CHECK(igraph_stack_int_push(&ST, node));
    VECTOR(marked)[node] = node+1;
    while (!igraph_dqueue_int_empty(&Q)) {
      int act=igraph_dqueue_int_pop(&Q);
      int dist=igraph_dqueue_int_pop(&Q) + 1;
      igraph_vector_int_t *edges=igraph_inclist_get(&incs_us, act);
      int i, edgeslen=igraph_vector_int_size(edges);
      for (i=0; i<edgeslen; i++) {
	int edge=VECTOR(*edges)[i];
	int nei=IGRAPH_OTHER(us, edge, act);
	if (dist <= k && VECTOR(marked)[nei] != node+1) {
	  igraph_dqueue_int_push(&Q, nei);
	  igraph_dqueue_int_push(&Q, dist);
	  VECTOR(marked)[nei] = node+1;
	  igraph_stack_int_push(&ST, nei);
	}
      }
    }

    /* Now check the edges of all nodes in THEM */
    while (!igraph_stack_int_empty(&ST)) {
      int act=igraph_stack_int_pop(&ST);
      igraph_vector_int_t *edges=igraph_inclist_get(&incs_them, act);
      int i, edgeslen=igraph_vector_int_size(edges);
      for (i=0; i<edgeslen; i++) {
	int edge=VECTOR(*edges)[i];
	int nei=IGRAPH_OTHER(them, edge, act);
	if (VECTOR(marked)[nei] == node+1) {
	  igraph_real_t w=weights_them ? VECTOR(*weights_them)[edge] : 1;
	  VECTOR(*res)[node] += w;
	}
      }
    }

    if (mode == IGRAPH_ALL || ! igraph_is_directed(us)) {
      VECTOR(*res)[node] /= 2;
    }

  } /* node < no_of_nodes */

  igraph_stack_int_destroy(&ST);
  igraph_inclist_destroy(&incs_them);
  igraph_inclist_destroy(&incs_us);
  igraph_vector_int_destroy(&marked);
  igraph_dqueue_int_destroy(&Q);
  IGRAPH_FINALLY_CLEAN(5);

  return 0;
}
예제 #12
0
파일: scan.c 프로젝트: abeham/igraph
int igraph_local_scan_k_ecount(const igraph_t *graph, int k,
			       igraph_vector_t *res,
			       const igraph_vector_t *weights,
			       igraph_neimode_t mode) {

  int no_of_nodes=igraph_vcount(graph);
  int node;
  igraph_dqueue_int_t Q;
  igraph_vector_int_t marked;
  igraph_inclist_t incs;

  if (k < 0) {
    IGRAPH_ERROR("k must be non-negative in k-scan", IGRAPH_EINVAL);
  }
  if (weights && igraph_vector_size(weights) != igraph_ecount(graph)) {
    IGRAPH_ERROR("Invalid weight vector length in k-scan", IGRAPH_EINVAL);
  }

  if (k==0) { return igraph_local_scan_0(graph, res, weights, mode); }
  if (k==1) { return igraph_local_scan_1_ecount(graph, res, weights, mode); }

  /* We do a BFS form each node, and simply count the number
     of edges on the way */

  IGRAPH_CHECK(igraph_dqueue_int_init(&Q, 100));
  IGRAPH_FINALLY(igraph_dqueue_int_destroy, &Q);
  IGRAPH_CHECK(igraph_vector_int_init(&marked, no_of_nodes));
  IGRAPH_FINALLY(igraph_vector_int_destroy, &marked);
  IGRAPH_CHECK(igraph_inclist_init(graph, &incs, mode));
  IGRAPH_FINALLY(igraph_inclist_destroy, &incs);

  IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes));
  igraph_vector_null(res);

  for (node=0 ; node < no_of_nodes ; node++) {
    igraph_dqueue_int_push(&Q, node);
    igraph_dqueue_int_push(&Q, 0);
    VECTOR(marked)[node] = node+1;
    while (!igraph_dqueue_int_empty(&Q)) {
      int act=igraph_dqueue_int_pop(&Q);
      int dist=igraph_dqueue_int_pop(&Q) + 1;
      igraph_vector_int_t *edges=igraph_inclist_get(&incs, act);
      int i, edgeslen=igraph_vector_int_size(edges);
      for (i=0; i<edgeslen; i++) {
	int edge=VECTOR(*edges)[i];
	int nei=IGRAPH_OTHER(graph, edge, act);
	if (dist <= k || VECTOR(marked)[nei] == node+1) {
	  igraph_real_t w=weights ? VECTOR(*weights)[edge] : 1;
	  VECTOR(*res)[node] += w;
	}
	if (dist <= k && VECTOR(marked)[nei] != node+1) {
	  igraph_dqueue_int_push(&Q, nei);
	  igraph_dqueue_int_push(&Q, dist);
	  VECTOR(marked)[nei] = node+1;
	}
      }
    }

    if (mode == IGRAPH_ALL || ! igraph_is_directed(graph)) {
      VECTOR(*res)[node] /= 2.0;
    }

  } /* node < no_of_nodes */

  igraph_inclist_destroy(&incs);
  igraph_vector_int_destroy(&marked);
  igraph_dqueue_int_destroy(&Q);
  IGRAPH_FINALLY_CLEAN(3);

  return 0;
}
예제 #13
0
파일: scan.c 프로젝트: abeham/igraph
int igraph_local_scan_1_ecount_them(const igraph_t *us, const igraph_t *them,
				    igraph_vector_t *res,
				    const igraph_vector_t *weights_them,
				    igraph_neimode_t mode) {

  int no_of_nodes=igraph_vcount(us);
  igraph_adjlist_t adj_us;
  igraph_inclist_t incs_them;
  igraph_vector_int_t neis;
  int node;

  if (igraph_vcount(them) != no_of_nodes) {
    IGRAPH_ERROR("Number of vertices must match in scan-1", IGRAPH_EINVAL);
  }
  if (igraph_is_directed(us) != igraph_is_directed(them)) {
    IGRAPH_ERROR("Directedness must match in scan-1", IGRAPH_EINVAL);
  }
  if (weights_them &&
      igraph_vector_size(weights_them) != igraph_ecount(them)) {
    IGRAPH_ERROR("Invalid weight vector length in scan-1 (them)",
		 IGRAPH_EINVAL);
  }

  igraph_adjlist_init(us, &adj_us, mode);
  IGRAPH_FINALLY(igraph_adjlist_destroy, &adj_us);
  igraph_adjlist_simplify(&adj_us);
  igraph_inclist_init(them, &incs_them, mode);
  IGRAPH_FINALLY(igraph_inclist_destroy, &incs_them);

  igraph_vector_int_init(&neis, no_of_nodes);
  IGRAPH_FINALLY(igraph_vector_int_destroy, &neis);

  igraph_vector_resize(res, no_of_nodes);
  igraph_vector_null(res);

  for (node=0; node < no_of_nodes; node++) {
    igraph_vector_int_t *neis_us=igraph_adjlist_get(&adj_us, node);
    igraph_vector_int_t *edges1_them=igraph_inclist_get(&incs_them, node);
    int len1_us=igraph_vector_int_size(neis_us);
    int len1_them=igraph_vector_int_size(edges1_them);
    int i;

    IGRAPH_ALLOW_INTERRUPTION();

    /* Mark neighbors and self in us */
    VECTOR(neis)[node] = node+1;
    for (i = 0; i < len1_us; i++) {
      int nei=VECTOR(*neis_us)[i];
      VECTOR(neis)[nei] = node+1;
    }

    /* Crawl neighbors in them, first ego */
    for (i = 0; i < len1_them; i++) {
      int e=VECTOR(*edges1_them)[i];
      int nei=IGRAPH_OTHER(them, e, node);
      if (VECTOR(neis)[nei] == node+1) {
	igraph_real_t w=weights_them ? VECTOR(*weights_them)[e] : 1;
	VECTOR(*res)[node] += w;
      }
    }
    /* Then the rest */
    for (i = 0; i < len1_us; i++) {
      int nei=VECTOR(*neis_us)[i];
      igraph_vector_int_t *edges2_them=igraph_inclist_get(&incs_them, nei);
      int j, len2_them=igraph_vector_int_size(edges2_them);
      for (j = 0; j < len2_them; j++) {
	int e2=VECTOR(*edges2_them)[j];
	int nei2=IGRAPH_OTHER(them, e2, nei);
	if (VECTOR(neis)[nei2] == node+1) {
	  igraph_real_t w=weights_them ? VECTOR(*weights_them)[e2] : 1;
	  VECTOR(*res)[node] += w;
	}
      }
    }

    /* For undirected, it was double counted */
    if (mode == IGRAPH_ALL || ! igraph_is_directed(us)) {
      VECTOR(*res)[node] /= 2.0;
    }

  } /* node < no_of_nodes */

  igraph_vector_int_destroy(&neis);
  igraph_inclist_destroy(&incs_them);
  igraph_adjlist_destroy(&adj_us);
  IGRAPH_FINALLY_CLEAN(3);

  return 0;
}
예제 #14
0
파일: scan.c 프로젝트: abeham/igraph
int igraph_i_local_scan_1_sumweights(const igraph_t *graph,
				     igraph_vector_t *res,
				     const igraph_vector_t *weights) {

  long int no_of_nodes=igraph_vcount(graph);
  long int node, i, j, nn;
  igraph_inclist_t allinc;
  igraph_vector_int_t *neis1, *neis2;
  long int neilen1, neilen2;
  long int *neis;
  long int maxdegree;

  igraph_vector_int_t order;
  igraph_vector_int_t rank;
  igraph_vector_t degree, *edge1=&degree; /* reuse degree as edge1 */

  if (igraph_vector_size(weights) != igraph_ecount(graph)) {
    IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
  }

  igraph_vector_int_init(&order, no_of_nodes);
  IGRAPH_FINALLY(igraph_vector_int_destroy, &order);
  IGRAPH_VECTOR_INIT_FINALLY(&degree, no_of_nodes);

  IGRAPH_CHECK(igraph_degree(graph, &degree, igraph_vss_all(), IGRAPH_ALL,
			     IGRAPH_LOOPS));
  maxdegree=(long int) igraph_vector_max(&degree)+1;
  igraph_vector_order1_int(&degree, &order, maxdegree);
  igraph_vector_int_init(&rank, no_of_nodes);
  IGRAPH_FINALLY(igraph_vector_int_destroy, &rank);
  for (i=0; i<no_of_nodes; i++) {
    VECTOR(rank)[ VECTOR(order)[i] ] = no_of_nodes-i-1;
  }

  IGRAPH_CHECK(igraph_inclist_init(graph, &allinc, IGRAPH_ALL));
  IGRAPH_FINALLY(igraph_inclist_destroy, &allinc);
  IGRAPH_CHECK(igraph_i_trans4_il_simplify(graph, &allinc, &rank));

  neis=igraph_Calloc(no_of_nodes, long int);
  if (neis==0) {
    IGRAPH_ERROR("undirected local transitivity failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, neis);

  IGRAPH_CHECK(igraph_strength(graph, res, igraph_vss_all(), IGRAPH_ALL,
			       IGRAPH_LOOPS, weights));

  for (nn=no_of_nodes-1; nn>=0; nn--) {
    node=VECTOR(order)[nn];

    IGRAPH_ALLOW_INTERRUPTION();

    neis1=igraph_inclist_get(&allinc, node);
    neilen1=igraph_vector_int_size(neis1);

    /* Mark the neighbors of the node */
    for (i=0; i<neilen1; i++) {
      int edge = VECTOR(*neis1)[i];
      int nei = IGRAPH_OTHER(graph, edge, node);
      VECTOR(*edge1)[nei] = VECTOR(*weights)[edge];
      neis[nei] = node+1;
    }

    for (i=0; i<neilen1; i++) {
      long int edge=VECTOR(*neis1)[i];
      long int nei=IGRAPH_OTHER(graph, edge, node);
      igraph_real_t w=VECTOR(*weights)[edge];
      neis2=igraph_inclist_get(&allinc, nei);
      neilen2=igraph_vector_int_size(neis2);
      for (j=0; j<neilen2; j++) {
	long int edge2=VECTOR(*neis2)[j];
	long int nei2=IGRAPH_OTHER(graph, edge2, nei);
	igraph_real_t w2=VECTOR(*weights)[edge2];
	if (neis[nei2] == node+1) {
	  VECTOR(*res)[node] += w2;
	  VECTOR(*res)[nei2] += w;
	  VECTOR(*res)[nei] += VECTOR(*edge1)[nei2];
	}
      }
    }
  }

  igraph_free(neis);
  igraph_inclist_destroy(&allinc);
  igraph_vector_int_destroy(&rank);
  igraph_vector_destroy(&degree);
  igraph_vector_int_destroy(&order);
  IGRAPH_FINALLY_CLEAN(5);

  return 0;
}
예제 #15
0
파일: scan.c 프로젝트: abeham/igraph
int igraph_i_local_scan_1_directed_all(const igraph_t *graph,
				       igraph_vector_t *res,
				       const igraph_vector_t *weights) {

  int no_of_nodes=igraph_vcount(graph);
  igraph_inclist_t incs;
  int i, node;

  igraph_vector_int_t neis;

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

  igraph_vector_int_init(&neis, no_of_nodes);
  IGRAPH_FINALLY(igraph_vector_int_destroy, &neis);

  igraph_vector_resize(res, no_of_nodes);
  igraph_vector_null(res);

  for (node=0; node < no_of_nodes; node++) {
    igraph_vector_int_t *edges1=igraph_inclist_get(&incs, node);
    int edgeslen1=igraph_vector_int_size(edges1);

    IGRAPH_ALLOW_INTERRUPTION();

    /* Mark neighbors. We also count the edges that are incident to ego.
       Note that this time we do not mark ego, because we don't want to
       double count its incident edges later, when we are going over the
       incident edges of ego's neighbors. */
    for (i=0; i<edgeslen1; i++) {
      int e=VECTOR(*edges1)[i];
      int nei=IGRAPH_OTHER(graph, e, node);
      igraph_real_t w= weights ? VECTOR(*weights)[e] : 1;
      VECTOR(neis)[nei] = node+1;
      VECTOR(*res)[node] += w;
    }

    /* Crawl neighbors. We make sure that each neighbor of 'node' is
       only crawed once. We count all qualifying edges of ego, and
       then unmark ego to avoid double counting. */
    for (i=0; i<edgeslen1; i++) {
      int e2=VECTOR(*edges1)[i];
      int nei=IGRAPH_OTHER(graph, e2, node);
      igraph_vector_int_t *edges2;
      int j, edgeslen2;
      if (VECTOR(neis)[nei] != node+1) { continue; }
      edges2=igraph_inclist_get(&incs, nei);
      edgeslen2=igraph_vector_int_size(edges2);
      for (j=0; j<edgeslen2; j++) {
	int e2=VECTOR(*edges2)[j];
	int nei2=IGRAPH_OTHER(graph, e2, nei);
	igraph_real_t w2= weights ? VECTOR(*weights)[e2] : 1;
	if (VECTOR(neis)[nei2] == node+1) {
	  VECTOR(*res)[node] += w2;
	}
      }
      VECTOR(neis)[nei] = 0;
    }

  } /* node < no_of_nodes */

  igraph_vector_int_destroy(&neis);
  igraph_inclist_destroy(&incs);
  IGRAPH_FINALLY_CLEAN(2);

  return 0;
}
예제 #16
0
파일: coloring.c 프로젝트: cran/igraph
int igraph_i_vertex_coloring_greedy_cn(const igraph_t *graph, igraph_vector_int_t *colors) {
    long i, vertex, maxdeg;
    long vc = igraph_vcount(graph);
    igraph_2wheap_t cn; /* indexed heap storing number of already coloured neighbours */
    igraph_vector_int_t neigh_colors;
    igraph_adjlist_t adjlist;

    IGRAPH_CHECK(igraph_vector_int_resize(colors, vc));
    igraph_vector_int_fill(colors, 0);

    /* Nothing to do for 0 or 1 vertices.
     * Remember that colours are integers starting from 0,
     * and the 'colors' vector is already 0-initialized above.
     */
    if (vc <= 1)
        return IGRAPH_SUCCESS;

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

    /* find maximum degree and a corresponding vertex */
    {
        igraph_vector_t degree;

        IGRAPH_CHECK(igraph_vector_init(&degree, 0));
        IGRAPH_FINALLY(igraph_vector_destroy, &degree);
        IGRAPH_CHECK(igraph_degree(graph, &degree, igraph_vss_all(), IGRAPH_ALL, 0));

        vertex = igraph_vector_which_max(&degree);
        maxdeg = VECTOR(degree)[vertex];

        igraph_vector_destroy(&degree);
        IGRAPH_FINALLY_CLEAN(1);
    }

    IGRAPH_CHECK(igraph_vector_int_init(&neigh_colors, 0));
    IGRAPH_CHECK(igraph_vector_int_reserve(&neigh_colors, maxdeg));
    IGRAPH_FINALLY(igraph_vector_int_destroy, &neigh_colors);

    IGRAPH_CHECK(igraph_2wheap_init(&cn, vc));
    IGRAPH_FINALLY(igraph_2wheap_destroy, &cn);
    for (i=0; i < vc; ++i)
        if (i != vertex)
            igraph_2wheap_push_with_index(&cn, i, 0); /* should not fail since memory was already reserved */

    while (1) {
        igraph_vector_int_t *neighbors = igraph_adjlist_get(&adjlist, vertex);
        long neigh_count = igraph_vector_int_size(neighbors);

        /* colour current vertex */
        {
            igraph_integer_t col;

            IGRAPH_CHECK(igraph_vector_int_resize(&neigh_colors, neigh_count));
            for (i=0; i < neigh_count; ++i)
                VECTOR(neigh_colors)[i] = VECTOR(*colors)[ VECTOR(*neighbors)[i] ];
            igraph_vector_int_sort(&neigh_colors);

            i=0;
            col = 0;
            do {
                while (i < neigh_count && VECTOR(neigh_colors)[i] == col)
                    i++;
                col++;
            } while (i < neigh_count && VECTOR(neigh_colors)[i] == col);

            VECTOR(*colors)[vertex] = col;
        }

        /* increment number of coloured neighbours for each neighbour of vertex */
        for (i=0; i < neigh_count; ++i) {
            long idx = VECTOR(*neighbors)[i];
            if (igraph_2wheap_has_elem(&cn, idx))
                igraph_2wheap_modify(&cn, idx, igraph_2wheap_get(&cn, idx) + 1);
        }

        /* stop if no more vertices left to colour */
        if (igraph_2wheap_empty(&cn))
            break;

        igraph_2wheap_delete_max_index(&cn, &vertex);

        IGRAPH_ALLOW_INTERRUPTION();
    }

    /* subtract 1 from each colour value, so that colours start at 0 */
    igraph_vector_int_add_constant(colors, -1);

    /* free data structures */
    igraph_vector_int_destroy(&neigh_colors);
    igraph_adjlist_destroy(&adjlist);
    igraph_2wheap_destroy(&cn);
    IGRAPH_FINALLY_CLEAN(3);

    return IGRAPH_SUCCESS;
}
예제 #17
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;
}
예제 #18
0
int igraph_all_minimal_st_separators(const igraph_t *graph, 
				     igraph_vector_ptr_t *separators) {

  /* 
   * Some notes about the tricks used here. For finding the components
   * of the graph after removing some vertices, we do the
   * following. First we mark the vertices with the actual mark stamp
   * (mark), then run breadth-first search on the graph, but not
   * considering the marked vertices. Then we increase the mark. If
   * there is integer overflow here, then we zero out the mark and set
   * it to one. (We might as well just always zero it out.)
   * 
   * For each separator the vertices are stored in vertex id order. 
   * This facilitates the comparison of the separators when we find a
   * potential new candidate. 
   * 
   * To keep track of which separator we already used as a basis, we
   * keep a boolean vector (already_tried). The try_next pointer show
   * the next separator to try as a basis.
   */

  long int no_of_nodes=igraph_vcount(graph);
  igraph_vector_t leaveout;
  igraph_vector_bool_t already_tried;
  long int try_next=0;
  unsigned long int mark=1;
  long int v;
  
  igraph_adjlist_t adjlist;
  igraph_vector_t components;
  igraph_dqueue_t Q;
  igraph_vector_t sorter;

  igraph_vector_ptr_clear(separators);
  IGRAPH_FINALLY(igraph_i_separators_free, separators);

  IGRAPH_CHECK(igraph_vector_init(&leaveout, no_of_nodes));
  IGRAPH_FINALLY(igraph_vector_destroy, &leaveout);
  IGRAPH_CHECK(igraph_vector_bool_init(&already_tried, 0));
  IGRAPH_FINALLY(igraph_vector_bool_destroy, &already_tried);
  IGRAPH_CHECK(igraph_vector_init(&components, 0));
  IGRAPH_FINALLY(igraph_vector_destroy, &components);
  IGRAPH_CHECK(igraph_vector_reserve(&components, no_of_nodes*2));
  IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL));
  IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
  IGRAPH_CHECK(igraph_dqueue_init(&Q, 100));
  IGRAPH_FINALLY(igraph_dqueue_destroy, &Q);
  IGRAPH_CHECK(igraph_vector_init(&sorter, 0));
  IGRAPH_FINALLY(igraph_vector_destroy, &sorter);
  IGRAPH_CHECK(igraph_vector_reserve(&sorter, no_of_nodes));
  
  /* --------------------------------------------------------------- 
   * INITIALIZATION, we check whether the neighborhoods of the 
   * vertices separate the graph. The ones that do will form the 
   * initial basis.
   */
  
  for (v=0; v<no_of_nodes; v++) {

    /* Mark v and its neighbors */
    igraph_vector_int_t *neis=igraph_adjlist_get(&adjlist, v);
    long int i, n=igraph_vector_int_size(neis);
    VECTOR(leaveout)[v]=mark;
    for (i=0; i<n; i++) {
      long int nei=(long int) VECTOR(*neis)[i];
      VECTOR(leaveout)[nei]=mark;
    }

    /* Find the components */
    IGRAPH_CHECK(igraph_i_clusters_leaveout(&adjlist, &components, &leaveout, 
					    &mark, &Q));

    /* Store the corresponding separators, N(C) for each component C */
    IGRAPH_CHECK(igraph_i_separators_store(separators, &adjlist, &components, 
					   &leaveout, &mark, &sorter));

  }

  /* ---------------------------------------------------------------
   * GENERATION, we need to use all already found separators as
   * basis and see if they generate more separators
   */
  
  while (try_next < igraph_vector_ptr_size(separators)) {
    igraph_vector_t *basis=VECTOR(*separators)[try_next];
    long int b, basislen=igraph_vector_size(basis);
    for (b=0; b<basislen; b++) {

      /* Remove N(x) U basis */
      long int x=(long int) VECTOR(*basis)[b];
      igraph_vector_int_t *neis=igraph_adjlist_get(&adjlist, x);
      long int i, n=igraph_vector_int_size(neis);
      for (i=0; i<basislen; i++) {
	long int sn=(long int) VECTOR(*basis)[i];
	VECTOR(leaveout)[sn]=mark;
      }
      for (i=0; i<n; i++) {
	long int nei=(long int) VECTOR(*neis)[i];
	VECTOR(leaveout)[nei]=mark;
      }
      
      /* Find the components */
      IGRAPH_CHECK(igraph_i_clusters_leaveout(&adjlist, &components, 
					      &leaveout, &mark, &Q));

      /* Store the corresponding separators, N(C) for each component C */
      IGRAPH_CHECK(igraph_i_separators_store(separators, &adjlist, 
					     &components, &leaveout, &mark, 
					     &sorter));
    }
    
    try_next++;
  }
  
  /* --------------------------------------------------------------- */

  igraph_vector_destroy(&sorter);
  igraph_dqueue_destroy(&Q);
  igraph_adjlist_destroy(&adjlist);
  igraph_vector_destroy(&components);
  igraph_vector_bool_destroy(&already_tried);
  igraph_vector_destroy(&leaveout);
  IGRAPH_FINALLY_CLEAN(7);	/* +1 for separators */

  return 0;
}
예제 #19
0
파일: components.c 프로젝트: igraph/igraph
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;
}
예제 #20
0
파일: bipartite.c 프로젝트: FEYoung/rigraph
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;
}
예제 #21
0
파일: bipartite.c 프로젝트: FEYoung/rigraph
int igraph_bipartite_projection_size(const igraph_t *graph,
				     const igraph_vector_bool_t *types,
				     igraph_integer_t *vcount1,
				     igraph_integer_t *ecount1,
				     igraph_integer_t *vcount2,
				     igraph_integer_t *ecount2) {

  long int no_of_nodes=igraph_vcount(graph);
  long int vc1=0, ec1=0, vc2=0, ec2=0;
  igraph_adjlist_t adjlist;
  igraph_vector_long_t added;
  long int i;
  
  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);

  for (i=0; i<no_of_nodes; i++) {
    igraph_vector_int_t *neis1;
    long int neilen1, j;
    long int *ecptr;
    if (VECTOR(*types)[i]) { 
      vc2++; 
      ecptr=&ec2;
    } else { 
      vc1++; 
      ecptr=&ec1;
    }
    neis1=igraph_adjlist_get(&adjlist, i);
    neilen1=igraph_vector_int_size(neis1);
    for (j=0; j<neilen1; j++) {
      long int k, neilen2, nei=(long int) VECTOR(*neis1)[j];
      igraph_vector_int_t *neis2=igraph_adjlist_get(&adjlist, nei);
      if (IGRAPH_UNLIKELY(VECTOR(*types)[i] == VECTOR(*types)[nei])) {
	IGRAPH_ERROR("Non-bipartite edge found in bipartite projection",
		     IGRAPH_EINVAL);
      }
      neilen2=igraph_vector_int_size(neis2);
      for (k=0; k<neilen2; k++) {
	long int nei2=(long int) VECTOR(*neis2)[k];
	if (nei2 <= i) { continue; }
	if (VECTOR(added)[nei2] == i+1) { continue; }
	VECTOR(added)[nei2] = i+1;
	(*ecptr)++;
      }
    }
  }

  *vcount1=(igraph_integer_t) vc1;
  *ecount1=(igraph_integer_t) ec1;
  *vcount2=(igraph_integer_t) vc2;
  *ecount2=(igraph_integer_t) ec2;

  igraph_adjlist_destroy(&adjlist);
  igraph_vector_long_destroy(&added);
  IGRAPH_FINALLY_CLEAN(2);
  
  return 0;
}
예제 #22
0
int igraph_i_maximal_cliques(const igraph_t *graph, igraph_i_maximal_clique_func_t func, void* data) {
  int directed=igraph_is_directed(graph);
  long int i, j, k, l;
  igraph_integer_t no_of_nodes, nodes_to_check, nodes_done;
  igraph_integer_t best_cand = 0, best_cand_degree = 0, best_fini_cand_degree;
  igraph_adjlist_t adj_list;
  igraph_stack_ptr_t stack;
  igraph_i_maximal_cliques_stack_frame frame, *new_frame_ptr;
  igraph_vector_t clique;
  igraph_vector_int_t new_cand, new_fini, cn, best_cand_nbrs,
    best_fini_cand_nbrs;
  igraph_bool_t cont = 1;
  int assret;

  if (directed)
    IGRAPH_WARNING("directionality of edges is ignored for directed graphs");

  no_of_nodes = igraph_vcount(graph);
  if (no_of_nodes == 0)
    return IGRAPH_SUCCESS;

  /* Construct an adjacency list representation */
  IGRAPH_CHECK(igraph_adjlist_init(graph, &adj_list, IGRAPH_ALL));
  IGRAPH_FINALLY(igraph_adjlist_destroy, &adj_list);
  IGRAPH_CHECK(igraph_adjlist_simplify(&adj_list));
  igraph_adjlist_sort(&adj_list);

  /* Initialize stack */
  IGRAPH_CHECK(igraph_stack_ptr_init(&stack, 0));
  IGRAPH_FINALLY(igraph_i_maximal_cliques_stack_destroy, &stack);

  /* Create the initial (empty) clique */
  IGRAPH_VECTOR_INIT_FINALLY(&clique, 0);

  /* Initialize new_cand, new_fini, cn, best_cand_nbrs and best_fini_cand_nbrs (will be used later) */
  igraph_vector_int_init(&new_cand, 0);
  IGRAPH_FINALLY(igraph_vector_int_destroy, &new_cand);
  igraph_vector_int_init(&new_fini, 0);
  IGRAPH_FINALLY(igraph_vector_int_destroy, &new_fini);
  igraph_vector_int_init(&cn, 0);
  IGRAPH_FINALLY(igraph_vector_int_destroy, &cn);
  igraph_vector_int_init(&best_cand_nbrs, 0);
  IGRAPH_FINALLY(igraph_vector_int_destroy, &best_cand_nbrs);
  igraph_vector_int_init(&best_fini_cand_nbrs, 0);
  IGRAPH_FINALLY(igraph_vector_int_destroy, &best_fini_cand_nbrs);

  /* Find the vertex with the highest degree */
  best_cand = 0; best_cand_degree = (igraph_integer_t) igraph_vector_int_size(igraph_adjlist_get(&adj_list, 0));
  for (i = 1; i < no_of_nodes; i++) {
    j = igraph_vector_int_size(igraph_adjlist_get(&adj_list, i));
    if (j > best_cand_degree) {
      best_cand = (igraph_integer_t) i;
      best_cand_degree = (igraph_integer_t) j;
    }
  }

  /* Create the initial stack frame */
  IGRAPH_CHECK(igraph_vector_int_init_seq(&frame.cand, 0, no_of_nodes-1));
  IGRAPH_FINALLY(igraph_vector_int_destroy, &frame.cand);
  IGRAPH_CHECK(igraph_vector_int_init(&frame.fini, 0));
  IGRAPH_FINALLY(igraph_vector_int_destroy, &frame.fini);
  IGRAPH_CHECK(igraph_vector_int_init(&frame.cand_filtered, 0));
  IGRAPH_FINALLY(igraph_vector_int_destroy, &frame.cand_filtered);
  IGRAPH_CHECK(igraph_vector_int_difference_sorted(&frame.cand,
        igraph_adjlist_get(&adj_list, best_cand), &frame.cand_filtered));
  IGRAPH_FINALLY_CLEAN(3);
  IGRAPH_FINALLY(igraph_i_maximal_cliques_stack_frame_destroy, &frame);

  /* TODO: frame.cand and frame.fini should be a set instead of a vector */

  /* Main loop starts here */
  nodes_to_check = (igraph_integer_t) igraph_vector_int_size(&frame.cand_filtered); nodes_done = 0;
  while (!igraph_vector_int_empty(&frame.cand_filtered) || !igraph_stack_ptr_empty(&stack)) {
    if (igraph_vector_int_empty(&frame.cand_filtered)) {
      /* No candidates left to check in this stack frame, pop out the previous stack frame */
      igraph_i_maximal_cliques_stack_frame *newframe = igraph_stack_ptr_pop(&stack);
      igraph_i_maximal_cliques_stack_frame_destroy(&frame);
      frame = *newframe;
      free(newframe);

      if (igraph_stack_ptr_size(&stack) == 1) {
        /* We will be using the next candidate node in the next iteration, so we can increase
         * nodes_done by 1 */
        nodes_done++;
      }

      /* For efficiency reasons, we only check for interruption and show progress here */
      IGRAPH_PROGRESS("Maximal cliques: ", 100.0 * nodes_done / nodes_to_check, NULL);
      IGRAPH_ALLOW_INTERRUPTION();

      igraph_vector_pop_back(&clique);
      continue;
    }

    /* Try the next node in the clique */
    i = (long int) igraph_vector_int_pop_back(&frame.cand_filtered);
    IGRAPH_CHECK(igraph_vector_push_back(&clique, i));

    /* Remove the node from the candidate list */
    assret=igraph_vector_int_binsearch(&frame.cand, i, &j); assert(assret);
    igraph_vector_int_remove(&frame.cand, j);

    /* Add the node to the finished list */
    assret = !igraph_vector_int_binsearch(&frame.fini, i, &j); assert(assret);
    IGRAPH_CHECK(igraph_vector_int_insert(&frame.fini, j, i));

    /* Create new_cand and new_fini */
    IGRAPH_CHECK(igraph_vector_int_intersect_sorted(&frame.cand, igraph_adjlist_get(&adj_list, i), &new_cand));
    IGRAPH_CHECK(igraph_vector_int_intersect_sorted(&frame.fini, igraph_adjlist_get(&adj_list, i), &new_fini));

    /* Do we have anything more to search? */
    if (igraph_vector_int_empty(&new_cand)) {
      if (igraph_vector_int_empty(&new_fini)) {
        /* We have a maximal clique here */
        IGRAPH_CHECK(func(&clique, data, &cont));
        if (!cont) {
          /* The callback function requested to stop the search */
          break;
        }
      }
      igraph_vector_pop_back(&clique);
      continue;
    }
    if (igraph_vector_int_empty(&new_fini) && 
	igraph_vector_int_size(&new_cand) == 1) {
      /* Shortcut: only one node left */
      IGRAPH_CHECK(igraph_vector_push_back(&clique, VECTOR(new_cand)[0]));
      IGRAPH_CHECK(func(&clique, data, &cont));
      if (!cont) {
        /* The callback function requested to stop the search */
        break;
      }
      igraph_vector_pop_back(&clique);
      igraph_vector_pop_back(&clique);
      continue;
    }

    /* Find the next best candidate node in new_fini */
    l = igraph_vector_int_size(&new_cand);
    best_cand_degree = -1;
    j = igraph_vector_int_size(&new_fini);
    for (i = 0; i < j; i++) {
      k = (long int)VECTOR(new_fini)[i];
      IGRAPH_CHECK(igraph_vector_int_intersect_sorted(&new_cand, igraph_adjlist_get(&adj_list, k), &cn));
      if (igraph_vector_int_size(&cn) > best_cand_degree) {
        best_cand_degree = (igraph_integer_t) igraph_vector_int_size(&cn);
        IGRAPH_CHECK(igraph_vector_int_update(&best_fini_cand_nbrs, &cn));
        if (best_cand_degree == l) {
          /* Cool, we surely have the best candidate node here as best_cand_degree can't get any better */
          break;
        }
      }
    }
    /* Shortcut here: we don't have to examine new_cand */
    if (best_cand_degree == l) {
      igraph_vector_pop_back(&clique);
      continue;
    }
    /* Still finding best candidate node */
    best_fini_cand_degree = best_cand_degree;
    best_cand_degree = -1;
    j = igraph_vector_int_size(&new_cand);
    l = l - 1;
    for (i = 0; i < j; i++) {
      k = (long int)VECTOR(new_cand)[i];
      IGRAPH_CHECK(igraph_vector_int_intersect_sorted(&new_cand, igraph_adjlist_get(&adj_list, k), &cn));
      if (igraph_vector_int_size(&cn) > best_cand_degree) {
        best_cand_degree = (igraph_integer_t) igraph_vector_int_size(&cn);
        IGRAPH_CHECK(igraph_vector_int_update(&best_cand_nbrs, &cn));
        if (best_cand_degree == l) {
          /* Cool, we surely have the best candidate node here as best_cand_degree can't get any better */
          break;
        }
      }
    }

    /* Create a new stack frame in case we back out later */
    new_frame_ptr = igraph_Calloc(1, igraph_i_maximal_cliques_stack_frame);
    if (new_frame_ptr == 0) {
      IGRAPH_ERROR("cannot allocate new stack frame", IGRAPH_ENOMEM);
    }
    IGRAPH_FINALLY(igraph_free, new_frame_ptr);
    *new_frame_ptr = frame;
    memset(&frame, 0, sizeof(frame));
    IGRAPH_CHECK(igraph_stack_ptr_push(&stack, new_frame_ptr));
    IGRAPH_FINALLY_CLEAN(1);  /* ownership of new_frame_ptr taken by the stack */
    /* Ownership of the current frame and its vectors (frame.cand, frame.done, frame.cand_filtered)
     * is taken by the stack from now on. Vectors in frame must be re-initialized with new_cand,
     * new_fini and stuff. The old frame.cand and frame.fini won't be leaked because they are
     * managed by the stack now. */
    frame.cand = new_cand;
    frame.fini = new_fini;
    IGRAPH_CHECK(igraph_vector_int_init(&new_cand, 0));
    IGRAPH_CHECK(igraph_vector_int_init(&new_fini, 0));
    IGRAPH_CHECK(igraph_vector_int_init(&frame.cand_filtered, 0));

    /* Adjust frame.cand_filtered */
    if (best_cand_degree < best_fini_cand_degree) {
      IGRAPH_CHECK(igraph_vector_int_difference_sorted(&frame.cand, &best_fini_cand_nbrs, &frame.cand_filtered));
    } else {
      IGRAPH_CHECK(igraph_vector_int_difference_sorted(&frame.cand, &best_cand_nbrs, &frame.cand_filtered));
    }
  }

  IGRAPH_PROGRESS("Maximal cliques: ", 100.0, NULL);

  igraph_adjlist_destroy(&adj_list);
  igraph_vector_destroy(&clique);
  igraph_vector_int_destroy(&new_cand);
  igraph_vector_int_destroy(&new_fini);
  igraph_vector_int_destroy(&cn);
  igraph_vector_int_destroy(&best_cand_nbrs);
  igraph_vector_int_destroy(&best_fini_cand_nbrs);
  igraph_i_maximal_cliques_stack_frame_destroy(&frame);
  igraph_i_maximal_cliques_stack_destroy(&stack);
  IGRAPH_FINALLY_CLEAN(9);

  return IGRAPH_SUCCESS;
}
예제 #23
0
파일: scan.c 프로젝트: abeham/igraph
int igraph_local_scan_neighborhood_ecount(const igraph_t *graph,
			  igraph_vector_t *res,
			  const igraph_vector_t *weights,
			  const igraph_vector_ptr_t *neighborhoods) {

  int node, no_of_nodes=igraph_vcount(graph);
  igraph_inclist_t incs;
  igraph_vector_int_t marked;
  igraph_bool_t directed=igraph_is_directed(graph);

  if (weights && igraph_vector_size(weights) != igraph_ecount(graph)) {
    IGRAPH_ERROR("Invalid weight vector length in local scan", IGRAPH_EINVAL);
  }
  if (igraph_vector_ptr_size(neighborhoods) != no_of_nodes) {
    IGRAPH_ERROR("Invalid neighborhood list length in local scan",
		 IGRAPH_EINVAL);
  }

  IGRAPH_CHECK(igraph_vector_int_init(&marked, no_of_nodes));
  IGRAPH_FINALLY(igraph_vector_int_destroy, &marked);
  IGRAPH_CHECK(igraph_inclist_init(graph, &incs, IGRAPH_OUT));
  IGRAPH_FINALLY(igraph_inclist_destroy, &incs);

  IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes));
  igraph_vector_null(res);

  for (node=0; node < no_of_nodes; node++) {
    igraph_vector_int_t *nei=VECTOR(*neighborhoods)[node];
    int i, neilen=igraph_vector_int_size(nei);
    VECTOR(marked)[node] = node + 1;
    for (i=0; i<neilen; i++) {
      int vertex=VECTOR(*nei)[i];
      if (vertex < 0 || vertex >= no_of_nodes) {
	IGRAPH_ERROR("Invalid vertex id in neighborhood list in local scan",
		     IGRAPH_EINVAL);
      }
      VECTOR(marked)[vertex] = node + 1;
    }

    for (i=0; i<neilen; i++) {
      int vertex=VECTOR(*nei)[i];
      igraph_vector_int_t *edges=igraph_inclist_get(&incs, vertex);
      int j, edgeslen=igraph_vector_int_size(edges);
      for (j=0; j<edgeslen; j++) {
	int edge=VECTOR(*edges)[j];
	int nei2=IGRAPH_OTHER(graph, edge, vertex);
	if (VECTOR(marked)[nei2] == node+1) {
	  igraph_real_t w = weights ? VECTOR(*weights)[edge] : 1;
	  VECTOR(*res)[node] += w;
	}
      }
    }
    if (!directed) { VECTOR(*res)[node] /= 2.0; }
  }

  igraph_inclist_destroy(&incs);
  igraph_vector_int_destroy(&marked);
  IGRAPH_FINALLY_CLEAN(2);

  return 0;
}
예제 #24
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;
}