示例#1
0
int igraph_is_separator(const igraph_t *graph, 
			const igraph_vs_t candidate,
			igraph_bool_t *res) {

  long int no_of_nodes=igraph_vcount(graph);
  igraph_vector_bool_t removed;
  igraph_dqueue_t Q;
  igraph_vector_t neis;
  igraph_vit_t vit;

  IGRAPH_CHECK(igraph_vit_create(graph, candidate, &vit));
  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
  IGRAPH_CHECK(igraph_vector_bool_init(&removed, no_of_nodes));
  IGRAPH_FINALLY(igraph_vector_bool_destroy, &removed);
  IGRAPH_CHECK(igraph_dqueue_init(&Q, 100));
  IGRAPH_FINALLY(igraph_dqueue_destroy, &Q);
  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);

  IGRAPH_CHECK(igraph_i_is_separator(graph, &vit, -1, res, &removed, 
				     &Q, &neis, no_of_nodes));

  igraph_vector_destroy(&neis);
  igraph_dqueue_destroy(&Q);
  igraph_vector_bool_destroy(&removed);
  igraph_vit_destroy(&vit);
  IGRAPH_FINALLY_CLEAN(4);

  return 0;
}
示例#2
0
int igraph_is_minimal_separator(const igraph_t *graph,
				const igraph_vs_t candidate, 
				igraph_bool_t *res) {

  long int no_of_nodes=igraph_vcount(graph);
  igraph_vector_bool_t removed;
  igraph_dqueue_t Q;
  igraph_vector_t neis;
  long int candsize;
  igraph_vit_t vit;
  
  IGRAPH_CHECK(igraph_vit_create(graph, candidate, &vit));
  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
  candsize=IGRAPH_VIT_SIZE(vit);

  IGRAPH_CHECK(igraph_vector_bool_init(&removed, no_of_nodes));
  IGRAPH_FINALLY(igraph_vector_bool_destroy, &removed);
  IGRAPH_CHECK(igraph_dqueue_init(&Q, 100));
  IGRAPH_FINALLY(igraph_dqueue_destroy, &Q);
  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);

  /* Is it a separator at all? */
  IGRAPH_CHECK(igraph_i_is_separator(graph, &vit, -1, res, &removed, 
				     &Q, &neis, no_of_nodes));
  if (!(*res)) {
    /* Not a separator at all, nothing to do, *res is already set */
  } else if (candsize == 0) {
    /* Nothing to do, minimal, *res is already set */
  } else {
    /* General case, we need to remove each vertex from 'candidate'
     * and check whether the remainder is a separator. If this is
     * false for all vertices, then 'candidate' is a minimal
     * separator.
     */
    long int i;
    for (i=0, *res=0; i<candsize && (!*res); i++) {
      igraph_vector_bool_null(&removed);
      IGRAPH_CHECK(igraph_i_is_separator(graph, &vit, i, res, &removed, 
					 &Q, &neis, no_of_nodes));    
    }
    (*res) = (*res) ? 0 : 1;	/* opposite */
  }
  
  igraph_vector_destroy(&neis);
  igraph_dqueue_destroy(&Q);
  igraph_vector_bool_destroy(&removed);
  igraph_vit_destroy(&vit);
  IGRAPH_FINALLY_CLEAN(4);

  return 0;
}
示例#3
0
int test_graph_from_leda_tutorial() {
  /* Test graph from the LEDA tutorial:
   * http://www.leda-tutorial.org/en/unofficial/ch05s03s05.html
   */
  igraph_t graph;
  igraph_vector_bool_t types;
  igraph_vector_long_t matching;
  igraph_integer_t matching_size;
   igraph_bool_t is_matching;
  int i;

  igraph_small(&graph, 0, 0,
      0, 8, 0, 12, 0, 14,
      1, 9, 1, 10, 1, 13,
      2, 8, 2, 9,
      3, 10, 3, 11, 3, 13,
      4, 9, 4, 14,
      5, 14,
      6, 9, 6, 14,
      7, 8, 7, 12, 7, 14
      , -1);
  igraph_vector_bool_init(&types, 15);
  for (i = 0; i < 15; i++)
    VECTOR(types)[i] = (i >= 8);
  igraph_vector_long_init(&matching, 0);

  igraph_i_maximum_bipartite_matching_unweighted(&graph, &types, &matching_size, &matching);
  if (matching_size != 6) {
    printf("matching_size is %ld, expected: 6\n", (long)matching_size);
    return 1;
  }
  igraph_is_maximal_matching(&graph, &types, &matching, &is_matching);
  if (!is_matching) {
    printf("not a matching: ");
    igraph_vector_long_print(&matching);
    return 3;
  }
  else
  igraph_vector_long_print(&matching);
  igraph_vector_long_destroy(&matching);
  igraph_vector_bool_destroy(&types);
  igraph_destroy(&graph);

  return 0;
}
示例#4
0
int igraph_bridges(const igraph_t *graph, igraph_vector_t *bridges) {
    igraph_inclist_t il;
    igraph_vector_bool_t visited;
    igraph_vector_int_t disc, low;
    igraph_vector_int_t parent;
    long n;
    long i;
    igraph_integer_t time;

    n = igraph_vcount(graph);

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

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

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

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

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

    igraph_vector_clear(bridges);

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

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

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

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

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

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

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

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

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

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

        IGRAPH_ALLOW_INTERRUPTION();

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

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

        } /* !igraph_stack_empty(&path) */

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

    } /* i < no_of_nodes */

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

    return 0;
}
示例#8
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;
}
示例#9
0
int igraph_i_is_separator(const igraph_t *graph,
			  igraph_vit_t *vit,
			  long int except,
			  igraph_bool_t *res,
			  igraph_vector_bool_t *removed,
			  igraph_dqueue_t *Q,
			  igraph_vector_t *neis,
			  long int no_of_nodes) {

  long int start=0;

  if (IGRAPH_VIT_SIZE(*vit) >= no_of_nodes-1) {
    /* Just need to check that we really have at least n-1 vertices in it */
    igraph_vector_bool_t hit;
    long int nohit=0;
    IGRAPH_CHECK(igraph_vector_bool_init(&hit, no_of_nodes));
    IGRAPH_FINALLY(igraph_vector_bool_destroy, &hit);
    for (IGRAPH_VIT_RESET(*vit); 
	 !IGRAPH_VIT_END(*vit); 
	 IGRAPH_VIT_NEXT(*vit)) {
      long int v=IGRAPH_VIT_GET(*vit);
      if (!VECTOR(hit)[v]) {
	nohit++;
	VECTOR(hit)[v] = 1;
      }
    }
    igraph_vector_bool_destroy(&hit);
    IGRAPH_FINALLY_CLEAN(1);
    if (nohit >= no_of_nodes-1) {
      *res = 0;
      return 0;
    }
  }
  
  /* Remove the given vertices from the graph, do a breadth-first
     search and check the number of components */  

  if (except < 0) {
    for (IGRAPH_VIT_RESET(*vit); 
	 !IGRAPH_VIT_END(*vit);
	 IGRAPH_VIT_NEXT(*vit)) {
      VECTOR(*removed)[ (long int) IGRAPH_VIT_GET(*vit) ] = 1;
    }
  } else {
    /* There is an exception */
    long int i;
    for (i=0, IGRAPH_VIT_RESET(*vit);
	 i<except; 
	 i++, IGRAPH_VIT_NEXT(*vit)) {
      VECTOR(*removed)[ (long int) IGRAPH_VIT_GET(*vit) ] = 1;
    }
    for (IGRAPH_VIT_NEXT(*vit); 
	 !IGRAPH_VIT_END(*vit); 
	 IGRAPH_VIT_NEXT(*vit)) {
      VECTOR(*removed)[ (long int) IGRAPH_VIT_GET(*vit) ] = 1;
    }
  }

  /* Look for the first node that is not removed */
  while (start < no_of_nodes && VECTOR(*removed)[start]) start++;
  
  if (start==no_of_nodes) { 
    IGRAPH_ERROR("All vertices are included in the separator", 
		 IGRAPH_EINVAL);
  }
  
  igraph_dqueue_push(Q, start);
  VECTOR(*removed)[start]=1;
  while (!igraph_dqueue_empty(Q)) {
    long int node=(long int) igraph_dqueue_pop(Q);
    long int j, n;
    igraph_neighbors(graph, neis, (igraph_integer_t) node, IGRAPH_ALL);
    n=igraph_vector_size(neis);
    for (j=0; j<n; j++) {
      long int nei=(long int) VECTOR(*neis)[j];
      if (!VECTOR(*removed)[nei]) {
	IGRAPH_CHECK(igraph_dqueue_push(Q, nei));
	VECTOR(*removed)[nei]=1;
      }
    }
  }
  
  /* Look for the next node that was neighter removed, not visited */
  while (start < no_of_nodes && VECTOR(*removed)[start]) start++;
  
  /* If there is another component, then we have a separator */
  *res = (start < no_of_nodes);

  return 0;
}
示例#10
0
QList<int> MWBM::run(QList<int> input_weights, int numberOfLeft, int numberOfRight, bool &isMatched)
{
    igraph_t graph;
    igraph_vector_bool_t types;
    igraph_vector_long_t matching;
    igraph_vector_t weights;
    igraph_integer_t matching_size;
    igraph_real_t matching_weight;
    igraph_bool_t is_matching;
    igraph_vector_t v;

    int i;
    QList<int> out;

    igraph_real_t weight_array[input_weights.size()];
    for(int j=0;j<input_weights.size();j++)
    {
        weight_array[j] = input_weights.at(j);
    };

    QList<int> edges_list;
    for(int j=0;j<numberOfLeft;j++)
    {
        for(int k=numberOfLeft;k<numberOfRight+numberOfLeft;k++)
        {
            edges_list.append(j);
            edges_list.append(k);
        }
    }

    igraph_real_t edges[edges_list.size()];

    for(int j=0;j<edges_list.size();j++)
    {
        edges[j] = edges_list.at(j);
    }

    igraph_vector_view(&v, edges, sizeof(edges)/sizeof(double));
    igraph_create(&graph, &v, 0, IGRAPH_DIRECTED);

    igraph_vector_bool_init(&types, numberOfLeft+numberOfRight);
    for (i = 0; i < numberOfLeft+numberOfRight; i++)
        VECTOR(types)[i] = (i >= numberOfLeft);
    igraph_vector_long_init(&matching, 0);
    igraph_vector_init_copy(&weights, weight_array,
                            sizeof(weight_array) / sizeof(weight_array[0]));

    igraph_maximum_bipartite_matching(&graph, &types, &matching_size,
                                      &matching_weight, &matching, &weights,DBL_EPSILON);

    igraph_is_maximal_matching(&graph, &types, &matching, &is_matching);
    if (!is_matching) {
        isMatched = false;
    }
    else
    {
        isMatched=true;
    }

    for(int j=0;j<numberOfLeft*2;j++)
        out.append(VECTOR(matching)[j]);

    igraph_vector_destroy(&weights);
    igraph_vector_long_destroy(&matching);
    igraph_vector_bool_destroy(&types);
    igraph_destroy(&graph);

    return out;
}
示例#11
0
int main() {
  igraph_t g;
  igraph_vector_t tdist;
  igraph_matrix_t pmat;
  igraph_bool_t conn;
  igraph_vector_bool_t bs;
  int i, ret;
  
  /* Symmetric preference game */
  igraph_vector_bool_init(&bs, 0);

  igraph_vector_init_real(&tdist, 3, 1.0, 1.0, 1.0);

  igraph_matrix_init(&pmat, 3, 3);
  for (i=0; i<3; i++) MATRIX(pmat, i, i) = 0.2;

  /* undirected, no loops */
  IGRAPH_CHECK(igraph_preference_game(&g, 1000, 3, &tdist, /*fixed_sizes=*/ 0,
				      &pmat, 0, 0, 0));
  if (igraph_vcount(&g) != 1000) return 18;
  if (igraph_is_directed(&g)) return 2;
  igraph_is_connected(&g, &conn, IGRAPH_STRONG);
  if (conn) return 3;
  igraph_is_loop(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
  if (igraph_vector_bool_sum(&bs)) return 4;
  igraph_is_multiple(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
  if (igraph_vector_bool_sum(&bs)) return 5;
  igraph_destroy(&g);

  for (i=0; i<2; i++) MATRIX(pmat, i, i+1) = 0.1;

  /* directed, no loops */
  IGRAPH_CHECK(igraph_preference_game(&g, 1000, 3, &tdist, /*fixed_sizes=*/0, 
				      &pmat, 0, 1, 0));
  if (igraph_vcount(&g) != 1000) return 17;
  if (!igraph_is_directed(&g)) return 6;
  igraph_is_loop(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
  if (igraph_vector_bool_sum(&bs)) return 7;
  igraph_is_multiple(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
  if (igraph_vector_bool_sum(&bs)) return 8;
  igraph_destroy(&g);

  /* undirected, loops */
  for (i=0; i<3; i++) MATRIX(pmat, i, i) = 1.0;
  IGRAPH_CHECK(igraph_preference_game(&g, 100, 3, &tdist, /*fixed_sizes=*/ 0,
				      &pmat, 0, 0, 1));
  if (igraph_vcount(&g) != 100) return 16;
  if (igraph_ecount(&g) < 1395) return 20;
  if (igraph_is_directed(&g)) return 9;
  igraph_is_loop(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
  if (igraph_vector_bool_sum(&bs) == 0) return 10;
  igraph_is_multiple(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
  if (igraph_vector_bool_sum(&bs)) return 11;
  igraph_destroy(&g);

  /* directed, loops */
  IGRAPH_CHECK(igraph_preference_game(&g, 100, 3, &tdist, /*fixed_sizes=*/ 0,
				      &pmat, 0, 1, 1));
  if (igraph_vcount(&g) != 100) return 15;
  if (igraph_ecount(&g) < 2700) return 19;
  if (!igraph_is_directed(&g)) return 12;
  igraph_is_loop(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
  if (igraph_vector_bool_sum(&bs) == 0) return 13;
  igraph_is_multiple(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
  if (igraph_vector_bool_sum(&bs)) return 14;
  igraph_destroy(&g);

  /* Asymmetric preference game */

  /* directed, no loops */
  igraph_matrix_resize(&pmat, 2, 2);
  MATRIX(pmat, 0, 0) = 1; MATRIX(pmat, 0, 1) = 1;
  MATRIX(pmat, 1, 0) = 1; MATRIX(pmat, 1, 1) = 1;
  IGRAPH_CHECK(igraph_asymmetric_preference_game(&g, 100, 2, 0, &pmat, 0, 0, 0));
  if (igraph_vcount(&g) != 100) return 21;
  if (igraph_ecount(&g) != 9900) return 22;
  if (!igraph_is_directed(&g)) return 23;
  igraph_is_loop(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
  if (igraph_vector_bool_sum(&bs)) return 24;
  igraph_is_multiple(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
  if (igraph_vector_bool_sum(&bs)) return 25;
  igraph_destroy(&g);

  /* directed, loops */
  igraph_matrix_resize(&pmat, 2, 2);
  MATRIX(pmat, 0, 0) = 1; MATRIX(pmat, 0, 1) = 1;
  MATRIX(pmat, 1, 0) = 1; MATRIX(pmat, 1, 1) = 1;
  IGRAPH_CHECK(igraph_asymmetric_preference_game(&g, 100, 2, 0, &pmat, 0, 0, 1));
  if (igraph_vcount(&g) != 100) return 26;
  if (igraph_ecount(&g) != 10000) return 27;
  if (!igraph_is_directed(&g)) return 28;
  igraph_is_loop(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
  if (igraph_vector_bool_sum(&bs) != 100) return 29;
  igraph_is_multiple(&g, &bs, igraph_ess_all(IGRAPH_EDGEORDER_ID));
  if (igraph_vector_bool_sum(&bs)) return 30;
  igraph_destroy(&g);

  igraph_vector_destroy(&tdist);
  igraph_matrix_destroy(&pmat);
  igraph_vector_bool_destroy(&bs);

  assert(IGRAPH_FINALLY_STACK_EMPTY);

  return 0;
}