/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard street, Cambridge, MA 02139 USA
   
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
   02110-1301 USA

*/

#include "igraph_constructors.h"
#include "igraph_structural.h"
#include "igraph_memory.h"
#include "igraph_interface.h"
#include "igraph_attributes.h"
#include "igraph_adjlist.h"
#include "igraph_interrupt_internal.h"
#include "igraph_dqueue.h"
#include "config.h"

#include <stdarg.h>
#include <math.h>
#include <string.h>

/** 
 * \section about_generators
 *
 * <para>Graph generators create graphs.</para>
 * 
 * <para>Almost all functions which create graph objects are documented
 * here. The exceptions are \ref igraph_subgraph() and alike, these 
 * create graphs based on another graph.</para>
 */


/**
 * \ingroup generators
 * \function igraph_create
 * \brief Creates a graph with the specified edges.
 * 
 * \param graph An uninitialized graph object.
 * \param edges The edges to add, the first two elements are the first
 *        edge, etc.
 * \param n The number of vertices in the graph, if smaller or equal
 *        to the highest vertex id in the \p edges vector it
 *        will be increased automatically. So it is safe to give 0
 *        here.
 * \param directed Boolean, whether to create a directed graph or
 *        not. If yes, then the first edge points from the first
 *        vertex id in \p edges to the second, etc.
 * \return Error code:
 *         \c IGRAPH_EINVEVECTOR: invalid edges
 *         vector (odd number of vertices).
 *         \c IGRAPH_EINVVID: invalid (negative)
 *         vertex id. 
 *
 * Time complexity: O(|V|+|E|),
 * |V| is the number of vertices,
 * |E| the number of edges in the
 * graph. 
 * 
 * \example examples/simple/igraph_create.c
 */
int igraph_create(igraph_t *graph, const igraph_vector_t *edges,
		igraph_integer_t n, igraph_bool_t directed) {
  igraph_bool_t has_edges=igraph_vector_size(edges) > 0;
  igraph_real_t max=has_edges ? igraph_vector_max(edges)+1 : 0;

  if (igraph_vector_size(edges) % 2 != 0) {
    IGRAPH_ERROR("Invalid (odd) edges vector", IGRAPH_EINVEVECTOR);
  }
  if (has_edges && !igraph_vector_isininterval(edges, 0, max-1)) {
    IGRAPH_ERROR("Invalid (negative) vertex id", IGRAPH_EINVVID);
  }

  IGRAPH_CHECK(igraph_empty(graph, n, directed));
  IGRAPH_FINALLY(igraph_destroy, graph);
  if (has_edges) {
    igraph_integer_t vc=igraph_vcount(graph);
    if (vc < max) {
      IGRAPH_CHECK(igraph_add_vertices(graph, (igraph_integer_t) (max-vc), 0));
    }
    IGRAPH_CHECK(igraph_add_edges(graph, edges, 0));
  }

  IGRAPH_FINALLY_CLEAN(1);
  return 0;
}

int igraph_i_adjacency_directed(igraph_matrix_t *adjmatrix, 
				igraph_vector_t *edges);
int igraph_i_adjacency_max(igraph_matrix_t *adjmatrix, 
			   igraph_vector_t *edges);
int igraph_i_adjacency_upper(igraph_matrix_t *adjmatrix, 
			     igraph_vector_t *edges);
int igraph_i_adjacency_lower(igraph_matrix_t *adjmatrix, 
			     igraph_vector_t *edges);
int igraph_i_adjacency_min(igraph_matrix_t *adjmatrix, 
			   igraph_vector_t *edges);

int igraph_i_adjacency_directed(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
  
  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
  long int i, j, k;
  
  for (i=0; i<no_of_nodes; i++) {
    for (j=0; j<no_of_nodes; j++) {
      long int M=(long int) MATRIX(*adjmatrix, i, j);
      for (k=0; k<M; k++) {
	IGRAPH_CHECK(igraph_vector_push_back(edges, i));
	IGRAPH_CHECK(igraph_vector_push_back(edges, j));
      }
    }
  }
  
  return 0;
}

int igraph_i_adjacency_max(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
  
  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
  long int i, j, k;
  
  for (i=0; i<no_of_nodes; i++) {
    for (j=i; j<no_of_nodes; j++) {
      long int M1=(long int) MATRIX(*adjmatrix, i, j);
      long int M2=(long int) MATRIX(*adjmatrix, j, i);
      if (M1<M2) { M1=M2; }
      for (k=0; k<M1; k++) {
	IGRAPH_CHECK(igraph_vector_push_back(edges, i));
	IGRAPH_CHECK(igraph_vector_push_back(edges, j));
      }
    }
  }
  
  return 0;
}

int igraph_i_adjacency_upper(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
  
  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
  long int i, j, k;
  
  for (i=0; i<no_of_nodes; i++) {
    for (j=i; j<no_of_nodes; j++) {
      long int M=(long int) MATRIX(*adjmatrix, i, j);
      for (k=0; k<M; k++) {
	IGRAPH_CHECK(igraph_vector_push_back(edges, i));
	IGRAPH_CHECK(igraph_vector_push_back(edges, j));
      }
    }
  }
  return 0;
}

int igraph_i_adjacency_lower(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {

  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
  long int i, j, k;
  
  for (i=0; i<no_of_nodes; i++) {
    for (j=0; j<=i; j++) {
      long int M=(long int) MATRIX(*adjmatrix, i, j);
      for (k=0; k<M; k++) {
	IGRAPH_CHECK(igraph_vector_push_back(edges, i));
	IGRAPH_CHECK(igraph_vector_push_back(edges, j));
      }
    }
  }
  return 0;
}

int igraph_i_adjacency_min(igraph_matrix_t *adjmatrix, igraph_vector_t *edges) {
  
  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
  long int i, j, k;
  
  for (i=0; i<no_of_nodes; i++) {
    for (j=i; j<no_of_nodes; j++) {
      long int M1=(long int) MATRIX(*adjmatrix, i, j);
      long int M2=(long int) MATRIX(*adjmatrix, j, i);
      if (M1>M2) { M1=M2; }
      for (k=0; k<M1; k++) {
	IGRAPH_CHECK(igraph_vector_push_back(edges, i));
	IGRAPH_CHECK(igraph_vector_push_back(edges, j));
      }
    }
  }
  
  return 0;
}

/**
 * \ingroup generators
 * \function igraph_adjacency
 * \brief Creates a graph object from an adjacency matrix.
 * 
 * The order of the vertices in the matrix is preserved, i.e. the vertex 
 * corresponding to the first row/column will be vertex with id 0, the 
 * next row is for vertex 1, etc.
 * \param graph Pointer to an uninitialized graph object.
 * \param adjmatrix The adjacency matrix. How it is interpreted
 *        depends on the \p mode argument.
 * \param mode Constant to specify how the given matrix is interpreted
 *        as an adjacency matrix. Possible values
 *        (A(i,j) 
 *        is the element in row i and column
 *        j in the adjacency matrix
 *        \p adjmatrix): 
 *        \clist
 *        \cli IGRAPH_ADJ_DIRECTED
 *          the graph will be directed and
 *          an element gives the number of edges between two vertices.
 *        \cli IGRAPH_ADJ_UNDIRECTED
 *          this is the same as \c IGRAPH_ADJ_MAX,
 *          for convenience. 
 *        \cli IGRAPH_ADJ_MAX
 *          undirected graph will be created
 *          and the number of edges between vertices
 *          i and 
 *          j is
 *          max(A(i,j), A(j,i)). 
 *        \cli IGRAPH_ADJ_MIN
 *          undirected graph will be created
 *          with min(A(i,j), A(j,i))
 *          edges between vertices
 *          i and
 *          j. 
 *        \cli IGRAPH_ADJ_PLUS 
 *          undirected graph will be created 
 *          with A(i,j)+A(j,i) edges
 *          between vertices
 *          i and
 *          j.  
 *        \cli IGRAPH_ADJ_UPPER 
 *          undirected graph will be created,
 *          only the upper right triangle (including the diagonal) is
 *          used for the number of edges.
 *        \cli IGRAPH_ADJ_LOWER 
 *          undirected graph will be created,
 *          only the lower left triangle (including the diagonal) is 
 *          used for creating the edges.
 *       \endclist
 * \return Error code,
 *         \c IGRAPH_NONSQUARE: non-square matrix.
 * 
 * Time complexity: O(|V||V|),
 * |V| is the number of vertices in the graph.
 * 
 * \example examples/simple/igraph_adjacency.c
 */

int igraph_adjacency(igraph_t *graph, igraph_matrix_t *adjmatrix,
		     igraph_adjacency_t mode) {

  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
  long int no_of_nodes;

  /* Some checks */
  if (igraph_matrix_nrow(adjmatrix) != igraph_matrix_ncol(adjmatrix)) {
    IGRAPH_ERROR("Non-square matrix", IGRAPH_NONSQUARE);
  }

  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  
  /* Collect the edges */
  no_of_nodes=igraph_matrix_nrow(adjmatrix);
  switch (mode) {
  case IGRAPH_ADJ_DIRECTED:
    IGRAPH_CHECK(igraph_i_adjacency_directed(adjmatrix, &edges));
    break;
  case IGRAPH_ADJ_MAX:
    IGRAPH_CHECK(igraph_i_adjacency_max(adjmatrix, &edges));
    break;
  case IGRAPH_ADJ_UPPER:
    IGRAPH_CHECK(igraph_i_adjacency_upper(adjmatrix, &edges));
    break;
  case IGRAPH_ADJ_LOWER:
    IGRAPH_CHECK(igraph_i_adjacency_lower(adjmatrix, &edges));
    break;
  case IGRAPH_ADJ_MIN:
    IGRAPH_CHECK(igraph_i_adjacency_min(adjmatrix, &edges));
    break;
  case IGRAPH_ADJ_PLUS:
    IGRAPH_CHECK(igraph_i_adjacency_directed(adjmatrix, &edges));
    break;
  }

  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes, 
			     (mode == IGRAPH_ADJ_DIRECTED))); 
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  
  return 0;
}

int igraph_i_weighted_adjacency_directed(const igraph_matrix_t *adjmatrix,
					 igraph_vector_t *edges, 
					 igraph_vector_t *weights, 
					 igraph_bool_t loops);
int igraph_i_weighted_adjacency_plus(const igraph_matrix_t *adjmatrix,
				     igraph_vector_t *edges,
				     igraph_vector_t *weights, 
				     igraph_bool_t loops);
int igraph_i_weighted_adjacency_max(const igraph_matrix_t *adjmatrix,
				    igraph_vector_t *edges, 
				    igraph_vector_t *weights, 
				    igraph_bool_t loops);
int igraph_i_weighted_adjacency_upper(const igraph_matrix_t *adjmatrix,
				      igraph_vector_t *edges, 
				      igraph_vector_t *weights,
				      igraph_bool_t loops);
int igraph_i_weighted_adjacency_lower(const igraph_matrix_t *adjmatrix,
				      igraph_vector_t *edges, 
				      igraph_vector_t *weights, 
				      igraph_bool_t loops);
int igraph_i_weighted_adjacency_min(const igraph_matrix_t *adjmatrix,
				    igraph_vector_t *edges,
				    igraph_vector_t *weights, 
				    igraph_bool_t loops);

int igraph_i_weighted_adjacency_directed(const igraph_matrix_t *adjmatrix,
					 igraph_vector_t *edges, 
					 igraph_vector_t *weights, 
					 igraph_bool_t loops) {
  
  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
  long int i, j;
  
  for (i=0; i<no_of_nodes; i++) {
    for (j=0; j<no_of_nodes; j++) {
      igraph_real_t M=MATRIX(*adjmatrix, i, j);
      if (M == 0.0) continue;
      if (i==j && !loops) { continue; }
      IGRAPH_CHECK(igraph_vector_push_back(edges, i));
      IGRAPH_CHECK(igraph_vector_push_back(edges, j));
      IGRAPH_CHECK(igraph_vector_push_back(weights, M));
    }
  }
  
  return 0;
}

int igraph_i_weighted_adjacency_plus(const igraph_matrix_t *adjmatrix,
				     igraph_vector_t *edges,
				     igraph_vector_t *weights, 
				     igraph_bool_t loops) {
  
  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
  long int i, j;
  
  for (i=0; i<no_of_nodes; i++) {
    for (j=i; j<no_of_nodes; j++) {
      igraph_real_t M=MATRIX(*adjmatrix, i, j) + MATRIX(*adjmatrix, j, i);
      if (M == 0.0) continue;
      if (i==j && !loops) { continue; }
      if (i == j) M /= 2;
      IGRAPH_CHECK(igraph_vector_push_back(edges, i));
      IGRAPH_CHECK(igraph_vector_push_back(edges, j));
      IGRAPH_CHECK(igraph_vector_push_back(weights, M));
    }
  }
  
  return 0;
}

int igraph_i_weighted_adjacency_max(const igraph_matrix_t *adjmatrix,
				    igraph_vector_t *edges, 
				    igraph_vector_t *weights, 
				    igraph_bool_t loops) {
  
  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
  long int i, j;
  
  for (i=0; i<no_of_nodes; i++) {
    for (j=i; j<no_of_nodes; j++) {
      igraph_real_t M1=MATRIX(*adjmatrix, i, j);
      igraph_real_t M2=MATRIX(*adjmatrix, j, i);
      if (M1<M2) { M1=M2; }
      if (M1 == 0.0) continue;
      if (i==j && !loops) { continue; }
      IGRAPH_CHECK(igraph_vector_push_back(edges, i));
      IGRAPH_CHECK(igraph_vector_push_back(edges, j));
      IGRAPH_CHECK(igraph_vector_push_back(weights, M1));
    }
  }
  return 0;
}

int igraph_i_weighted_adjacency_upper(const igraph_matrix_t *adjmatrix,
				      igraph_vector_t *edges, 
				      igraph_vector_t *weights,
				      igraph_bool_t loops) {
  
  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
  long int i, j;
  
  for (i=0; i<no_of_nodes; i++) {
    for (j=i; j<no_of_nodes; j++) {
      igraph_real_t M=MATRIX(*adjmatrix, i, j);
      if (M == 0.0) continue;
      if (i==j && !loops) { continue; }
      IGRAPH_CHECK(igraph_vector_push_back(edges, i));
      IGRAPH_CHECK(igraph_vector_push_back(edges, j));
      IGRAPH_CHECK(igraph_vector_push_back(weights, M));
    }
  }
  return 0;
}

int igraph_i_weighted_adjacency_lower(const igraph_matrix_t *adjmatrix,
				      igraph_vector_t *edges, 
				      igraph_vector_t *weights, 
				      igraph_bool_t loops) {

  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
  long int i, j;
  
  for (i=0; i<no_of_nodes; i++) {
    for (j=0; j<=i; j++) {
      igraph_real_t M=MATRIX(*adjmatrix, i, j);
      if (M == 0.0) continue;
      if (i==j && !loops) { continue; }
      IGRAPH_CHECK(igraph_vector_push_back(edges, i));
      IGRAPH_CHECK(igraph_vector_push_back(edges, j));
      IGRAPH_CHECK(igraph_vector_push_back(weights, M));
    }
  }
  return 0;
}

int igraph_i_weighted_adjacency_min(const igraph_matrix_t *adjmatrix,
				    igraph_vector_t *edges,
				    igraph_vector_t *weights, 
				    igraph_bool_t loops) {
  
  long int no_of_nodes=igraph_matrix_nrow(adjmatrix);
  long int i, j;
  
  for (i=0; i<no_of_nodes; i++) {
    for (j=i; j<no_of_nodes; j++) {
      igraph_real_t M1=MATRIX(*adjmatrix, i, j);
      igraph_real_t M2=MATRIX(*adjmatrix, j, i);
      if (M1>M2) { M1=M2; }
      if (M1 == 0.0) continue;
      if (i==j && !loops) { continue; }
      IGRAPH_CHECK(igraph_vector_push_back(edges, i));
      IGRAPH_CHECK(igraph_vector_push_back(edges, j));
      IGRAPH_CHECK(igraph_vector_push_back(weights, M1));
    }
  }
  
  return 0;
}

/**
 * \ingroup generators
 * \function igraph_weighted_adjacency
 * \brief Creates a graph object from a weighted adjacency matrix.
 * 
 * The order of the vertices in the matrix is preserved, i.e. the vertex 
 * corresponding to the first row/column will be vertex with id 0, the 
 * next row is for vertex 1, etc.
 * \param graph Pointer to an uninitialized graph object.
 * \param adjmatrix The weighted adjacency matrix. How it is interpreted
 *        depends on the \p mode argument. The common feature is that
 *        edges with zero weights are considered nonexistent (however,
 *        negative weights are permitted).
 * \param mode Constant to specify how the given matrix is interpreted
 *        as an adjacency matrix. Possible values
 *        (A(i,j) 
 *        is the element in row i and column
 *        j in the adjacency matrix
 *        \p adjmatrix): 
 *        \clist
 *        \cli IGRAPH_ADJ_DIRECTED
 *          the graph will be directed and
 *          an element gives the weight of the edge between two vertices.
 *        \cli IGRAPH_ADJ_UNDIRECTED
 *          this is the same as \c IGRAPH_ADJ_MAX,
 *          for convenience. 
 *        \cli IGRAPH_ADJ_MAX
 *          undirected graph will be created
 *          and the weight of the edge between vertices
 *          i and 
 *          j is
 *          max(A(i,j), A(j,i)). 
 *        \cli IGRAPH_ADJ_MIN
 *          undirected graph will be created
 *          with edge weight min(A(i,j), A(j,i))
 *          between vertices
 *          i and
 *          j. 
 *        \cli IGRAPH_ADJ_PLUS 
 *          undirected graph will be created 
 *          with edge weight A(i,j)+A(j,i)
 *          between vertices
 *          i and
 *          j.  
 *        \cli IGRAPH_ADJ_UPPER 
 *          undirected graph will be created,
 *          only the upper right triangle (including the diagonal) is
 *          used for the edge weights.
 *        \cli IGRAPH_ADJ_LOWER 
 *          undirected graph will be created,
 *          only the lower left triangle (including the diagonal) is 
 *          used for the edge weights. 
 *       \endclist
 * \param attr the name of the attribute that will store the edge weights.
 *         If \c NULL , it will use \c weight as the attribute name.
 * \param loops Logical scalar, whether to ignore the diagonal elements 
 *         in the adjacency matrix. 
 * \return Error code,
 *         \c IGRAPH_NONSQUARE: non-square matrix.
 * 
 * Time complexity: O(|V||V|),
 * |V| is the number of vertices in the graph.
 * 
 * \example examples/simple/igraph_weighted_adjacency.c
 */

int igraph_weighted_adjacency(igraph_t *graph, igraph_matrix_t *adjmatrix,
			      igraph_adjacency_t mode, const char* attr, 
			      igraph_bool_t loops) {

  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
  igraph_vector_t weights=IGRAPH_VECTOR_NULL;
  const char* default_attr = "weight";
  igraph_vector_ptr_t attr_vec;
  igraph_attribute_record_t attr_rec;
  long int no_of_nodes;

  /* Some checks */
  if (igraph_matrix_nrow(adjmatrix) != igraph_matrix_ncol(adjmatrix)) {
    IGRAPH_ERROR("Non-square matrix", IGRAPH_NONSQUARE);
  }

  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  IGRAPH_VECTOR_INIT_FINALLY(&weights, 0);
  IGRAPH_VECTOR_PTR_INIT_FINALLY(&attr_vec, 1);

  /* Collect the edges */
  no_of_nodes=igraph_matrix_nrow(adjmatrix);
  switch (mode) {
  case IGRAPH_ADJ_DIRECTED:
    IGRAPH_CHECK(igraph_i_weighted_adjacency_directed(adjmatrix, &edges, 
						      &weights, loops));
    break;
  case IGRAPH_ADJ_MAX:
    IGRAPH_CHECK(igraph_i_weighted_adjacency_max(adjmatrix, &edges, 
						 &weights, loops));
    break;
  case IGRAPH_ADJ_UPPER:
    IGRAPH_CHECK(igraph_i_weighted_adjacency_upper(adjmatrix, &edges,
						   &weights, loops));
    break;
  case IGRAPH_ADJ_LOWER:
    IGRAPH_CHECK(igraph_i_weighted_adjacency_lower(adjmatrix, &edges, 
						   &weights, loops));
    break;
  case IGRAPH_ADJ_MIN:
    IGRAPH_CHECK(igraph_i_weighted_adjacency_min(adjmatrix, &edges,
						 &weights, loops));
    break;
  case IGRAPH_ADJ_PLUS:
    IGRAPH_CHECK(igraph_i_weighted_adjacency_plus(adjmatrix, &edges,
						  &weights, loops));
    break;
  }

  /* Prepare attribute record */
  attr_rec.name = attr ? attr : default_attr;
  attr_rec.type = IGRAPH_ATTRIBUTE_NUMERIC;
  attr_rec.value = &weights;
  VECTOR(attr_vec)[0] = &attr_rec;

  /* Create graph */
  IGRAPH_CHECK(igraph_empty(graph, (igraph_integer_t) no_of_nodes, 
			    (mode == IGRAPH_ADJ_DIRECTED)));
  IGRAPH_FINALLY(igraph_destroy, graph);
  if (igraph_vector_size(&edges)>0) {
    IGRAPH_CHECK(igraph_add_edges(graph, &edges, &attr_vec));
  }
  IGRAPH_FINALLY_CLEAN(1);

  /* Cleanup */
  igraph_vector_destroy(&edges);
  igraph_vector_destroy(&weights);
  igraph_vector_ptr_destroy(&attr_vec);
  IGRAPH_FINALLY_CLEAN(3);
  
  return 0;
}

/**
 * \ingroup generators
 * \function igraph_star
 * \brief Creates a \em star graph, every vertex connects only to the center.
 *
 * \param graph Pointer to an uninitialized graph object, this will
 *        be the result.
 * \param n Integer constant, the number of vertices in the graph.
 * \param mode Constant, gives the type of the star graph to
 *        create. Possible values:
 *        \clist
 *        \cli IGRAPH_STAR_OUT
 *          directed star graph, edges point
 *          \em from the center to the other vertices.
 *        \cli IGRAPH_STAR_IN
 *          directed star graph, edges point
 *          \em to the center from the other vertices.
 *        \cli IGRAPH_STAR_MUTUAL
 *          directed star graph with mutual edges.
 *        \cli IGRAPH_STAR_UNDIRECTED 
 *          an undirected star graph is
 *          created. 
 *        \endclist
 * \param center Id of the vertex which will be the center of the
 *          graph. 
 * \return Error code:
 *         \clist
 *         \cli IGRAPH_EINVVID 
 *           invalid number of vertices.
 *         \cli IGRAPH_EINVAL 
 *           invalid center vertex.
 *         \cli IGRAPH_EINVMODE 
 *           invalid mode argument.
 *         \endclist
 * 
 * Time complexity: O(|V|), the
 * number of vertices in the graph.
 *
 * \sa \ref igraph_lattice(), \ref igraph_ring(), \ref igraph_tree()
 * for creating other regular structures.
 * 
 * \example examples/simple/igraph_star.c
 */

int igraph_star(igraph_t *graph, igraph_integer_t n, igraph_star_mode_t mode, 
		igraph_integer_t center) {

  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
  long int i;

  if (n<0) { 
    IGRAPH_ERROR("Invalid number of vertices", IGRAPH_EINVVID);
  }
  if (center<0 || center >n-1) {
    IGRAPH_ERROR("Invalid center vertex", IGRAPH_EINVAL);
  }
  if (mode != IGRAPH_STAR_OUT && mode != IGRAPH_STAR_IN && 
      mode != IGRAPH_STAR_MUTUAL && mode != IGRAPH_STAR_UNDIRECTED) {
    IGRAPH_ERROR("invalid mode", IGRAPH_EINVMODE);
  }
  
  if (mode != IGRAPH_STAR_MUTUAL) {
    IGRAPH_VECTOR_INIT_FINALLY(&edges, (n-1)*2);
  } else {
    IGRAPH_VECTOR_INIT_FINALLY(&edges, (n-1)*2*2);
  }
  
  if (mode == IGRAPH_STAR_OUT) {
    for (i=0; i<center; i++) {
      VECTOR(edges)[2*i]=center;
      VECTOR(edges)[2*i+1]=i;
    }
    for (i=center+1; i<n; i++) {
      VECTOR(edges)[2*(i-1)]=center;
      VECTOR(edges)[2*(i-1)+1]=i;
    }
  } else if (mode == IGRAPH_STAR_MUTUAL) {
    for (i=0; i<center; i++) {
      VECTOR(edges)[4*i]=center;
      VECTOR(edges)[4*i+1]=i;
      VECTOR(edges)[4*i+2]=i;
      VECTOR(edges)[4*i+3]=center;
    }
    for (i=center+1; i<n; i++) {
      VECTOR(edges)[4*i-4]=center;
      VECTOR(edges)[4*i-3]=i;
      VECTOR(edges)[4*i-2]=i;
      VECTOR(edges)[4*i-1]=center;
    }
  } else {
    for (i=0; i<center; i++) {
      VECTOR(edges)[2*i+1]=center;
      VECTOR(edges)[2*i]=i;
    }
    for (i=center+1; i<n; i++) {
      VECTOR(edges)[2*(i-1)+1]=center;
      VECTOR(edges)[2*(i-1)]=i;
    }
  }
  
  IGRAPH_CHECK(igraph_create(graph, &edges, 0, 
			     (mode != IGRAPH_STAR_UNDIRECTED)));
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  
  return 0;
}

/**
 * \ingroup generators 
 * \function igraph_lattice
 * \brief Creates most kinds of lattices.
 *
 * \param graph An uninitialized graph object.
 * \param dimvector Vector giving the sizes of the lattice in each of
 *        its dimensions. Ie. the dimension of the lattice will be the
 *        same as the length of this vector.
 * \param nei Integer value giving the distance (number of steps)
 *        within which two vertices will be connected.
 * \param directed Boolean, whether to create a directed graph. The
 *        direction of the edges is determined by the generation
 *        algorithm and is unlikely to suit you, so this isn't a very
 *        useful option.
 * \param mutual Boolean, if the graph is directed this gives whether
 *        to create all connections as mutual.
 * \param circular Boolean, defines whether the generated lattice is
 *        periodic.
 * \return Error code:
 *         \c IGRAPH_EINVAL: invalid (negative)
 *         dimension vector. 
 *
 * Time complexity: if \p nei is less than two then it is O(|V|+|E|) (as
 * far as I remember), |V| and |E| are the number of vertices 
 * and edges in the generated graph. Otherwise it is O(|V|*d^o+|E|), d
 * is the average degree of the graph, o is the \p nei argument.
 */
int igraph_lattice(igraph_t *graph, const igraph_vector_t *dimvector,
		igraph_integer_t nei, igraph_bool_t directed, igraph_bool_t mutual,
		igraph_bool_t circular) {

  long int dims=igraph_vector_size(dimvector);
  long int no_of_nodes=(long int) igraph_vector_prod(dimvector);
  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
  long int *coords, *weights;
  long int i, j;
  int carry, pos;

  if (igraph_vector_any_smaller(dimvector, 0)) {
    IGRAPH_ERROR("Invalid dimension vector", IGRAPH_EINVAL);
  }

  /* init coords & weights */

  coords=igraph_Calloc(dims, long int);
  if (coords==0) {
    IGRAPH_ERROR("lattice failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(free, coords);	/* TODO: hack */
  weights=igraph_Calloc(dims, long int);
  if (weights == 0) {
    IGRAPH_ERROR("lattice failed", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(free, weights);
  if (dims > 0) {
    weights[0]=1;
    for (i=1; i<dims; i++) {
      weights[i]=weights[i-1] * (long int) VECTOR(*dimvector)[i-1];
    }
  }
  
  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_nodes*dims +
				     mutual*directed * no_of_nodes*dims));

  for (i=0; i<no_of_nodes; i++) {
    IGRAPH_ALLOW_INTERRUPTION();
    for (j=0; j<dims; j++) {
      if (circular || coords[j] != VECTOR(*dimvector)[j]-1) {
	long int new_nei;
	if (coords[j] != VECTOR(*dimvector)[j]-1) {
	  new_nei = i + weights[j] + 1;
	} else {
	  new_nei = i - (long int) (VECTOR(*dimvector)[j]-1) * weights[j] + 1;
	}
	if (new_nei != i+1 && 
	    (VECTOR(*dimvector)[j] != 2 || coords[j] != 1 || directed)) {
	  igraph_vector_push_back(&edges, i); /* reserved */
	  igraph_vector_push_back(&edges, new_nei-1); /* reserved */
	}
      } /* if circular || coords[j] */
      if (mutual && directed && (circular || coords[j] != 0)) {
	long int new_nei;
	if (coords[j]!=0) {
	  new_nei=i-weights[j]+1;
	} else {
	  new_nei=i + (long int) (VECTOR(*dimvector)[j]-1) * weights[j]+1;
	}
	if (new_nei != i+1 && 
	    (VECTOR(*dimvector)[j] != 2 || !circular)) {
	  igraph_vector_push_back(&edges, i); /* reserved */
	  igraph_vector_push_back(&edges, new_nei-1); /* reserved */
	}
      } /* if circular || coords[0] */
    } /* for j<dims */
    
    /* increase coords */
    carry=1;
    pos=0;
    
    while (carry==1 && pos != dims) {
      if (coords[pos] != VECTOR(*dimvector)[pos]-1) {
	coords[pos]++;
	carry=0;
      } else {
	coords[pos]=0;
	pos++;
      }
    }
    
  } /* for i<no_of_nodes */

  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes, 
			     directed));
  if (nei >= 2) {
    IGRAPH_CHECK(igraph_connect_neighborhood(graph, nei, IGRAPH_ALL));
  }

  /* clean up */
  igraph_Free(coords);
  igraph_Free(weights);
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(3);

  return 0;
}

/**
 * \ingroup generators
 * \function igraph_ring
 * \brief Creates a \em ring graph, a one dimensional lattice.
 * 
 * An undirected (circular) ring on n vertices is commonly known in graph
 * theory as the cycle graph C_n.
 *
 * \param graph Pointer to an uninitialized graph object.
 * \param n The number of vertices in the ring.
 * \param directed Logical, whether to create a directed ring.
 * \param mutual Logical, whether to create mutual edges in a directed
 *        ring. It is ignored for undirected graphs.
 * \param circular Logical, if false, the ring will be open (this is
 *        not a real \em ring actually).
 * \return Error code:
 *         \c IGRAPH_EINVAL: invalid number of vertices.
 * 
 * Time complexity: O(|V|), the
 * number of vertices in the graph.
 *
 * \sa \ref igraph_lattice() for generating more general lattices.
 * 
 * \example examples/simple/igraph_ring.c
 */

int igraph_ring(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed,
		igraph_bool_t mutual, igraph_bool_t circular) {
  
  igraph_vector_t v=IGRAPH_VECTOR_NULL;

  if (n<0) {
    IGRAPH_ERROR("negative number of vertices", IGRAPH_EINVAL);
  }
  
  IGRAPH_VECTOR_INIT_FINALLY(&v, 1);
  VECTOR(v)[0]=n;
  
  IGRAPH_CHECK(igraph_lattice(graph, &v, 1, directed, mutual, circular));
  igraph_vector_destroy(&v);		 
  
  IGRAPH_FINALLY_CLEAN(1);
  return 0;
}

/**
 * \ingroup generators
 * \function igraph_tree
 * \brief Creates a tree in which almost all vertices have the same number of children.
 *
 * \param graph Pointer to an uninitialized graph object.
 * \param n Integer, the number of vertices in the graph.
 * \param children Integer, the number of children of a vertex in the
 *        tree. 
 * \param type Constant, gives whether to create a directed tree, and
 *        if this is the case, also its orientation. Possible values:
 *        \clist
 *        \cli IGRAPH_TREE_OUT 
 *          directed tree, the edges point
 *          from the parents to their children,
 *        \cli IGRAPH_TREE_IN 
 *          directed tree, the edges point from
 *          the children to their parents.
 *        \cli IGRAPH_TREE_UNDIRECTED
 *          undirected tree.
 *        \endclist
 * \return Error code:
 *         \c IGRAPH_EINVAL: invalid number of vertices.
 *         \c IGRAPH_INVMODE: invalid mode argument.
 * 
 * Time complexity: O(|V|+|E|), the
 * number of vertices plus the number of edges in the graph.
 * 
 * \sa \ref igraph_lattice(), \ref igraph_star() for creating other regular
 * structures. 
 * 
 * \example examples/simple/igraph_tree.c
 */

int igraph_tree(igraph_t *graph, igraph_integer_t n, igraph_integer_t children, 
		igraph_tree_mode_t type) {
  
  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
  long int i, j;
  long int idx=0;
  long int to=1;

  if (n<0 || children<=0) {
    IGRAPH_ERROR("Invalid number of vertices or children", IGRAPH_EINVAL);
  }
  if (type != IGRAPH_TREE_OUT && type != IGRAPH_TREE_IN &&
      type != IGRAPH_TREE_UNDIRECTED) {
    IGRAPH_ERROR("Invalid mode argument", IGRAPH_EINVMODE);
  }
  
  IGRAPH_VECTOR_INIT_FINALLY(&edges, 2*(n-1));
  
  i=0;
  if (type == IGRAPH_TREE_OUT) {
    while (idx<2*(n-1)) {
      for (j=0; j<children && idx<2*(n-1); j++) {
	VECTOR(edges)[idx++]=i;
	VECTOR(edges)[idx++]=to++;
      }
      i++;
    }
  } else {
    while (idx<2*(n-1)) {
      for (j=0; j<children && idx<2*(n-1); j++) {
	VECTOR(edges)[idx++]=to++;
	VECTOR(edges)[idx++]=i;
      }
      i++;
    }
  }
      
  IGRAPH_CHECK(igraph_create(graph, &edges, n, type!=IGRAPH_TREE_UNDIRECTED));
  
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  return 0;
}

/**
 * \ingroup generators
 * \function igraph_full
 * \brief Creates a full graph (directed or undirected, with or without loops). 
 * 
 * </para><para>
 * In a full graph every possible edge is present, every vertex is
 * connected to every other vertex. A full graph in \c igraph should be
 * distinguished from the concept of complete graphs as used in graph theory.
 * If n is a positive integer, then the complete graph K_n on n vertices is
 * the undirected simple graph with the following property. For any distinct
 * pair (u,v) of vertices in K_n, uv (or equivalently vu) is an edge of K_n.
 * In \c igraph, a full graph on n vertices can be K_n, a directed version of
 * K_n, or K_n with at least one loop edge. In any case, if F is a full graph
 * on n vertices as generated by \c igraph, then K_n is a subgraph of the
 * undirected version of F.
 * 
 * \param graph Pointer to an uninitialized graph object.
 * \param n Integer, the number of vertices in the graph.
 * \param directed Logical, whether to create a directed graph.
 * \param loops Logical, whether to include self-edges (loops).
 * \return Error code:
 *         \c IGRAPH_EINVAL: invalid number of vertices.
 * 
 * Time complexity: O(|V|+|E|),
 * |V| is the number of vertices,
 * |E| the number of edges in the
 * graph. Of course this is the same as
 * O(|E|)=O(|V||V|) 
 * here. 
 * 
 * \sa \ref igraph_lattice(), \ref igraph_star(), \ref igraph_tree()
 * for creating other regular structures.
 * 
 * \example examples/simple/igraph_full.c
 */

int igraph_full(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed,
		igraph_bool_t loops) {
  
  igraph_vector_t edges=IGRAPH_VECTOR_NULL;
  long int i, j;

  if (n<0) {
    IGRAPH_ERROR("invalid number of vertices", IGRAPH_EINVAL);
  }

  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);

  if (directed && loops) {
    IGRAPH_CHECK(igraph_vector_reserve(&edges, n*n));
    for (i=0; i<n; i++) {
      for (j=0; j<n; j++) {
	igraph_vector_push_back(&edges, i); /* reserved */
	igraph_vector_push_back(&edges, j); /* reserved */
      }
    }
  } else if (directed && !loops) {
    IGRAPH_CHECK(igraph_vector_reserve(&edges, n*(n-1)));
    for (i=0; i<n; i++) {
      for (j=0; j<i; j++) {
	igraph_vector_push_back(&edges, i); /* reserved */
	igraph_vector_push_back(&edges, j); /* reserved */
      }
      for (j=i+1; j<n; j++) {
	igraph_vector_push_back(&edges, i); /* reserved */
	igraph_vector_push_back(&edges, j); /* reserved */
      }
    }
  } else if (!directed && loops) {
    IGRAPH_CHECK(igraph_vector_reserve(&edges, n*(n+1)/2));
    for (i=0; i<n; i++) {
      for (j=i; j<n; j++) {
	igraph_vector_push_back(&edges, i); /* reserved */
	igraph_vector_push_back(&edges, j); /* reserved */
      }
    }
  } else {
    IGRAPH_CHECK(igraph_vector_reserve(&edges, n*(n-1)/2));
    for (i=0; i<n; i++) {
      for (j=i+1; j<n; j++) {
	igraph_vector_push_back(&edges, i); /* reserved */
	igraph_vector_push_back(&edges, j); /* reserved */
      }
    }
  }
  
  IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  
  return 0;
}

/**
 * \function igraph_full_citation
 * Creates a full citation graph
 * 
 * This is a directed graph, where every <code>i->j</code> edge is
 * present if and only if <code>j&lt;i</code>.
 * If the \c directed argument is zero then an undirected graph is
 * created, and it is just a full graph. 
 * \param graph Pointer to an uninitialized graph object, the result
 *    is stored here.
 * \param n The number of vertices.
 * \param directed Whether to created a directed graph. If zero an
 *    undirected graph is created.
 * \return Error code.
 * 
 * Time complexity: O(|V|^2), as we have many edges.
 */

int igraph_full_citation(igraph_t *graph, igraph_integer_t n, 
			 igraph_bool_t directed) {
  igraph_vector_t edges;
  long int i, j, ptr=0;
  
  IGRAPH_VECTOR_INIT_FINALLY(&edges, n*(n-1));
  for (i=1; i<n; i++) {
    for (j=0; j<i; j++) {
      VECTOR(edges)[ptr++] = i;
      VECTOR(edges)[ptr++] = j;
    }
  }
  
  IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  return 0;
}

/**
 * \function igraph_small
 * \brief Shorthand to create a short graph, giving the edges as arguments.
 * 
 * </para><para>
 * This function is handy when a relatively small graph needs to be created. 
 * Instead of giving the edges as a vector, they are given simply as
 * arguments and a '-1' needs to be given after the last meaningful
 * edge argument. 
 * 
 * </para><para>Note that only graphs which have vertices less than
 * the highest value of the 'int' type can be created this way. If you
 * give larger values then the result is undefined.
 * 
 * \param graph Pointer to an uninitialized graph object. The result
 *        will be stored here.
 * \param n The number of vertices in the graph; a nonnegative integer.
 * \param directed Logical constant; gives whether the graph should be
 *        directed. Supported values are:
 *        \clist
 *        \cli IGRAPH_DIRECTED
 *          The graph to be created will be \em directed.
 *        \cli IGRAPH_UNDIRECTED
 *          The graph to be created will be \em undirected.
 *        \endclist
 * \param ... The additional arguments giving the edges of the
 *        graph. Don't forget to supply an additional '-1' after the last
 *        (meaningful) argument.
 * \return Error code.
 * 
 * Time complexity: O(|V|+|E|), the number of vertices plus the number
 * of edges in the graph to create.
 * 
 * \example examples/simple/igraph_small.c
 */

int igraph_small(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, 
		 ...) {
  igraph_vector_t edges;
  va_list ap;
  
  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  
  va_start(ap, directed);
  while (1) {
    int num = va_arg(ap, int);
    if (num == -1) {
      break;
    }
    igraph_vector_push_back(&edges, num);
  }

  IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));
  
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  return 0;
}

/**
 * \function igraph_extended_chordal_ring
 * Create an extended chordal ring
 * 
 * An extended chordal ring is a regular graph, each node has the same
 * degree. It can be obtained from a simple ring by adding some extra
 * edges specified by a matrix. Let p denote the number of columns in
 * the <parameter>W</parameter> matrix. The extra edges of vertex i
 * are added according to column (i mod p) in
 * <parameter>W</parameter>. The number of extra edges is the number
 * of rows in <parameter>W</parameter>: for each row j an edge
 * i->i+w[ij] is added if i+w[ij] is less than the number of total
 * nodes. 
 * 
 * </para><para>
 * See also Kotsis, G: Interconnection Topologies for Parallel Processing
 * Systems, PARS Mitteilungen 11, 1-6, 1993.
 * 
 * \param graph Pointer to an uninitialized graph object, the result
 *   will be stored here. The result is always an undirected graph.
 * \param nodes Integer constant, the number of vertices in the
 *   graph. It must be at least 3.
 * \param W The matrix specifying the extra edges. The number of
 *   columns should divide the number of total vertices.
 * \return Error code.
 * 
 * \sa \ref igraph_ring().
 * 
 * Time complexity: O(|V|+|E|), the number of vertices plus the number
 * of edges.
 */

int igraph_extended_chordal_ring(igraph_t *graph, igraph_integer_t nodes, 
				 const igraph_matrix_t *W) {

  igraph_vector_t edges;
  long int period=igraph_matrix_ncol(W);
  long int degree=igraph_matrix_nrow(W)+2;
  long int i, j, mpos=0, epos=0;
  
  if (nodes<3) {
    IGRAPH_ERROR("An extended chordal ring has at least 3 nodes",
		 IGRAPH_EINVAL);
  }
  
  if ((long int)nodes % period != 0) {
    IGRAPH_ERROR("The period (number of columns in W) should divide the " 
		 "number of nodes", IGRAPH_EINVAL);
  }

  IGRAPH_VECTOR_INIT_FINALLY(&edges, nodes*degree);

  for (i=0; i<nodes-1; i++) {
    VECTOR(edges)[epos++] = i;
    VECTOR(edges)[epos++] = i+1;
  }
  VECTOR(edges)[epos++] = 0;
  VECTOR(edges)[epos++] = nodes-1;
  
  if (degree > 2) {
    for (i=0; i<nodes; i++) {
      for (j=0; j<degree-2; j++) {
	long int offset=(long int) MATRIX(*W, j, mpos);
	if (i+offset < nodes) {
	  VECTOR(edges)[epos++] = i;
	  VECTOR(edges)[epos++] = i+offset;
	}
      }
      mpos++; if (mpos==period) { mpos=0; }
    }
  }
  
  igraph_vector_resize(&edges, epos);
  IGRAPH_CHECK(igraph_create(graph, &edges, nodes, IGRAPH_UNDIRECTED));
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  return 0;  
}

/**
 * \function igraph_connect_neighborhood
 * \brief Connects every vertex to its neighborhood
 * 
 * This function adds new edges to the input graph. Each vertex is connected
 * to all vertices reachable by at most \p order steps from it
 * (unless a connection already existed).  In other words, the \p order power of
 * the graph is computed.
 * 
 * </para><para> Note that the input graph is modified in place, no
 * new graph is created. Call \ref igraph_copy() if you want to keep
 * the original graph as well.
 * 
 * </para><para> For undirected graphs reachability is always
 * symmetric: if vertex A can be reached from vertex B in at
 * most \p order steps, then the opposite is also true. Only one
 * undirected (A,B) edge will be added in this case.
 * \param graph The input graph, this is the output graph as well.
 * \param order Integer constant, it gives the distance within which
 *    the vertices will be connected to the source vertex.
 * \param mode Constant, it specifies how the neighborhood search is
 *    performed for directed graphs. If \c IGRAPH_OUT then vertices
 *    reachable from the source vertex will be connected, \c IGRAPH_IN
 *    is the opposite. If \c IGRAPH_ALL then the directed graph is
 *    considered as an undirected one.
 * \return Error code.
 * 
 * \sa \ref igraph_lattice() uses this function to connect the
 * neighborhood of the vertices.
 * 
 * Time complexity: O(|V|*d^k), |V| is the number of vertices in the
 * graph, d is the average degree and k is the \p order argument.
 */

int igraph_connect_neighborhood(igraph_t *graph, igraph_integer_t order,
				igraph_neimode_t mode) {
  
  long int no_of_nodes=igraph_vcount(graph);
  igraph_dqueue_t q;
  igraph_vector_t edges;
  long int i, j, in;
  long int *added;
  igraph_vector_t neis;
  
  if (order<0) {
    IGRAPH_ERROR("Negative order, cannot connect neighborhood", IGRAPH_EINVAL);
  }

  if (order<2) { 
    IGRAPH_WARNING("Order smaller than two, graph will be unchanged");
  }

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

  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  added=igraph_Calloc(no_of_nodes, long int);
  if (added==0) {
    IGRAPH_ERROR("Cannot connect neighborhood", IGRAPH_ENOMEM);
  }
  IGRAPH_FINALLY(igraph_free, added);
  IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
  
  for (i=0; i<no_of_nodes; i++) {
    added[i]=i+1;
    igraph_neighbors(graph, &neis, (igraph_integer_t) i, mode);
    in=igraph_vector_size(&neis);
    if (order > 1) {
      for (j=0; j<in; j++) {
	long int nei=(long int) VECTOR(neis)[j];
	added[nei]=i+1;
	igraph_dqueue_push(&q, nei);
	igraph_dqueue_push(&q, 1);
      }
    }
    
    while (!igraph_dqueue_empty(&q)) {
      long int actnode=(long int) igraph_dqueue_pop(&q);
      long int actdist=(long int) igraph_dqueue_pop(&q);
      long int n;
      igraph_neighbors(graph, &neis, (igraph_integer_t) actnode, mode);
      n=igraph_vector_size(&neis);
      
      if (actdist<order-1) {
	for (j=0; j<n; j++) {
	  long int nei=(long int) VECTOR(neis)[j];
	  if (added[nei] != i+1) {
	    added[nei]=i+1;
	    IGRAPH_CHECK(igraph_dqueue_push(&q, nei));
	    IGRAPH_CHECK(igraph_dqueue_push(&q, actdist+1));
	    if (mode != IGRAPH_ALL || i < nei) {
	      if (mode == IGRAPH_IN) {
		IGRAPH_CHECK(igraph_vector_push_back(&edges, nei));
		IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
	      } else {
		IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
		IGRAPH_CHECK(igraph_vector_push_back(&edges, nei));
	      }
	    }
	  }
	}
      } else { 
	for (j=0; j<n; j++) {
	  long int nei=(long int) VECTOR(neis)[j];
	  if (added[nei] != i+1) {
	    added[nei]=i+1;
	    if (mode != IGRAPH_ALL || i < nei) {
	      if (mode == IGRAPH_IN) {
		IGRAPH_CHECK(igraph_vector_push_back(&edges, nei));
		IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
	      } else {
		IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
		IGRAPH_CHECK(igraph_vector_push_back(&edges, nei));
	      }
	    }
	  }
	}
      }
      
    } /* while q not empty */
  } /* for i < no_of_nodes */
  
  igraph_vector_destroy(&neis);
  igraph_dqueue_destroy(&q);
  igraph_free(added);
  IGRAPH_FINALLY_CLEAN(3);
  
  IGRAPH_CHECK(igraph_add_edges(graph, &edges, 0));
  
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  
  return 0;
}

/**
 * \function igraph_de_bruijn
 * \brief Generate a de Bruijn graph.
 * 
 * A de Bruijn graph represents relationships between strings. An alphabet
 * of \c m letters are used and strings of length \c n are considered. 
 * A vertex corresponds to every possible string and there is a directed edge
 * from vertex \c v to vertex \c w if the string of \c v can be transformed into
 * the string of \c w by removing its first letter and appending a letter to it.
 * 
 * </para><para>
 * Please note that the graph will have \c m to the power \c n vertices and 
 * even more edges, so probably you don't want to supply too big numbers for
 * \c m and \c n.
 * 
 * </para><para>
 * De Bruijn graphs have some interesting properties, please see another source,
 * eg. Wikipedia for details. 
 * 
 * \param graph Pointer to an uninitialized graph object, the result will be 
 *        stored here.
 * \param m Integer, the number of letters in the alphabet.
 * \param n Integer, the length of the strings.
 * \return Error code.
 * 
 * \sa \ref igraph_kautz().
 * 
 * Time complexity: O(|V|+|E|), the number of vertices plus the number of edges.
 */

int igraph_de_bruijn(igraph_t *graph, igraph_integer_t m, igraph_integer_t n) {
  
  /* m - number of symbols */
  /* n - length of strings */
  
  long int no_of_nodes, no_of_edges;
  igraph_vector_t edges;
  long int i, j;
  long int mm=m;
  
  if (m<0 || n<0) {
    IGRAPH_ERROR("`m' and `n' should be non-negative in a de Bruijn graph",
		 IGRAPH_EINVAL);
  }
  
  if (n==0) {
    return igraph_empty(graph, 1, IGRAPH_DIRECTED);
  }
  if (m==0) {
    return igraph_empty(graph, 0, IGRAPH_DIRECTED);
  }
  
  no_of_nodes=(long int) pow(m, n);
  no_of_edges=no_of_nodes*m;

  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2));
  
  for (i=0; i<no_of_nodes; i++) {
    long int basis=(i*mm) % no_of_nodes;
    for (j=0; j<m; j++) {
      igraph_vector_push_back(&edges, i);
      igraph_vector_push_back(&edges, basis+j);
    }
  }
  
  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes,
			     IGRAPH_DIRECTED));
  
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  
  return 0;
}

/**
 * \function igraph_kautz
 * \brief Generate a Kautz graph.
 * 
 * A Kautz graph is a labeled graph, vertices are labeled by strings
 * of length \c n+1 above an alphabet with \c m+1 letters, with
 * the restriction that every two consecutive letters in the string
 * must be different. There is a directed edge from a vertex \c v to
 * another vertex \c w if it is possible to transform the string of
 * \c v into the string of \c w by removing the first letter and
 * appending a letter to it.
 * 
 * </para><para>
 * Kautz graphs have some interesting properties, see eg. Wikipedia
 * for details.
 * 
 * </para><para>
 * Vincent Matossian wrote the first version of this function in R,
 * thanks.
 * \param graph Pointer to an uninitialized graph object, the result
 * will be stored here.
 * \param m Integer, \c m+1 is the number of letters in the alphabet.
 * \param n Integer, \c n+1 is the length of the strings.
 * \return Error code.
 * 
 * \sa \ref igraph_de_bruijn().
 * 
 * Time complexity: O(|V|* [(m+1)/m]^n +|E|), in practice it is more
 * like O(|V|+|E|). |V| is the number of vertices, |E| is the number
 * of edges and \c m and \c n are the corresponding arguments.
 */

int igraph_kautz(igraph_t *graph, igraph_integer_t m, igraph_integer_t n) {
  
  /* m+1 - number of symbols */
  /* n+1 - length of strings */

  long int mm=m;
  long int no_of_nodes, no_of_edges;
  long int allstrings;
  long int i, j, idx=0;
  igraph_vector_t edges;
  igraph_vector_long_t digits, table;
  igraph_vector_long_t index1, index2;
  long int actb=0;
  long int actvalue=0;
  
  if (m<0 || n<0) {
    IGRAPH_ERROR("`m' and `n' should be non-negative in a Kautz graph",
		 IGRAPH_EINVAL);
  }

  if (n==0) {
    return igraph_full(graph, m+1, IGRAPH_DIRECTED, IGRAPH_NO_LOOPS);
  }
  if (m==0) { 
    return igraph_empty(graph, 0, IGRAPH_DIRECTED);
  }
  
  no_of_nodes=(long int) ((m+1)*pow(m, n));
  no_of_edges=no_of_nodes*m;
  allstrings=(long int) pow(m+1, n+1);

  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
  
  IGRAPH_CHECK(igraph_vector_long_init(&table, n+1));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &table);
  j=1;
  for (i=n; i>=0; i--) {
    VECTOR(table)[i]=j;
    j *= (m+1);
  }

  IGRAPH_CHECK(igraph_vector_long_init(&digits, n+1));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &digits);
  IGRAPH_CHECK(igraph_vector_long_init(&index1, (long int) pow(m+1, n+1)));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &index1);
  IGRAPH_CHECK(igraph_vector_long_init(&index2, no_of_nodes));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &index2);  

  /* Fill the index tables*/
  while (1) {
    /* at the beginning of the loop, 0:actb contain the valid prefix */
    /* we might need to fill it to get a valid string */
    long int z=0;
    if (VECTOR(digits)[actb]==0) { z=1; }
    for (actb++; actb<=n; actb++) {
      VECTOR(digits)[actb]=z;
      actvalue += z*VECTOR(table)[actb];
      z=1-z;
    }
    actb=n;

    /* ok, we have a valid string now */
    VECTOR(index1)[actvalue]=idx+1;
    VECTOR(index2)[idx]=actvalue;
    idx++;
    
    /* finished? */
    if (idx >= no_of_nodes) { break; }
    
    /* not yet, we need a valid prefix now */
    while (1) {
      /* try to increase digits at position actb */
      long int next=VECTOR(digits)[actb]+1;
      if (actb != 0 && VECTOR(digits)[actb-1]==next) { next++; }
      if (next <= m) {
	/* ok, no problem */
	actvalue += (next-VECTOR(digits)[actb])*VECTOR(table)[actb];
	VECTOR(digits)[actb]=next;
	break;
      } else {
	/* bad luck, try the previous digit */
	actvalue -= VECTOR(digits)[actb]*VECTOR(table)[actb];
	actb--;
      }
    }
  }

  IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges*2));
    
  /* Now come the edges at last */
  for (i=0; i<no_of_nodes; i++) {
    long int fromvalue=VECTOR(index2)[i];
    long int lastdigit=fromvalue % (mm+1);
    long int basis=(fromvalue * (mm+1)) % allstrings;
    for (j=0; j<=m; j++) {
      long int tovalue, to;
      if (j==lastdigit) { continue; }
      tovalue=basis+j;
      to=VECTOR(index1)[tovalue]-1;
      if (to<0) { continue; }
      igraph_vector_push_back(&edges, i);
      igraph_vector_push_back(&edges, to);
    }
  }

  igraph_vector_long_destroy(&index2);
  igraph_vector_long_destroy(&index1);
  igraph_vector_long_destroy(&digits);
  igraph_vector_long_destroy(&table);
  IGRAPH_FINALLY_CLEAN(4);

  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes, 
			     IGRAPH_DIRECTED));
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  
  return 0;
}

/**
 * \function igraph_lcf_vector
 * \brief Create a graph from LCF notation
 * 
 * This function is essentially the same as \ref igraph_lcf(), only
 * the way for giving the arguments is different. See \ref
 * igraph_lcf() for details.
 * \param graph Pointer to an uninitialized graph object.
 * \param n Integer constant giving the number of vertices.
 * \param shifts A vector giving the shifts.
 * \param repeats An integer constant giving the number of repeats 
 *        for the shifts.
 * \return Error code.
 * 
 * \sa \ref igraph_lcf()
 * 
 * Time complexity: O(|V|+|E|), linear in the number of vertices plus
 * the number of edges.
 */

int igraph_lcf_vector(igraph_t *graph, igraph_integer_t n,
		      const igraph_vector_t *shifts, 
		      igraph_integer_t repeats) {
  
  igraph_vector_t edges;
  long int no_of_shifts=igraph_vector_size(shifts);
  long int ptr=0, i, sptr=0;
  long int no_of_nodes=n;
  long int no_of_edges=n+no_of_shifts*repeats;

  if (repeats<0) IGRAPH_ERROR("number of repeats must be positive", IGRAPH_EINVAL);
  IGRAPH_VECTOR_INIT_FINALLY(&edges, 2*no_of_edges);

  if (no_of_nodes > 0) {
    /* Create a ring first */
    for (i=0; i<no_of_nodes; i++) {
      VECTOR(edges)[ptr++]=i;
      VECTOR(edges)[ptr++]=i+1;
    }
    VECTOR(edges)[ptr-1]=0;
  }

  /* Then add the rest */
  while (ptr<2*no_of_edges) {
    long int sh=(long int) VECTOR(*shifts)[sptr % no_of_shifts];
    long int from=sptr % no_of_nodes;
    long int to=(no_of_nodes+sptr+sh) % no_of_nodes;
    VECTOR(edges)[ptr++]=from;
    VECTOR(edges)[ptr++]=to;
    sptr++;
  }
  
  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes, 
			     IGRAPH_UNDIRECTED));
  IGRAPH_CHECK(igraph_simplify(graph, 1 /* true */, 1 /* true */, NULL));
  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  
  return 0;			     
}

/**
 * \function igraph_lcf
 * \brief Create a graph from LCF notation
 * 
 * </para><para>
 * LCF is short for Lederberg-Coxeter-Frucht, it is a concise notation for
 * 3-regular Hamiltonian graphs. It consists of three parameters: the
 * number of vertices in the graph, a list of shifts giving additional
 * edges to a cycle backbone, and another integer giving how many times
 * the shifts should be performed. See
 * http://mathworld.wolfram.com/LCFNotation.html for details. 
 * 
 * \param graph Pointer to an uninitialized graph object.
 * \param n Integer, the number of vertices in the graph.
 * \param ... The shifts and the number of repeats for the shifts,
 *        plus an additional 0 to mark the end of the arguments.
 * \return Error code.
 * 
 * \sa See \ref igraph_lcf_vector() for a similar function using a
 * vector_t instead of the variable length argument list.
 * 
 * Time complexity: O(|V|+|E|), the number of vertices plus the number
 * of edges.
 * 
 * \example examples/simple/igraph_lcf.c
 */

int igraph_lcf(igraph_t *graph, igraph_integer_t n, ...) {
  igraph_vector_t shifts;
  igraph_integer_t repeats;
  va_list ap;
  
  IGRAPH_VECTOR_INIT_FINALLY(&shifts, 0);
  
  va_start(ap, n);
  while (1) {
    int num=va_arg(ap, int);
    if (num==0) {
      break;
    }
    IGRAPH_CHECK(igraph_vector_push_back(&shifts, num));
  }
  if (igraph_vector_size(&shifts)==0) {
    repeats=0;
  } else {
    repeats=(igraph_integer_t) igraph_vector_pop_back(&shifts);
  }
  
  IGRAPH_CHECK(igraph_lcf_vector(graph, n, &shifts, repeats));
  igraph_vector_destroy(&shifts);
  IGRAPH_FINALLY_CLEAN(1);
  
  return 0;
}

const igraph_real_t igraph_i_famous_bull[] = {
  5, 5, 0,
  0,1,0,2,1,2,1,3,2,4
};

const igraph_real_t igraph_i_famous_chvatal[] = { 
  12, 24, 0, 
  5, 6, 6, 7, 7, 8, 8, 9, 5, 9, 4, 5, 4, 8, 2, 8, 2, 6, 0, 6, 0, 9, 3, 9, 3, 7, 
  1, 7, 1, 5, 1, 10, 4, 10, 4, 11, 2, 11, 0, 10, 0, 11, 3, 11, 3, 10, 1, 2
};

const igraph_real_t igraph_i_famous_coxeter[] = {
  28, 42, 0,
  0, 1, 0, 2, 0, 7, 1, 4, 1, 13, 2, 3, 2, 8, 3, 6, 3, 9, 4, 5, 4, 12, 5, 6, 5, 
  11, 6, 10, 7, 19, 7, 24, 8, 20, 8, 23, 9, 14, 9, 22, 10, 15, 10, 21, 11, 16, 
  11, 27, 12, 17, 12, 26, 13, 18, 13, 25, 14, 17, 14, 18, 15, 18, 15, 19, 16, 19, 
  16, 20, 17, 20, 21, 23, 21, 26, 22, 24, 22, 27, 23, 25, 24, 26, 25, 27
};

const igraph_real_t igraph_i_famous_cubical[] = {
  8, 12, 0,
  0, 1, 1, 2, 2, 3, 0, 3, 4, 5, 5, 6, 6, 7, 4, 7, 0, 4, 1, 5, 2, 6, 3, 7
};  

const igraph_real_t igraph_i_famous_diamond[] = {
  4, 5, 0,
  0,1,0,2,1,2,1,3,2,3
};

const igraph_real_t igraph_i_famous_dodecahedron[] = {
  20, 30, 0, 
  0, 1, 0, 4, 0, 5, 1, 2, 1, 6, 2, 3, 2, 7, 3, 4, 3, 8, 4, 9, 5, 10, 5, 11, 6, 
  10, 6, 14, 7, 13, 7, 14, 8, 12, 8, 13, 9, 11, 9, 12, 10, 15, 11, 16, 12, 17, 
  13, 18, 14, 19, 15, 16, 15, 19, 16, 17, 17, 18, 18, 19
};

const igraph_real_t igraph_i_famous_folkman[] = {
  20, 40, 0,
  0, 5, 0, 8, 0, 10, 0, 13, 1, 7, 1, 9, 1, 12, 1, 14, 2, 6, 2, 8, 2, 11, 2, 13, 
  3, 5, 3, 7, 3, 10, 3, 12, 4, 6, 4, 9, 4, 11, 4, 14, 5, 15, 5, 19, 6, 15, 6, 16, 
  7, 16, 7, 17, 8, 17, 8, 18, 9, 18, 9, 19, 10, 15, 10, 19, 11, 15, 11, 16, 12, 
  16, 12, 17, 13, 17, 13, 18, 14, 18, 14, 19
};  

const igraph_real_t igraph_i_famous_franklin[] = {
  12, 18, 0,
  0, 1, 0, 2, 0, 6, 1, 3, 1, 7, 2, 4, 2, 10, 3, 5, 3, 11, 4, 5, 4, 6, 5, 7, 6, 8, 
  7, 9, 8, 9, 8, 11, 9, 10, 10, 11
};  

const igraph_real_t igraph_i_famous_frucht[] = {
  12, 18, 0,
  0, 1, 0, 2, 0, 11, 1, 3, 1, 6, 2, 5, 2, 10, 3, 4, 3, 6, 4, 8, 4, 11, 5, 9, 5, 
  10, 6, 7, 7, 8, 7, 9, 8, 9, 10, 11
};  

const igraph_real_t igraph_i_famous_grotzsch[] = {
  11, 20, 0,
  0, 1, 0, 2, 0, 7, 0, 10, 1, 3, 1, 6, 1, 9, 2, 4, 2, 6, 2, 8, 3, 4, 3, 8, 3, 10, 
  4, 7, 4, 9, 5, 6, 5, 7, 5, 8, 5, 9, 5, 10
};  

const igraph_real_t igraph_i_famous_heawood[] = {
  14, 21, 0,
  0, 1, 0, 5, 0, 13, 1, 2, 1, 10, 2, 3, 2, 7, 3, 4, 3, 12, 4, 5, 4, 9, 5, 6, 6, 
  7, 6, 11, 7, 8, 8, 9, 8, 13, 9, 10, 10, 11, 11, 12, 12, 13
};  

const igraph_real_t igraph_i_famous_herschel[] = {
  11, 18, 0,
  0, 2, 0, 3, 0, 4, 0, 5, 1, 2, 1, 3, 1, 6, 1, 7, 2, 10, 3, 9, 4, 8, 4, 9, 5, 8, 
  5, 10, 6, 8, 6, 9, 7, 8, 7, 10
};  

const igraph_real_t igraph_i_famous_house[] = {
  5, 6, 0,
  0,1,0,2,1,3,2,3,2,4,3,4
};

const igraph_real_t igraph_i_famous_housex[] = {
  5, 8, 0,
  0,1,0,2,0,3,1,2,1,3,2,3,2,4,3,4
};

const igraph_real_t igraph_i_famous_icosahedron[] = {
  12, 30, 0,
  0, 1, 0, 2, 0, 3, 0, 4, 0, 8, 1, 2, 1, 6, 1, 7, 1, 8, 2, 4, 2, 5, 2, 6, 3, 4, 
  3, 8, 3, 9, 3, 11, 4, 5, 4, 11, 5, 6, 5, 10, 5, 11, 6, 7, 6, 10, 7, 8, 7, 9, 7, 
  10, 8, 9, 9, 10, 9, 11, 10, 11
};  

const igraph_real_t igraph_i_famous_krackhardt_kite[] = {
  10,18,0,
  0,1,0,2,0,3,0,5, 1,3,1,4,1,6, 2,3,2,5, 3,4,3,5,3,6, 4,6, 5,6,5,7, 6,7, 7,8, 8,9
};

const igraph_real_t igraph_i_famous_levi[] = {
  30, 45, 0,
  0, 1, 0, 7, 0, 29, 1, 2, 1, 24, 2, 3, 2, 11, 3, 4, 3, 16, 4, 5, 4, 21, 5, 6, 5, 
  26, 6, 7, 6, 13, 7, 8, 8, 9, 8, 17, 9, 10, 9, 22, 10, 11, 10, 27, 11, 12, 12, 
  13, 12, 19, 13, 14, 14, 15, 14, 23, 15, 16, 15, 28, 16, 17, 17, 18, 18, 19, 18, 
  25, 19, 20, 20, 21, 20, 29, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 
  28, 28, 29
};  

const igraph_real_t igraph_i_famous_mcgee[] = {
  24, 36, 0,
  0, 1, 0, 7, 0, 23, 1, 2, 1, 18, 2, 3, 2, 14, 3, 4, 3, 10, 4, 5, 4, 21, 5, 6, 5, 
  17, 6, 7, 6, 13, 7, 8, 8, 9, 8, 20, 9, 10, 9, 16, 10, 11, 11, 12, 11, 23, 12, 
  13, 12, 19, 13, 14, 14, 15, 15, 16, 15, 22, 16, 17, 17, 18, 18, 19, 19, 20, 20, 
  21, 21, 22, 22, 23
};

const igraph_real_t igraph_i_famous_meredith[] = {
  70, 140, 0,
  0, 4, 0, 5, 0, 6, 1, 4, 1, 5, 1, 6, 2, 4, 2, 5, 2, 6, 3, 4, 3, 5, 3, 6, 7, 11, 
  7, 12, 7, 13, 8, 11, 8, 12, 8, 13, 9, 11, 9, 12, 9, 13, 10, 11, 10, 12, 10, 13, 
  14, 18, 14, 19, 14, 20, 15, 18, 15, 19, 15, 20, 16, 18, 16, 19, 16, 20, 17, 18, 
  17, 19, 17, 20, 21, 25, 21, 26, 21, 27, 22, 25, 22, 26, 22, 27, 23, 25, 23, 26, 
  23, 27, 24, 25, 24, 26, 24, 27, 28, 32, 28, 33, 28, 34, 29, 32, 29, 33, 29, 34, 
  30, 32, 30, 33, 30, 34, 31, 32, 31, 33, 31, 34, 35, 39, 35, 40, 35, 41, 36, 39, 
  36, 40, 36, 41, 37, 39, 37, 40, 37, 41, 38, 39, 38, 40, 38, 41, 42, 46, 42, 47, 
  42, 48, 43, 46, 43, 47, 43, 48, 44, 46, 44, 47, 44, 48, 45, 46, 45, 47, 45, 48, 
  49, 53, 49, 54, 49, 55, 50, 53, 50, 54, 50, 55, 51, 53, 51, 54, 51, 55, 52, 53, 
  52, 54, 52, 55, 56, 60, 56, 61, 56, 62, 57, 60, 57, 61, 57, 62, 58, 60, 58, 61, 
  58, 62, 59, 60, 59, 61, 59, 62, 63, 67, 63, 68, 63, 69, 64, 67, 64, 68, 64, 69, 
  65, 67, 65, 68, 65, 69, 66, 67, 66, 68, 66, 69, 2, 50, 1, 51, 9, 57, 8, 58, 16, 
  64, 15, 65, 23, 36, 22, 37, 30, 43, 29, 44, 3, 21, 7, 24, 14, 31, 0, 17, 10, 
  28, 38, 42, 35, 66, 59, 63, 52, 56, 45, 49
};  

const igraph_real_t igraph_i_famous_noperfectmatching[] = {
  16, 27, 0,
  0, 1, 0, 2, 0, 3, 1, 2, 1, 3, 2, 3, 2, 4, 3, 4, 4, 5, 5, 6, 5, 7, 6, 12, 6, 13, 
  7, 8, 7, 9, 8, 9, 8, 10, 8, 11, 9, 10, 9, 11, 10, 11, 12, 13, 12, 14, 12, 15, 
  13, 14, 13, 15, 14, 15
};  

const igraph_real_t igraph_i_famous_nonline[] = {
  50, 72, 0,
  0, 1, 0, 2, 0, 3, 4, 6, 4, 7, 5, 6, 5, 7, 6, 7, 7, 8, 9, 11, 9, 12, 9, 13, 10, 
  11, 10, 12, 10, 13, 11, 12, 11, 13, 12, 13, 14, 15, 15, 16, 15, 17, 16, 17, 16, 
  18, 17, 18, 18, 19, 20, 21, 20, 22, 20, 23, 21, 22, 21, 23, 21, 24, 22, 23, 22, 
  24, 24, 25, 26, 27, 26, 28, 26, 29, 27, 28, 27, 29, 27, 30, 27, 31, 28, 29, 28, 
  30, 28, 31, 30, 31, 32, 34, 32, 35, 32, 36, 33, 34, 33, 35, 33, 37, 34, 35, 36, 
  37, 38, 39, 38, 40, 38, 43, 39, 40, 39, 41, 39, 42, 39, 43, 40, 41, 41, 42, 42, 
  43, 44, 45, 44, 46, 45, 46, 45, 47, 46, 47, 46, 48, 47, 48, 47, 49, 48, 49
};  

const igraph_real_t igraph_i_famous_octahedron[] = {
  6, 12, 0,
  0, 1, 0, 2, 1, 2, 3, 4, 3, 5, 4, 5, 0, 3, 0, 5, 1, 3, 1, 4, 2, 4, 2, 5
};  

const igraph_real_t igraph_i_famous_petersen[] = {
  10, 15, 0,
  0,1,0,4,0,5, 1,2,1,6, 2,3,2,7, 3,4,3,8, 4,9, 5,7,5,8, 6,8,6,9, 7,9
};

const igraph_real_t igraph_i_famous_robertson[] = {
  19, 38, 0,
  0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 
  12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 0, 18, 0, 4, 4, 9, 9, 13, 13, 
  17, 2, 17, 2, 6, 6, 10, 10, 15, 0, 15, 1, 8, 8, 16, 5, 16, 5, 12, 1, 12, 7, 18, 
  7, 14, 3, 14, 3, 11, 11, 18
};  

const igraph_real_t igraph_i_famous_smallestcyclicgroup[] = {
  9, 15, 0,
  0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 1, 2, 1, 3, 1, 7, 1, 8, 2, 5, 2, 6, 2, 7, 3, 8, 
  4, 5, 6, 7
};  

const igraph_real_t igraph_i_famous_tetrahedron[] = {
  4, 6, 0, 
  0, 3, 1, 3, 2, 3, 0, 1, 1, 2, 0, 2
};  

const igraph_real_t igraph_i_famous_thomassen[] = {
  34, 52, 0,
  0, 2, 0, 3, 1, 3, 1, 4, 2, 4, 5, 7, 5, 8, 6, 8, 6, 9, 7, 9, 10, 12, 10, 13, 11, 
  13, 11, 14, 12, 14, 15, 17, 15, 18, 16, 18, 16, 19, 17, 19, 9, 19, 4, 14, 24, 
  25, 25, 26, 20, 26, 20, 21, 21, 22, 22, 23, 23, 27, 27, 28, 28, 29, 29, 30, 30, 
  31, 31, 32, 32, 33, 24, 33, 5, 24, 6, 25, 7, 26, 8, 20, 0, 20, 1, 21, 2, 22, 3, 
  23, 10, 27, 11, 28, 12, 29, 13, 30, 15, 30, 16, 31, 17, 32, 18, 33
};  

const igraph_real_t igraph_i_famous_tutte[] = {
  46, 69, 0, 
  0, 10, 0, 11, 0, 12, 1, 2, 1, 7, 1, 19, 2, 3, 2, 41, 3, 4, 3, 27, 4, 5, 4, 33, 
  5, 6, 5, 45, 6, 9, 6, 29, 7, 8, 7, 21, 8, 9, 8, 22, 9, 24, 10, 13, 10, 14, 11, 
  26, 11, 28, 12, 30, 12, 31, 13, 15, 13, 21, 14, 15, 14, 18, 15, 16, 16, 17, 16, 
  20, 17, 18, 17, 23, 18, 24, 19, 25, 19, 40, 20, 21, 20, 22, 22, 23, 23, 24, 25, 
  26, 25, 38, 26, 34, 27, 28, 27, 39, 28, 34, 29, 30, 29, 44, 30, 35, 31, 32, 31, 
  35, 32, 33, 32, 42, 33, 43, 34, 36, 35, 37, 36, 38, 36, 39, 37, 42, 37, 44, 38, 
  40, 39, 41, 40, 41, 42, 43, 43, 45, 44, 45
};

const igraph_real_t igraph_i_famous_uniquely3colorable[] = {
  12, 22, 0,
  0, 1, 0, 3, 0, 6, 0, 8, 1, 4, 1, 7, 1, 9, 2, 3, 2, 6, 2, 7, 2, 9, 2, 11, 3, 4, 
  3, 10, 4, 5, 4, 11, 5, 6, 5, 7, 5, 8, 5, 10, 8, 11, 9, 10
};  

const igraph_real_t igraph_i_famous_walther[] = {
  25, 31, 0,
  0, 1, 1, 2, 1, 8, 2, 3, 2, 13, 3, 4, 3, 16, 4, 5, 5, 6, 5, 19, 6, 7, 6, 20, 7, 
  21, 8, 9, 8, 13, 9, 10, 9, 22, 10, 11, 10, 20, 11, 12, 13, 14, 14, 15, 14, 23, 
  15, 16, 15, 17, 17, 18, 18, 19, 18, 24, 20, 24, 22, 23, 23, 24
};  

const igraph_real_t igraph_i_famous_zachary[] = {
  34, 78, 0,
  0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8,
  0,10, 0,11, 0,12, 0,13, 0,17, 0,19, 0,21, 0,31,
  1, 2, 1, 3, 1, 7, 1,13, 1,17, 1,19, 1,21, 1,30,
  2, 3, 2, 7, 2,27, 2,28, 2,32, 2, 9, 2, 8, 2,13,
  3, 7, 3,12, 3,13, 4, 6, 4,10, 5, 6, 5,10, 5,16,
  6,16, 8,30, 8,32, 8,33, 9,33,13,33,14,32,14,33,
  15,32,15,33,18,32,18,33,19,33,20,32,20,33,
  22,32,22,33,23,25,23,27,23,32,23,33,23,29,
  24,25,24,27,24,31,25,31,26,29,26,33,27,33,
  28,31,28,33,29,32,29,33,30,32,30,33,31,32,31,33,
  32,33
};

int igraph_i_famous(igraph_t *graph, const igraph_real_t *data);

int igraph_i_famous(igraph_t *graph, const igraph_real_t *data) {
  long int no_of_nodes=(long int) data[0];
  long int no_of_edges=(long int) data[1];
  igraph_bool_t directed=(igraph_bool_t) data[2];
  igraph_vector_t edges;
  
  igraph_vector_view(&edges, data+3, 2*no_of_edges);
  IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes,
			     directed));
  return 0;  
}

/**
 * \function igraph_famous
 * \brief Create a famous graph by simply providing its name
 * 
 * </para><para>
 * The name of the graph can be simply supplied as a string. 
 * Note that this function creates graphs which don't take any parameters,
 * there are separate functions for graphs with parameters, eg. \ref
 * igraph_full() for creating a full graph.
 * 
 * </para><para>
 * The following graphs are supported:
 * \clist
 *   \cli Bull
 *           The bull graph, 5 vertices, 5 edges, resembles the
 *           head of a bull if drawn properly.
 *   \cli Chvatal 
 *           This is the smallest triangle-free graph that is
 *           both 4-chromatic and 4-regular. According to the Grunbaum
 *           conjecture there exists an m-regular, m-chromatic graph
 *           with n vertices for every m>1 and n>2. The Chvatal graph
 *           is an example for m=4 and n=12. It has 24 edges.
 *   \cli Coxeter 
 *           A non-Hamiltonian cubic symmetric graph with 28
 *           vertices and 42 edges.
 *   \cli Cubical
 *           The Platonic graph of the cube. A convex regular
 *           polyhedron with 8 vertices and 12 edges.
 *   \cli Diamond
 *           A graph with 4 vertices and 5 edges, resembles a
 *           schematic diamond if drawn properly.
 *   \cli Dodecahedral, Dodecahedron
 *           Another Platonic solid
 *           with 20 vertices and 30 edges.
 *   \cli Folkman 
 *           The semisymmetric graph with minimum number of
 *           vertices, 20 and 40 edges. A semisymmetric graph is
 *           regular, edge transitive and not vertex transitive.
 *   \cli Franklin 
 *           This is a graph whose embedding to the Klein
 *           bottle can be colored with six colors, it is a
 *           counterexample to the necessity of the Heawood
 *           conjecture on a Klein bottle. It has 12 vertices and 18
 *           edges. 
 *   \cli Frucht 
 *           The Frucht Graph is the smallest cubical graph
 *           whose automorphism group consists only of the identity
 *           element. It has 12 vertices and 18 edges.
 *   \cli Grotzsch 
 *           The Grötzsch graph is a triangle-free graph with
 *           11 vertices, 20 edges, and chromatic number 4. It is named after
 *           German mathematician Herbert Grötzsch, and its existence
 *           demonstrates that the assumption of planarity is necessary in
 *           Grötzsch's theorem that every triangle-free planar
 *           graph is 3-colorable. 
 *   \cli Heawood 
 *           The Heawood graph is an undirected graph with 14
 *           vertices and 21 edges. The graph is cubic, and all cycles in the
 *           graph have six or more edges. Every smaller cubic graph has shorter
 *           cycles, so this graph is the 6-cage, the smallest cubic graph of
 *           girth 6. 
 *   \cli Herschel 
 *           The Herschel graph is the smallest
 *           nonhamiltonian polyhedral graph. It is the
 *           unique such graph on 11 nodes, and has 18 edges.
 *   \cli House
 *           The house graph is a 5-vertex, 6-edge graph, the
 *           schematic draw of a house if drawn properly, basically a 
 *           triangle on top of a square.
 *   \cli HouseX
 *           The same as the house graph with an X in the square. 5
 *           vertices and 8 edges.
 *   \cli Icosahedral, Icosahedron 
 *           A Platonic solid with 12
 *           vertices and 30 edges.
 *   \cli Krackhardt_Kite
 *           A social network with 10 vertices and 18 edges.
 *           Krackhardt, D. Assessing the Political Landscape:
 *           Structure, Cognition, and Power in Organizations.
 *           Admin. Sci. Quart. 35, 342-369, 1990. 
 *   \cli Levi 
 *           The graph is a 4-arc transitive cubic graph, it has
 *           30 vertices and 45 edges.
 *   \cli McGee 
 *           The McGee graph is the unique 3-regular 7-cage
 *           graph, it has 24 vertices and 36 edges.
 *   \cli Meredith 
 *           The Meredith graph is a quartic graph on 70
 *           nodes and 140 edges that is a counterexample to the conjecture that
 *           every 4-regular 4-connected graph is Hamiltonian. 
 *   \cli Noperfectmatching 
 *           A connected graph with 16 vertices and
 *           27 edges containing no perfect matching. A matching in a graph
 *           is a set of pairwise non-incident edges; that is, no two edges
 *           share a common vertex. A perfect matching is a matching
 *           which covers all vertices of the graph. 
 *   \cli Nonline 
 *           A graph whose connected components are the 9
 *           graphs whose presence as a vertex-induced subgraph in a
 *           graph makes a nonline graph. It has 50 vertices and 72 edges.
 *   \cli Octahedral, Octahedron 
 *           Platonic solid with 6
 *           vertices and 12 edges. 
 *   \cli Petersen
 *           A 3-regular graph with 10 vertices and 15 edges. It is
 *           the smallest hypohamiltonian graph, ie. it is
 *           non-hamiltonian but removing any single vertex from it makes it
 *           Hamiltonian.
 *   \cli Robertson 
 *           The unique (4,5)-cage graph, ie. a 4-regular
 *           graph of girth 5. It has 19 vertices and 38 edges.
 *   \cli Smallestcyclicgroup 
 *           A smallest nontrivial graph
 *           whose automorphism group is cyclic. It has 9 vertices and
 *           15 edges.
 *   \cli Tetrahedral, Tetrahedron 
 *           Platonic solid with 4
 *           vertices and 6 edges.
 *   \cli Thomassen 
 *           The smallest hypotraceable graph,
 *           on 34 vertices and 52 edges. A hypotracable graph does
 *           not contain a Hamiltonian path but after removing any
 *           single vertex from it the remainder always contains a
 *           Hamiltonian path. A graph containing a Hamiltonian path
 *           is called traceable.
 *   \cli Tutte 
 *           Tait's Hamiltonian graph conjecture states that
 *           every 3-connected 3-regular planar graph is Hamiltonian.
 *           This graph is a counterexample. It has 46 vertices and 69
 *           edges. 
 *   \cli Uniquely3colorable 
 *           Returns a 12-vertex, triangle-free
 *           graph with chromatic number 3 that is uniquely
 *           3-colorable.
 *   \cli Walther 
 *           An identity graph with 25 vertices and 31
 *           edges. An identity graph has a single graph automorphism,
 *           the trivial one.
 *   \cli Zachary
 *           Social network of friendships between 34 members of a
 *           karate club at a US university in the 1970s. See
 *           W. W. Zachary, An information flow model for conflict and
 *           fission in small groups, Journal of Anthropological
 *           Research 33, 452-473 (1977). 
 * \endclist
 * 
 * \param graph Pointer to an uninitialized graph object.
 * \param name Character constant, the name of the graph to be
 *     created, it is case insensitive.
 * \return Error code, IGRAPH_EINVAL if there is no graph with the
 *     given name.
 * 
 * \sa Other functions for creating graph structures:
 * \ref igraph_ring(), \ref igraph_tree(), \ref igraph_lattice(), \ref
 * igraph_full().
 * 
 * Time complexity: O(|V|+|E|), the number of vertices plus the number
 * of edges in the graph.
 */

int igraph_famous(igraph_t *graph, const char *name) {

  if (!strcasecmp(name, "bull")) {
    return igraph_i_famous(graph, igraph_i_famous_bull);
  } else if (!strcasecmp(name, "chvatal")) {
    return igraph_i_famous(graph, igraph_i_famous_chvatal);
  } else if (!strcasecmp(name, "coxeter")) {
    return igraph_i_famous(graph, igraph_i_famous_coxeter);
  } else if (!strcasecmp(name, "cubical")) {    
    return igraph_i_famous(graph, igraph_i_famous_cubical);
  } else if (!strcasecmp(name, "diamond")) {
    return igraph_i_famous(graph, igraph_i_famous_diamond);
  } else if (!strcasecmp(name, "dodecahedral") ||
	     !strcasecmp(name, "dodecahedron")) {
    return igraph_i_famous(graph, igraph_i_famous_dodecahedron);
  } else if (!strcasecmp(name, "folkman")) {
    return igraph_i_famous(graph, igraph_i_famous_folkman);
  } else if (!strcasecmp(name, "franklin")) {
    return igraph_i_famous(graph, igraph_i_famous_franklin);
  } else if (!strcasecmp(name, "frucht")) {
    return igraph_i_famous(graph, igraph_i_famous_frucht);
  } else if (!strcasecmp(name, "grotzsch")) {
    return igraph_i_famous(graph, igraph_i_famous_grotzsch);
  } else if (!strcasecmp(name, "heawood")) {
    return igraph_i_famous(graph, igraph_i_famous_heawood);
  } else if (!strcasecmp(name, "herschel")) {
    return igraph_i_famous(graph, igraph_i_famous_herschel);
  } else if (!strcasecmp(name, "house")) {
    return igraph_i_famous(graph, igraph_i_famous_house);
  } else if (!strcasecmp(name, "housex")) {
    return igraph_i_famous(graph, igraph_i_famous_housex);
  } else if (!strcasecmp(name, "icosahedral") ||
	     !strcasecmp(name, "icosahedron")) {
    return igraph_i_famous(graph, igraph_i_famous_icosahedron);
  } else if (!strcasecmp(name, "krackhardt_kite")) {
    return igraph_i_famous(graph, igraph_i_famous_krackhardt_kite);
  } else if (!strcasecmp(name, "levi")) {
    return igraph_i_famous(graph, igraph_i_famous_levi);
  } else if (!strcasecmp(name, "mcgee")) {
    return igraph_i_famous(graph, igraph_i_famous_mcgee);
  } else if (!strcasecmp(name, "meredith")) {
    return igraph_i_famous(graph, igraph_i_famous_meredith);
  } else if (!strcasecmp(name, "noperfectmatching")) {
    return igraph_i_famous(graph, igraph_i_famous_noperfectmatching);
  } else if (!strcasecmp(name, "nonline")) {
    return igraph_i_famous(graph, igraph_i_famous_nonline);
  } else if (!strcasecmp(name, "octahedral") ||
	     !strcasecmp(name, "octahedron")) {
    return igraph_i_famous(graph, igraph_i_famous_octahedron);
  } else if (!strcasecmp(name, "petersen")) {
    return igraph_i_famous(graph, igraph_i_famous_petersen);
  } else if (!strcasecmp(name, "robertson")) {
    return igraph_i_famous(graph, igraph_i_famous_robertson);
  } else if (!strcasecmp(name, "smallestcyclicgroup")) {
    return igraph_i_famous(graph, igraph_i_famous_smallestcyclicgroup);
  } else if (!strcasecmp(name, "tetrahedral") ||
	     !strcasecmp(name, "tetrahedron")) {
    return igraph_i_famous(graph, igraph_i_famous_tetrahedron);
  } else if (!strcasecmp(name, "thomassen")) {
    return igraph_i_famous(graph, igraph_i_famous_thomassen);
  } else if (!strcasecmp(name, "tutte")) {
    return igraph_i_famous(graph, igraph_i_famous_tutte);
  } else if (!strcasecmp(name, "uniquely3colorable")) {
    return igraph_i_famous(graph, igraph_i_famous_uniquely3colorable);
  } else if (!strcasecmp(name, "walther")) {
    return igraph_i_famous(graph, igraph_i_famous_walther);
  } else if (!strcasecmp(name, "zachary")) {
    return igraph_i_famous(graph, igraph_i_famous_zachary);
  } else {
    IGRAPH_ERROR("Unknown graph, see documentation", IGRAPH_EINVAL);
  }
  
  return 0;
}

/**
 * \function igraph_adjlist
 * Create a graph from an adjacency list
 * 
 * An adjacency list is a list of vectors, containing the neighbors 
 * of all vertices. For operations that involve many changes to the
 * graph structure, it is recommended that you convert the graph into
 * an adjacency list via \ref igraph_adjlist_init(), perform the
 * modifications (these are cheap for an adjacency list) and then
 * recreate the igraph graph via this function.
 * 
 * \param graph Pointer to an uninitialized graph object.
 * \param adjlist The adjacency list.
 * \param mode Whether or not to create a directed graph. \c IGRAPH_ALL
 *             means an undirected graph, \c IGRAPH_OUT means a
 *             directed graph from an out-adjacency list (i.e. each
 *             list contains the successors of the corresponding
 *             vertices), \c IGRAPH_IN means a directed graph from an
 *             in-adjacency list
 * \param duplicate Logical, for undirected graphs this specified
 *        whether each edge is included twice, in the vectors of 
 *        both adjacent vertices. If this is false (0), then it is
 *        assumed that every edge is included only once. This argument 
 *        is ignored for directed graphs.
 * \return Error code.
 * 
 * \sa \ref igraph_adjlist_init() for the opposite operation.
 *
 * Time complexity: O(|V|+|E|).
 * 
 */

int igraph_adjlist(igraph_t *graph, const igraph_adjlist_t *adjlist,
		   igraph_neimode_t mode, igraph_bool_t duplicate) {
  
  long int no_of_nodes=igraph_adjlist_size(adjlist);
  long int no_of_edges=0;
  long int i;

  igraph_vector_t edges;
  long int edgeptr=0;

  duplicate = duplicate && (mode == IGRAPH_ALL); /* only duplicate if undirected */
  
  for (i=0; i<no_of_nodes; i++) {
    no_of_edges += igraph_vector_int_size(igraph_adjlist_get(adjlist, i));
  }
  
  if (duplicate) {
    no_of_edges /= 2;
  }

  IGRAPH_VECTOR_INIT_FINALLY(&edges, 2*no_of_edges);
  
  for (i=0; i<no_of_nodes; i++) {
    igraph_vector_int_t *neis=igraph_adjlist_get(adjlist, i);
    long int j, n=igraph_vector_int_size(neis);
    long int loops=0;

    for (j=0; j<n; j++) {
      long int nei=(long int) VECTOR(*neis)[j];
      if (nei==i) {
        loops++; 
      } else {
        if (! duplicate || nei > i) {
          if (edgeptr+2 > 2*no_of_edges) {
            IGRAPH_ERROR("Invalid adjacency list, most probably not correctly"
              " duplicated edges for an undirected graph", IGRAPH_EINVAL);
          }
          if (mode == IGRAPH_IN) {
            VECTOR(edges)[edgeptr++] = nei;
            VECTOR(edges)[edgeptr++] = i;
          } else {
            VECTOR(edges)[edgeptr++] = i;
            VECTOR(edges)[edgeptr++] = nei;
          }
	    }
      }
    }
    /* loops */
    if (duplicate) { loops=loops/2; }
    if (edgeptr+2*loops > 2*no_of_edges) {
      IGRAPH_ERROR("Invalid adjacency list, most probably not correctly"
		   " duplicated edges for an undirected graph", IGRAPH_EINVAL);
    }
    for (j=0; j<loops; j++) {
      VECTOR(edges)[edgeptr++] = i;
      VECTOR(edges)[edgeptr++] = i;
    }
  }

  if (mode == IGRAPH_ALL)
    IGRAPH_CHECK(igraph_create(graph, &edges, 
			       (igraph_integer_t) no_of_nodes, 0));
  else
    IGRAPH_CHECK(igraph_create(graph, &edges, 
			       (igraph_integer_t) no_of_nodes, 1));

  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
  
  return 0;
}
