/* call-seq:
 *   IGraph::GenerateRandom.cited_type_game(nodes,types,pref,edges_per_step_directed) -> IGraph
 *
 * Function to create a network based on some vertex categories. This function
 * creates a citation network, in each step a single vertex and edges_per_step
 * citating edges are added, nodes with different categories (may) have
 * different probabilities to get cited, as given by the pref vector.
 *
 * Note that this function might generate networks with multiple edges if
 * edges_per_step is greater than one. You might want to call
 * igraph_simplify() on the result to remove multiple edges.
 *
 * nodes: The number of vertices in the network.
 *
 * types: Numeric Array giving the categories of the vertices, so it should
 * contain nodes non-negative integer numbers. Types are numbered from zero.
 *
 * pref: The attractivity of the different vertex categories in an Array. Its
 * length should be the maximum element in types plus one (types are numbered
 * from zero).
 *
 * edges_per_step: Integer constant, the number of edges to add in each time
 * step.
 *
 * directed: Logical constant, whether to create a directed network.
 */
VALUE cIGraph_cited_type_game(VALUE self, VALUE nodes, VALUE types, VALUE pref, VALUE e_per_s, VALUE directed) {

    igraph_t *graph;
    VALUE new_graph;
    igraph_vector_t type_distv;
    igraph_vector_t prefv;
    int i;

    new_graph = cIGraph_alloc(cIGraph);
    Data_Get_Struct(new_graph, igraph_t, graph);

    igraph_vector_init(&type_distv,0);
    igraph_vector_init(&prefv,0);

    for(i=0; i<RARRAY_LEN(types); i++) {
        igraph_vector_push_back(&type_distv,NUM2DBL(RARRAY_PTR(types)[i]));
    }
    for(i=0; i<RARRAY_LEN(pref); i++) {
        igraph_vector_push_back(&prefv,NUM2DBL(RARRAY_PTR(pref)[i]));
    }

    igraph_destroy(graph);
    igraph_cited_type_game(graph, NUM2INT(nodes),
                           &type_distv,
                           &prefv,
                           NUM2INT(e_per_s),
                           directed == Qtrue ? 1: 0);

    igraph_vector_destroy(&type_distv);
    igraph_vector_destroy(&prefv);

    return new_graph;


}
Example #2
0
int igraph_random_sample_alga(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;
  
  igraph_real_t top=N-n;
  igraph_real_t Nreal=N;
  igraph_real_t S=0;
  igraph_real_t V, quot;
  
  l=l-1;

  while (n>=2) {
    V=RNG_UNIF01();
    S=1;
    quot=top/Nreal;
    while (quot>V) {
      S+=1;
      top=-1.0+top;
      Nreal=-1.0+Nreal;
      quot=(quot*top)/Nreal;
    }
    l+=S;
    igraph_vector_push_back(res, l);	/* allocated */
    Nreal=-1.0+Nreal; n=-1+n;
  }
  
  S=floor(round(Nreal)*RNG_UNIF01());
  l+=S+1;
  igraph_vector_push_back(res, l);	/* allocated */
  
  return 0;
}
/* call-seq:
 *   IGraph::GenerateRandom.degree_sequence_game(out_deg,in_deg) -> IGraph
 *
 * Generates a random graph with a given degree sequence
 *
 * out_deg: The degree sequence for an undirected graph (if in_seq is of
 * length zero), or the out-degree sequence of a directed graph (if in_deq is
 * not of length zero.
 *
 * in_deg: It is either a zero-length Array or the in-degree sequence.
 */
VALUE cIGraph_degree_sequence_game(VALUE self, VALUE out_deg, VALUE in_deg) {

    igraph_t *graph;
    VALUE new_graph;
    igraph_vector_t out_degv;
    igraph_vector_t in_degv;
    int i;

    new_graph = cIGraph_alloc(cIGraph);
    Data_Get_Struct(new_graph, igraph_t, graph);

    igraph_vector_init(&out_degv,0);
    igraph_vector_init(&in_degv,0);

    for(i=0; i<RARRAY_LEN(out_deg); i++) {
        igraph_vector_push_back(&out_degv,NUM2INT(RARRAY_PTR(out_deg)[i]));
    }
    for(i=0; i<RARRAY_LEN(in_deg); i++) {
        igraph_vector_push_back(&in_degv,NUM2INT(RARRAY_PTR(in_deg)[i]));
    }

    igraph_destroy(graph);
    igraph_degree_sequence_game(graph, &out_degv, &in_degv, 0);

    igraph_vector_destroy(&out_degv);
    igraph_vector_destroy(&in_degv);

    return new_graph;

}
Example #4
0
/**
 * \ingroup structural
 * \function igraph_similarity_jaccard_es
 * \brief Jaccard similarity coefficient for a given edge selector.
 *
 * </para><para>
 * The Jaccard similarity coefficient of two vertices is the number of common
 * neighbors divided by the number of vertices that are neighbors of at
 * least one of the two vertices being considered. This function calculates
 * the pairwise Jaccard similarities for the endpoints of edges in a given edge
 * selector.
 *
 * \param graph The graph object to analyze
 * \param res Pointer to a vector, the result of the calculation will
 *        be stored here. The number of elements is the same as the number
 *        of edges in \p es.
 * \param es An edge selector that specifies the edges to be included in the
 *        result.
 * \param mode The type of neighbors to be used for the calculation in
 *        directed graphs. Possible values:
 *        \clist
 *        \cli IGRAPH_OUT
 *          the outgoing edges will be considered for each node.
 *        \cli IGRAPH_IN
 *          the incoming edges will be considered for each node.
 *        \cli IGRAPH_ALL
 *          the directed graph is considered as an undirected one for the
 *          computation.
 *        \endclist
 * \param loops Whether to include the vertices themselves in the neighbor
 *        sets.
 * \return Error code:
 *        \clist
 *        \cli IGRAPH_ENOMEM
 *           not enough memory for temporary data.
 *        \cli IGRAPH_EINVVID
 *           invalid vertex id passed.
 *        \cli IGRAPH_EINVMODE
 *           invalid mode argument.
 *        \endclist
 * 
 * Time complexity: O(nd), n is the number of edges in the edge selector, d is
 * the (maximum) degree of the vertices in the graph.
 *
 * \sa \ref igraph_similarity_jaccard() and \ref igraph_similarity_jaccard_pairs()
 *   to calculate the Jaccard similarity between all pairs of a vertex set or
 *   some selected vertex pairs, or \ref igraph_similarity_dice(),
 *   \ref igraph_similarity_dice_pairs() and \ref igraph_similarity_dice_es() for a
 *   measure very similar to the Jaccard coefficient
 * 
 * \example examples/simple/igraph_similarity.c
 */
int igraph_similarity_jaccard_es(const igraph_t *graph, igraph_vector_t *res,
	const igraph_es_t es, igraph_neimode_t mode, igraph_bool_t loops) {
  igraph_vector_t v;
  igraph_eit_t eit;

  IGRAPH_VECTOR_INIT_FINALLY(&v, 0);

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

  while (!IGRAPH_EIT_END(eit)) {
    long int eid = IGRAPH_EIT_GET(eit);
    igraph_vector_push_back(&v, IGRAPH_FROM(graph, eid));
    igraph_vector_push_back(&v, IGRAPH_TO(graph, eid));
    IGRAPH_EIT_NEXT(eit);
  }

  igraph_eit_destroy(&eit);
  IGRAPH_FINALLY_CLEAN(1);

  IGRAPH_CHECK(igraph_similarity_jaccard_pairs(graph, res, &v, mode, loops));
  igraph_vector_destroy(&v);
  IGRAPH_FINALLY_CLEAN(1);

  return IGRAPH_SUCCESS;
}
Example #5
0
/* removes multiple edges and returns new edge id's for each edge in |E|log|E| */
int igraph_i_multilevel_simplify_multiple(igraph_t *graph, igraph_vector_t *eids) {
  long int ecount = igraph_ecount(graph);
  long int i, l = -1, last_from = -1, last_to = -1;
  igraph_bool_t directed = igraph_is_directed(graph);
  igraph_integer_t from, to;
  igraph_vector_t edges;
  igraph_i_multilevel_link *links;

  /* Make sure there's enough space in eids to store the new edge IDs */
  IGRAPH_CHECK(igraph_vector_resize(eids, ecount));

  links = igraph_Calloc(ecount, igraph_i_multilevel_link);
  if (links == 0) {
    IGRAPH_ERROR("multi-level community structure detection failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(free, links);

  for (i = 0; i < ecount; i++) {
    igraph_edge(graph, (igraph_integer_t) i, &from, &to);
    links[i].from = from;
    links[i].to = to;
    links[i].id = i;
  }  

  qsort((void*)links, (size_t) ecount, sizeof(igraph_i_multilevel_link),
      igraph_i_multilevel_link_cmp);

  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  for (i = 0; i < ecount; i++) {
    if (links[i].from == last_from && links[i].to == last_to) {
      VECTOR(*eids)[links[i].id] = l;
      continue;
    }

    last_from = links[i].from;
    last_to = links[i].to;

    igraph_vector_push_back(&edges, last_from);
    igraph_vector_push_back(&edges, last_to);

    l++;

    VECTOR(*eids)[links[i].id] = l;
  }

  free(links);
  IGRAPH_FINALLY_CLEAN(1);

  igraph_destroy(graph);
  IGRAPH_CHECK(igraph_create(graph, &edges, igraph_vcount(graph), directed));

  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);

  return 0;
}
Example #6
0
int igraph_complementer(igraph_t *res, const igraph_t *graph, 
			igraph_bool_t loops) {

  long int no_of_nodes=igraph_vcount(graph);
  igraph_vector_t edges;
  igraph_vector_t neis;
  long int i, j;
  long int zero=0, *limit;

  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);

  if (igraph_is_directed(graph)) {
    limit=&zero;
  } else {
    limit=&i;
  }
  
  for (i=0; i<no_of_nodes; i++) {
    IGRAPH_ALLOW_INTERRUPTION();
    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) i, 
				  IGRAPH_OUT));
    if (loops) {
      for (j=no_of_nodes-1; j>=*limit; j--) {
	if (igraph_vector_empty(&neis) || j>igraph_vector_tail(&neis)) {
	  IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
	  IGRAPH_CHECK(igraph_vector_push_back(&edges, j));
	} else {
	  igraph_vector_pop_back(&neis);
	}
      }
    } else {
      for (j=no_of_nodes-1; j>=*limit; j--) {
	if (igraph_vector_empty(&neis) || j>igraph_vector_tail(&neis)) {
	  if (i!=j) {
	    IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
	    IGRAPH_CHECK(igraph_vector_push_back(&edges, j));
	  }
	} else {
	  igraph_vector_pop_back(&neis);
	}
      }
    }      
  }
  
  IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) no_of_nodes, 
			     igraph_is_directed(graph)));  
  igraph_vector_destroy(&edges);
  igraph_vector_destroy(&neis);
  IGRAPH_I_ATTRIBUTE_DESTROY(res);
  IGRAPH_I_ATTRIBUTE_COPY(res, graph, /*graph=*/1, /*vertex=*/1, /*edge=*/0);
  IGRAPH_FINALLY_CLEAN(2);
  return 0;
}
Example #7
0
int igraph_dot_product_game(igraph_t *graph, const igraph_matrix_t *vecs,
			    igraph_bool_t directed) {

  igraph_integer_t nrow=igraph_matrix_nrow(vecs);
  igraph_integer_t ncol=igraph_matrix_ncol(vecs);
  int i, j;
  igraph_vector_t edges;
  igraph_bool_t warned_neg=0, warned_big=0;
  
  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
    
  RNG_BEGIN();

  for (i = 0; i < ncol; i++) {
    int from=directed ? 0 : i+1;
    igraph_vector_t v1;
    igraph_vector_view(&v1, &MATRIX(*vecs, 0, i), nrow);
    for (j = from; j < ncol; j++) {
      igraph_real_t prob;
      igraph_vector_t v2;
      if (i==j) { continue; }
      igraph_vector_view(&v2, &MATRIX(*vecs, 0, j), nrow);
      igraph_lapack_ddot(&v1, &v2, &prob);
      if (prob < 0 && ! warned_neg) {
	warned_neg=1;
	IGRAPH_WARNING("Negative connection probability in "
		       "dot-product graph");
      } else if (prob > 1 && ! warned_big) {
	warned_big=1;
	IGRAPH_WARNING("Greater than 1 connection probability in "
		       "dot-product graph");
	IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
	IGRAPH_CHECK(igraph_vector_push_back(&edges, j));
      } else if (RNG_UNIF01() < prob) { 
	IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
	IGRAPH_CHECK(igraph_vector_push_back(&edges, j));
      }
    }
  }

  RNG_END();
  
  igraph_create(graph, &edges, ncol, directed);
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);

  return 0;
}
/* call-seq:
 *   IGraph::GenerateRandom.preference_game(nodes,types,type_dist,pref_matrixdirected,loops) -> IGraph
 *
 * Generates a graph with vertex types and connection preferences
 *
 * This is practically the nongrowing variant of igraph_establishment_game.
 * A given number of vertices are generated. Every vertex is assigned to a
 * vertex type according to the given type probabilities. Finally, every
 * vertex pair is evaluated and an edge is created between them with a
 * probability depending on the types of the vertices involved.
 *
 * nodes: The number of vertices in the graph.
 *
 * types: The number of vertex types.
 *
 * type_dist: Vector giving the distribution of vertex types.
 *
 * pref_matrix: IGraphMatrix giving the connection probabilities for
 * different vertex types.
 *
 * directed: Logical, whether to generate a directed graph. If undirected
 * graphs are requested, only the lower left triangle of the preference
 * matrix is considered.
 *
 * loops: Logical, whether loop edges are allowed.
 */
VALUE cIGraph_preference_game(VALUE self, VALUE nodes, VALUE types, VALUE type_dist, VALUE pref_matrix, VALUE directed, VALUE loops) {

    igraph_t *graph;
    VALUE new_graph;
    igraph_vector_t type_distv;
    igraph_matrix_t *pref_matrixm;
    int i;

    new_graph = cIGraph_alloc(cIGraph);
    Data_Get_Struct(new_graph, igraph_t, graph);

    Data_Get_Struct(pref_matrix, igraph_matrix_t, pref_matrixm);

    igraph_vector_init(&type_distv,0);

    for(i=0; i<RARRAY_LEN(type_dist); i++) {
        igraph_vector_push_back(&type_distv,NUM2DBL(RARRAY_PTR(type_dist)[i]));
    }

    igraph_destroy(graph);
    igraph_preference_game(graph, NUM2INT(nodes), NUM2INT(types),
                           &type_distv,
                           pref_matrixm,
                           NULL,
                           directed == Qtrue ? 1: 0,
                           loops == Qtrue ? 1 : 0);

    igraph_vector_destroy(&type_distv);

    return new_graph;


}
Example #9
0
/* call-seq:
 *   igraph.motifs_randesu(size,cut)
 *
 */
VALUE cIGraph_motifs_randesu(VALUE self, VALUE size, VALUE cuts){

  igraph_t *graph;
  igraph_vector_t cutsv;
  igraph_vector_t res;
  int i;
  VALUE hist = rb_ary_new();

  Data_Get_Struct(self, igraph_t, graph);

  igraph_vector_init(&res,0);

  //Convert an array of vertices to a vector of vertex ids
  igraph_vector_init(&cutsv,0);
  for(i=0;i<RARRAY_LEN(cuts);i++){
    igraph_vector_push_back(&cutsv,NUM2DBL(RARRAY_PTR(cuts)[i]));
  }

  igraph_motifs_randesu(graph,&res,NUM2INT(size),&cutsv);

  for(i=0; i<igraph_vector_size(&res); i++){
    rb_ary_push(hist,INT2NUM(VECTOR(res)[i]));
  }

  igraph_vector_destroy(&cutsv);
  igraph_vector_destroy(&res);
 
  return hist;

}
/* call-seq:
 *   IGraph::GenerateRandom.citing_cited_type_game(nodes,types,pref,edges_per_step_directed) -> IGraph
 *
 * This game is similar to igraph_cited_type_game() but here the category of
 * the citing vertex is also considered.
 *
 * An evolving citation network is modeled here, a single vertex and its
 * edges_per_step citation are added in each time step. The odds the a given
 * vertex is cited by the new vertex depends on the category of both the
 * citing and the cited vertex and is given in the pref matrix. The categories
 * of the citing vertex correspond to the rows, the categories of the cited
 * vertex to the columns of this matrix. Ie. the element in row i and column
 * j gives the probability that a j vertex is cited, if the category of the
 * citing vertex is i.
 *
 * Note that this function might generate networks with multiple edges if
 * edges_per_step is greater than one. You might want to call
 * igraph_simplify() on the result to remove multiple edges.
 *
 * nodes: The number of vertices in the network.
 *
 * types: A numeric IGraphMatrix of length nodes, containing the categories
 * of the vertices. The categories are numbered from zero.
 *
 * pref: The preference IGraphMatrix, a square matrix is required, both the
 * number of rows and columns should be the maximum element in types plus
 * one (types are numbered from zero).
 *
 * edges_per_step: Integer constant, the number of edges to add in each time
 * step.
 *
 * directed: Logical constant, whether to create a directed network.
 */
VALUE cIGraph_citing_cited_type_game(VALUE self, VALUE nodes, VALUE types, VALUE pref, VALUE e_per_s, VALUE directed) {

    igraph_t *graph;
    VALUE new_graph;
    igraph_vector_t typev;
    igraph_matrix_t *prefm;
    int i;

    new_graph = cIGraph_alloc(cIGraph);
    Data_Get_Struct(new_graph, igraph_t, graph);
    Data_Get_Struct(pref, igraph_matrix_t, prefm);

    igraph_vector_init(&typev,0);

    for(i=0; i<RARRAY_LEN(types); i++) {
        igraph_vector_push_back(&typev,NUM2INT(RARRAY_PTR(types)[i]));
    }

    /*printf("ok\n");*/

    igraph_destroy(graph);
    igraph_citing_cited_type_game(graph, NUM2INT(nodes),
                                  &typev,
                                  prefm,
                                  NUM2INT(e_per_s),
                                  directed == Qtrue ? 1: 0);

    /*printf("death\n");*/

    igraph_vector_destroy(&typev);

    return new_graph;


}
Example #11
0
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;
}
Example #12
0
int igraph_disjoint_union_many(igraph_t *res, 
			       const igraph_vector_ptr_t *graphs) {
  long int no_of_graphs=igraph_vector_ptr_size(graphs);
  igraph_bool_t directed=1;
  igraph_vector_t edges;
  long int no_of_edges=0;
  long int shift=0;
  igraph_t *graph;
  long int i, j;
  igraph_integer_t from, to;
  
  if (no_of_graphs != 0) {
    graph=VECTOR(*graphs)[0];
    directed=igraph_is_directed(graph);
    for (i=0; i<no_of_graphs; i++) {      
      graph=VECTOR(*graphs)[i];
      no_of_edges += igraph_ecount(graph);
      if (directed != igraph_is_directed(graph)) {
	IGRAPH_ERROR("Cannot union directed and undirected graphs", 
		     IGRAPH_EINVAL);
      }
    }
  }
  
  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  IGRAPH_CHECK(igraph_vector_reserve(&edges, 2*no_of_edges));
  
  for (i=0; i<no_of_graphs; i++) {
    long int ec;
    graph=VECTOR(*graphs)[i];    
    ec=igraph_ecount(graph);
    for (j=0; j<ec; j++) {
      igraph_edge(graph, (igraph_integer_t) j, &from, &to);
      igraph_vector_push_back(&edges, from+shift);
      igraph_vector_push_back(&edges, to+shift);
    }
    shift += igraph_vcount(graph);
  }
  
  IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) shift, directed));
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  return 0;
}
Example #13
0
int igraph_i_separators_store(igraph_vector_ptr_t *separators, 
			      const igraph_adjlist_t *adjlist,
			      igraph_vector_t *components, 
			      igraph_vector_t *leaveout, 
			      unsigned long int *mark, 
			      igraph_vector_t *sorter) {
  
  /* We need to stote N(C), the neighborhood of C, but only if it is 
   * not already stored among the separators.
   */
  
  long int cptr=0, next, complen=igraph_vector_size(components);

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

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

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

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

    UPDATEMARK();

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

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

  return 0;
}
Example #14
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;
}
Example #15
0
/* call-seq:
 *   graph.constraint(vs,weights) -> Array
 *
 * Returns an Array of constraint measures for the vertices 
 * in the graph. Weights is an Array of weight measures for each edge.
 */
VALUE cIGraph_constraint(int argc, VALUE *argv, VALUE self){

  igraph_t *graph;
  igraph_vs_t vids;
  igraph_vector_t vidv;
  igraph_vector_t res;
  igraph_vector_t wght;
  int i;
  VALUE constraints = rb_ary_new();
  VALUE vs, weights;

  rb_scan_args(argc,argv,"11",&vs, &weights);

  //vector to hold the results of the degree calculations
  IGRAPH_FINALLY(igraph_vector_destroy, &res);
  IGRAPH_FINALLY(igraph_vector_destroy, &wght);
  IGRAPH_FINALLY(igraph_vector_destroy, &vidv);
  IGRAPH_CHECK(igraph_vector_init(&res,0));
  IGRAPH_CHECK(igraph_vector_init(&wght,0));

  Data_Get_Struct(self, igraph_t, graph);

  //Convert an array of vertices to a vector of vertex ids
  IGRAPH_CHECK(igraph_vector_init_int(&vidv,0));
  cIGraph_vertex_arr_to_id_vec(self,vs,&vidv);
  //create vertex selector from the vecotr of ids
  igraph_vs_vector(&vids,&vidv);

  if(weights == Qnil){
    IGRAPH_CHECK(igraph_constraint(graph,&res,vids,NULL));
  } else {
    for(i=0;i<RARRAY_LEN(weights);i++){
      IGRAPH_CHECK(igraph_vector_push_back(&wght,NUM2DBL(RARRAY_PTR(weights)[i])));
    }
    IGRAPH_CHECK(igraph_constraint(graph,&res,vids,&wght));
  }

  for(i=0;i<igraph_vector_size(&res);i++){
    rb_ary_push(constraints,rb_float_new(VECTOR(res)[i]));
  }

  igraph_vector_destroy(&vidv);
  igraph_vector_destroy(&res);
  igraph_vector_destroy(&wght);
  igraph_vs_destroy(&vids);

  IGRAPH_FINALLY_CLEAN(3);

  return constraints;

}
Example #16
0
int igraph_disjoint_union(igraph_t *res, const igraph_t *left, 
			  const igraph_t *right) {

  long int no_of_nodes_left=igraph_vcount(left);
  long int no_of_nodes_right=igraph_vcount(right);
  long int no_of_edges_left=igraph_ecount(left);
  long int no_of_edges_right=igraph_ecount(right);
  igraph_vector_t edges;
  igraph_bool_t directed_left=igraph_is_directed(left);
  igraph_integer_t from, to;
  long int i;
  
  if (directed_left != igraph_is_directed(right)) {
    IGRAPH_ERROR("Cannot union directed and undirected graphs",
		 IGRAPH_EINVAL);
  }

  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  IGRAPH_CHECK(igraph_vector_reserve(&edges, 
				     2*(no_of_edges_left+no_of_edges_right)));
  for (i=0; i<no_of_edges_left; i++) {
    igraph_edge(left, (igraph_integer_t) i, &from, &to);
    igraph_vector_push_back(&edges, from);
    igraph_vector_push_back(&edges, to);
  }
  for (i=0; i<no_of_edges_right; i++) {
    igraph_edge(right, (igraph_integer_t) i, &from, &to);
    igraph_vector_push_back(&edges, from+no_of_nodes_left);
    igraph_vector_push_back(&edges, to+no_of_nodes_left);
  }
  
  IGRAPH_CHECK(igraph_create(res, &edges, (igraph_integer_t) 
			     (no_of_nodes_left+no_of_nodes_right), 
			     directed_left));
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  return 0;
}
Example #17
0
int cliques_load_unordered_maximal_cliques_list(cliques *c, const char *path) {
    FILE *input;
    igraph_vector_t *k_clique_v;
    int size, node_id;
    int max_size=0,cur_size=0;
    if (c == NULL || path == NULL)
        return -1;

    if ((input = fopen(path, "r")) == NULL)
        return -2;

    k_clique_v = (igraph_vector_t*) malloc(sizeof (igraph_vector_t));
    igraph_vector_init(k_clique_v, 0);
    // read the file and compute the maximum size
    // of the cliques
    while (fscanf(input, "%i", &node_id) != EOF) {
      if (node_id == -1){
	if(cur_size > max_size)
	  max_size = cur_size;
        cur_size=0;
      } else
        cur_size++;
    }

    // initialize cliques structure internal vectors
    // according to the size of the maximum clique
    if((cliques_init_member_vectors(c, max_size)) < 0)
      return -3;

    // reset the file position indicator to the beginning of the file
    fseek(input, 0L, SEEK_SET);
    // load maximal cliques from the file


    while (fscanf(input, "%i", &node_id) != EOF) {
      if (node_id != -1){
        igraph_vector_push_back(k_clique_v, node_id);
      }else {
        size = igraph_vector_size(k_clique_v);
        igraph_vector_sort(k_clique_v);
        igraph_vector_ptr_push_back(VECTOR(c->maximal_cliques_v_ptr)[size], k_clique_v);
        
        k_clique_v = (igraph_vector_t*) malloc(sizeof (igraph_vector_t));
        igraph_vector_init(k_clique_v, 0);
      }
    }
    cliques_order_cliques_by_decreasing_k(c, NULL);
    igraph_vector_destroy(k_clique_v);
    return 0;
}
Example #18
0
int igraph_i_2dgrid_addvertices(igraph_2dgrid_t *grid, igraph_vector_t *eids,
                                igraph_integer_t vid, igraph_real_t r,
                                long int x, long int y) {
    long int act;
    igraph_real_t *v=VECTOR(grid->next);

    r=r*r;
    act=(long int) MATRIX(grid->startidx, x, y);
    while (act != 0) {
        if (igraph_2dgrid_dist2(grid, vid, act-1) < r) {
            IGRAPH_CHECK(igraph_vector_push_back(eids, act-1));
        }
        act=(long int) v[act-1];
    }
    return 0;
}
Example #19
0
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;
}
Example #20
0
/* call-seq:
 *   graph.eigenvector_centrality(scale, weights) -> Array
 *
 * Returns a two-element arrar, the first element of which is an Array of 
 * eigenvector centrality scores for graph, and the second of which is the
 * eigenvalue.
 *
 * scale is a boolean value. If true, the scores will be weighted so that the
 * absolute value of the maximum centrality is one.
 *
 * weights is an Array giving the weights of the edges. If nil, the edges are unweighted.
 */
VALUE cIGraph_eigenvector_centrality(VALUE self, VALUE scale, VALUE weights) {
  int i;
  igraph_t *graph;
  igraph_vector_t vec;
  igraph_real_t val;
  igraph_vector_t wgts;
  igraph_arpack_options_t arpack_opt;
  igraph_bool_t sc = 0;
  VALUE eigenvector = rb_ary_new();
  VALUE rb_res = rb_ary_new();

  IGRAPH_FINALLY(igraph_vector_destroy, &vec);
  IGRAPH_FINALLY(igraph_vector_destroy, &wgts);
  IGRAPH_CHECK(igraph_vector_init(&vec,0));
  IGRAPH_CHECK(igraph_vector_init(&wgts,0));

  igraph_arpack_options_init(&arpack_opt);

  if (scale == Qtrue) sc = 1;

  Data_Get_Struct(self, igraph_t, graph);

  if (weights == Qnil) {
    IGRAPH_CHECK(igraph_eigenvector_centrality(graph, &vec, &val, sc, NULL, &arpack_opt));
  } else {
    for(i = 0; i < RARRAY_LEN(weights); i++)
      IGRAPH_CHECK(igraph_vector_push_back(&wgts, NUM2DBL(RARRAY_PTR(weights)[i])));

    IGRAPH_CHECK(igraph_eigenvector_centrality(graph, &vec, &val, sc, &wgts, &arpack_opt));
  }

  for(i = 0; i < igraph_vector_size(&vec); i++)
    rb_ary_push(eigenvector, rb_float_new(VECTOR(vec)[i]));

  igraph_vector_destroy(&vec);
  igraph_vector_destroy(&wgts);

  rb_ary_push(rb_res, eigenvector);
  rb_ary_push(rb_res, rb_float_new(val));

  IGRAPH_FINALLY_CLEAN(2);

  return rb_res;
}
Example #21
0
int cIGraph_vertex_arr_to_id_vec(VALUE graph, VALUE va, igraph_vector_t *nv){

  VALUE vertex;
  VALUE tmp;
  VALUE i;

  tmp = rb_check_array_type(va);

  if(NIL_P(tmp))
    rb_raise(cIGraphError, "Array expected\n");
    
  //Initialize edge vector
  //igraph_vector_init_int(nv,0);
  for (i=0; i<RARRAY_LEN(va); i++) {
    vertex = RARRAY_PTR(va)[i];
    igraph_vector_push_back(nv,cIGraph_get_vertex_id(graph, vertex));
  }

  return 0;

}
Example #22
0
VALUE cIGraph_community_eb_get_merges(VALUE self, VALUE edges){

  igraph_t *graph;
  igraph_matrix_t *res = malloc(sizeof(igraph_matrix_t));

  igraph_vector_t edges_vec;
  igraph_vector_t bridges_vec;

  VALUE result,bridges_a;

  int i;

  Data_Get_Struct(self, igraph_t, graph);

  igraph_matrix_init(res,0,0);
  igraph_vector_init(&edges_vec,0);
  igraph_vector_init(&bridges_vec,0);

  for(i=0;i<RARRAY_LEN(edges);i++){
    igraph_vector_push_back(&edges_vec,NUM2INT(RARRAY_PTR(edges)[i]));
  }

  igraph_community_eb_get_merges(graph,&edges_vec,res,&bridges_vec);

  bridges_a = rb_ary_new();
  for(i=0;i<igraph_vector_size(&bridges_vec);i++){
    rb_ary_push(bridges_a,INT2NUM(VECTOR(bridges_vec)[i]));
  }

  igraph_vector_destroy(&bridges_vec);
  igraph_vector_destroy(&edges_vec);

  result = rb_ary_new3(2,
		       Data_Wrap_Struct(cIGraphMatrix, 0, 
					cIGraph_matrix_free, res),
		       bridges_a);

  return result;

}
Example #23
0
/* call-seq:
 *   igraph.motifs_randesu_estimate(size,cut,samplen,samplev)
 *
 */
VALUE cIGraph_motifs_randesu_estimate(VALUE self, VALUE size, VALUE cuts, 
				      VALUE samplen, VALUE samplev){

  igraph_t *graph;
  igraph_vector_t cutsv;
  igraph_vector_t vidv;
  igraph_integer_t res;
  int i;

  if(samplev != Qnil){
    igraph_vector_init(&vidv,0);
    //Convert an array of vertices to a vector of vertex ids
    igraph_vector_init_int(&vidv,0);
    cIGraph_vertex_arr_to_id_vec(self,samplev,&vidv);
   }

  Data_Get_Struct(self, igraph_t, graph);

  igraph_vector_init(&cutsv,0);
  for(i=0;i<RARRAY_LEN(cuts);i++){
    igraph_vector_push_back(&cutsv,NUM2DBL(RARRAY_PTR(cuts)[i]));
  }

  if(samplev == Qnil){
    igraph_motifs_randesu_estimate(graph,&res,NUM2INT(size),
				   &cutsv,NUM2INT(samplen),NULL);
  } else {
    igraph_motifs_randesu_estimate(graph,&res,NUM2INT(size),
				   &cutsv,NUM2INT(samplen),&vidv);
  }

  igraph_vector_destroy(&cutsv);
  if(samplev != Qnil){
    igraph_vector_destroy(&vidv);
  }
  
  return INT2NUM(res);

}
Example #24
0
/* call-seq:
 *   igraph.motifs_randesu_no(size,cut)
 *
 */
VALUE cIGraph_motifs_randesu_no(VALUE self, VALUE size, VALUE cuts){

  igraph_t *graph;
  igraph_vector_t cutsv;
  igraph_integer_t res;
  int i;

  Data_Get_Struct(self, igraph_t, graph);

  //Convert an array of vertices to a vector of vertex ids
  igraph_vector_init(&cutsv,0);
  for(i=0;i<RARRAY_LEN(cuts);i++){
    igraph_vector_push_back(&cutsv,NUM2DBL(RARRAY_PTR(cuts)[i]));
  }

  igraph_motifs_randesu_no(graph,&res,NUM2INT(size),&cutsv);

  igraph_vector_destroy(&cutsv);
 
  return INT2NUM(res);

}
Example #25
0
int main(void)
{
     igraph_integer_t diameter;
     igraph_t graph;
     igraph_integer_t v; 
     igraph_vector_t edges;
     igraph_vector_init(&edges,100);
     int i,j;

     int n=30,k=14;
     for(i=0;i<n;i++)
     {
         igraph_vector_push_back(&edges, i);
	 igraph_vector_push_back(&edges, (i+1)%n);
 
	 igraph_vector_push_back(&edges, i);
	 igraph_vector_push_back(&edges, i+n);

	 igraph_vector_push_back(&edges, n+i);
	 igraph_vector_push_back(&edges, n+(i+k)%n);
     }

     
     igraph_create(&graph, &edges, 0, 0);
     
     //igraph_vector_ptr_init(&v, 100);
     //igraph_erdos_renyi_game(&graph, IGRAPH_ERDOS_RENYI_GNP, 100, 5.0/1000,
     //                        IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS);
     //igraph_diameter(&graph, &diameter, 0, 0, 0, IGRAPH_UNDIRECTED, 1);
     //maximal.independent.vertex.sets(graph)
     igraph_independence_number(&graph, &v);
     
     printf("MIS of a random graph with average degree 5: %i\n",
             v);
     igraph_destroy(&graph);
     return 0;
}
Example #26
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;
}
Example #27
0
int main() {
  
  igraph_t graph, ring;
  igraph_vector_t order, rank, father, pred, succ, dist;
  igraph_vector_t restricted;
  igraph_vector_t roots;
  long int i;
  
  igraph_ring(&ring, 10, /*directed=*/ 0, /*mutual=*/ 0, /*circular=*/ 1);
  igraph_disjoint_union(&graph, &ring, &ring);
  igraph_destroy(&ring);
  
  igraph_vector_init(&order, 0);
  igraph_vector_init(&rank, 0);
  igraph_vector_init(&father, 0);
  igraph_vector_init(&pred, 0);
  igraph_vector_init(&succ, 0);
  igraph_vector_init(&dist, 0);
  
  igraph_bfsr(&graph, /*root=*/0, /*roots=*/ 0, /*neimode=*/ IGRAPH_OUT, 
       /*unreachable=*/ 1, /*restricted=*/ 0,
       &order, &rank, &father, &pred, &succ, &dist, 
       /*callback=*/ 0, /*extra=*/ 0);
  
  igraph_vector_print(&order);
  igraph_vector_print(&rank);
  igraph_vector_print(&father);
  igraph_vector_print(&pred);
  igraph_vector_print(&succ);
  igraph_vector_print(&dist);

  igraph_vector_destroy(&order);
  igraph_vector_destroy(&rank);
  igraph_vector_destroy(&father);
  igraph_vector_destroy(&pred);
  igraph_vector_destroy(&succ);
  igraph_vector_destroy(&dist);

  /* Test the callback */

  igraph_bfsr(&graph, /*root=*/ 0, /*roots=*/ 0, /*neimode=*/ IGRAPH_OUT, 
       /*unreachable=*/ 1, /*restricted=*/ 0,
       0, 0, 0, 0, 0, 0, &bfs_callback, 0);
  printf("\n");
  
  /* Test different roots */

  igraph_bfsr(&graph, /*root=*/ 2, /*roots=*/ 0, /*neimode=*/ IGRAPH_OUT, 
       /*unreachable=*/ 1, /*restricted=*/ 0,
       0, 0, 0, 0, 0, 0, &bfs_callback, 0);
  printf("\n");

  /* Test restricted */

  igraph_vector_init(&restricted, 0);
  for (i=5; i<igraph_vcount(&graph); i++) {
    igraph_vector_push_back(&restricted, i);
  }
  igraph_bfsr(&graph, /*root=*/ 5, /*roots=*/ 0, /*neimode=*/ IGRAPH_OUT, 
       /*unreachable=*/ 1, &restricted,
       0, 0, 0, 0, 0, 0, &bfs_callback, 0);
  printf("\n");  

  /* Root not in restricted set */

  igraph_bfsr(&graph, /*root=*/ 4, /*roots=*/ 0, /*neimode=*/ IGRAPH_OUT, 
       /*unreachable=*/ 1, &restricted,
       0, 0, 0, 0, 0, 0, &bfs_callback, 0);
  printf("\n");  

  igraph_bfsr(&graph, /*root=*/ 3, /*roots=*/ 0, /*neimode=*/ IGRAPH_OUT, 
       /*unreachable=*/ 0, &restricted,
       0, 0, 0, 0, 0, 0, &bfs_callback, 0);
  printf("\n");  

  /* Multiple root vertices */

  igraph_vector_init(&roots, 3);
  VECTOR(roots)[0]=3; 
  VECTOR(roots)[1]=4;
  VECTOR(roots)[2]=6;
  igraph_bfsr(&graph, /*root=*/ -1, &roots, /*neimode=*/ IGRAPH_OUT, 
       /*unreachable=*/ 0, &restricted,
       0, 0, 0, 0, 0, 0, &bfs_callback, 0);
  printf("\n");    

  igraph_vector_destroy(&roots);
  igraph_vector_destroy(&restricted);
  igraph_destroy(&graph);
  
  return 0;
}
Example #28
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, 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_INIT_FINALLY(&new_cand, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&new_fini, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&cn, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&best_cand_nbrs, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&best_fini_cand_nbrs, 0);

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

  /* Create the initial stack frame */
  IGRAPH_CHECK(igraph_vector_init_seq(&frame.cand, 0, no_of_nodes-1));
  IGRAPH_FINALLY(igraph_vector_destroy, &frame.cand);
  IGRAPH_CHECK(igraph_vector_init(&frame.fini, 0));
  IGRAPH_FINALLY(igraph_vector_destroy, &frame.fini);
  IGRAPH_CHECK(igraph_vector_init(&frame.cand_filtered, 0));
  IGRAPH_FINALLY(igraph_vector_destroy, &frame.cand_filtered);
  IGRAPH_CHECK(igraph_vector_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_vector_size(&frame.cand_filtered); nodes_done = 0;
  while (!igraph_vector_empty(&frame.cand_filtered) || !igraph_stack_ptr_empty(&stack)) {
    if (igraph_vector_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 = igraph_vector_pop_back(&frame.cand_filtered);
    IGRAPH_CHECK(igraph_vector_push_back(&clique, i));

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

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

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

    /* Do we have anything more to search? */
    if (igraph_vector_empty(&new_cand)) {
      if (igraph_vector_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_empty(&new_fini) && igraph_vector_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_size(&new_cand);
    best_cand_degree = -1;
    j = igraph_vector_size(&new_fini);
    for (i = 0; i < j; i++) {
      k = (long int)VECTOR(new_fini)[i];
      IGRAPH_CHECK(igraph_vector_intersect_sorted(&new_cand, igraph_adjlist_get(&adj_list, k), &cn));
      if (igraph_vector_size(&cn) > best_cand_degree) {
        best_cand_degree = igraph_vector_size(&cn);
        IGRAPH_CHECK(igraph_vector_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_size(&new_cand);
    l = l - 1;
    for (i = 0; i < j; i++) {
      k = (long int)VECTOR(new_cand)[i];
      IGRAPH_CHECK(igraph_vector_intersect_sorted(&new_cand, igraph_adjlist_get(&adj_list, k), &cn));
      if (igraph_vector_size(&cn) > best_cand_degree) {
        best_cand_degree = igraph_vector_size(&cn);
        IGRAPH_CHECK(igraph_vector_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_init(&new_cand, 0));
    IGRAPH_CHECK(igraph_vector_init(&new_fini, 0));
    IGRAPH_CHECK(igraph_vector_init(&frame.cand_filtered, 0));

    /* Adjust frame.cand_filtered */
    if (best_cand_degree < best_fini_cand_degree) {
      IGRAPH_CHECK(igraph_vector_difference_sorted(&frame.cand, &best_fini_cand_nbrs, &frame.cand_filtered));
    } else {
      IGRAPH_CHECK(igraph_vector_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_destroy(&new_cand);
  igraph_vector_destroy(&new_fini);
  igraph_vector_destroy(&cn);
  igraph_vector_destroy(&best_cand_nbrs);
  igraph_vector_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;
}
Example #29
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;
}
Example #30
0
int igraph_i_maximal_independent_vertex_sets_backtrack(const igraph_t *graph,
						       igraph_vector_ptr_t *res,
						       igraph_i_max_ind_vsets_data_t *clqdata,
						       igraph_integer_t level) {
  long int v1, v2, v3, c, j, k;
  igraph_vector_t *neis1, *neis2;
  igraph_bool_t f;
  igraph_integer_t j1;
  long int it_state;

  IGRAPH_ALLOW_INTERRUPTION();

  if (level >= clqdata->matrix_size-1) {
    igraph_integer_t size=0;
    if (res) {
      igraph_vector_t *vec;
      vec = igraph_Calloc(1, igraph_vector_t);
      if (vec == 0)
        IGRAPH_ERROR("igraph_i_maximal_independent_vertex_sets failed", IGRAPH_ENOMEM);
      IGRAPH_VECTOR_INIT_FINALLY(vec, 0);
      for (v1=0; v1<clqdata->matrix_size; v1++)
	if (clqdata->IS[v1] == 0) {
	  IGRAPH_CHECK(igraph_vector_push_back(vec, v1));
	}
      size=igraph_vector_size(vec);
      if (!clqdata->keep_only_largest)
        IGRAPH_CHECK(igraph_vector_ptr_push_back(res, vec));
      else {
        if (size > clqdata->largest_set_size) {
          /* We are keeping only the largest sets, and we've found one that's
           * larger than all previous sets, so we have to clear the list */
          j=igraph_vector_ptr_size(res);
          for (v1=0; v1<j; v1++) {
            igraph_vector_destroy(VECTOR(*res)[v1]);
            free(VECTOR(*res)[v1]);
          }
          igraph_vector_ptr_clear(res);
          IGRAPH_CHECK(igraph_vector_ptr_push_back(res, vec));
        } else if (size == clqdata->largest_set_size) {
          IGRAPH_CHECK(igraph_vector_ptr_push_back(res, vec));
        } else {
		  igraph_vector_destroy(vec);
		  free(vec);
		}
      }
      IGRAPH_FINALLY_CLEAN(1);
    } else {
      for (v1=0, size=0; v1<clqdata->matrix_size; v1++)
	if (clqdata->IS[v1] == 0) size++;
    }
    if (size>clqdata->largest_set_size) clqdata->largest_set_size=size;
  } else {
    v1 = level+1;
    /* Count the number of vertices with an index less than v1 that have
     * an IS value of zero */
    neis1 = igraph_adjlist_get(&clqdata->adj_list, v1);
    c = 0;
    j = 0;
    while (j<VECTOR(clqdata->deg)[v1] && (v2=VECTOR(*neis1)[j]) <= level) {
      if (clqdata->IS[v2] == 0) c++;
      j++;
    }

    if (c == 0) {
      /* If there are no such nodes... */
      j = 0;
      while (j<VECTOR(clqdata->deg)[v1] && (v2=VECTOR(*neis1)[j]) <= level) {
	clqdata->IS[v2]++;
	j++;
      }
      IGRAPH_CHECK(igraph_i_maximal_independent_vertex_sets_backtrack(graph,res,clqdata,v1));
      j = 0;
      while (j<VECTOR(clqdata->deg)[v1] && (v2=VECTOR(*neis1)[j]) <= level) {
	clqdata->IS[v2]--;
	j++;
      }
    } else {
      /* If there are such nodes, store the count in the IS value of v1 */
      clqdata->IS[v1] = c;
      IGRAPH_CHECK(igraph_i_maximal_independent_vertex_sets_backtrack(graph,res,clqdata,v1));
      clqdata->IS[v1] = 0;
      
      f=1;
      j=0;
      while (j<VECTOR(clqdata->deg)[v1] && (v2=VECTOR(*neis1)[j]) <= level) {
	if (clqdata->IS[v2] == 0) {
	  IGRAPH_CHECK(igraph_set_add(&clqdata->buckets[v1], j));
	  neis2 = igraph_adjlist_get(&clqdata->adj_list, v2);
	  k = 0;
	  while (k<VECTOR(clqdata->deg)[v2] && (v3=VECTOR(*neis2)[k])<=level) {
	    clqdata->IS[v3]--;
	    if (clqdata->IS[v3] == 0) f=0;
	    k++;
	  }
	}
	clqdata->IS[v2]++;
	j++;
      }

      if (f) 
	IGRAPH_CHECK(igraph_i_maximal_independent_vertex_sets_backtrack(graph,res,clqdata,v1));

      j=0;
      while (j<VECTOR(clqdata->deg)[v1] && (v2=VECTOR(*neis1)[j]) <= level) {
	clqdata->IS[v2]--;
	j++;
      }
      
      it_state=0;
      while (igraph_set_iterate(&clqdata->buckets[v1], &it_state, &j1)) {
	j=(long)j1;
	v2=VECTOR(*neis1)[j];
	neis2 = igraph_adjlist_get(&clqdata->adj_list, v2);
	k = 0;
	while (k<VECTOR(clqdata->deg)[v2] && (v3=VECTOR(*neis2)[k])<=level) {
	  clqdata->IS[v3]++;
	  k++;
	}
      }
      igraph_set_clear(&clqdata->buckets[v1]);
    }
  }

  return 0;
}