haskell-igraph-0.8.0: igraph/src/structure_generators.c
/* -*- 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; \ref igraph_from_prufer() for creating arbitrary trees;
* \ref igraph_tree_game() for uniform random sampling of trees.
*
* \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<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 cycle graph with additional chords
* connecting its vertices.
*
* Each row \c L of the matrix \p W specifies a set of chords to be
* inserted, in the following way: vertex \c i will connect to a vertex
* <code>L[(i mod p)]</code> steps ahead of it along the cycle, where
* \c p is the length of \c L.
* In other words, vertex \c i will be connected to vertex
* <code>(i + L[(i mod p)]) mod nodes</code>.
*
* </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.
* \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.
* \param directed Whether the graph should be directed.
* \return Error code.
*
* \sa \ref igraph_ring(), \ref igraph_lcf(), \ref igraph_lcf_vector()
*
* 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_bool_t directed) {
igraph_vector_t edges;
long int period = igraph_matrix_ncol(W);
long int nrow = igraph_matrix_nrow(W);
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, 2 * (nodes + nodes * nrow));
for (i = 0; i < nodes - 1; i++) {
VECTOR(edges)[epos++] = i;
VECTOR(edges)[epos++] = i + 1;
}
VECTOR(edges)[epos++] = nodes - 1;
VECTOR(edges)[epos++] = 0;
if (nrow > 0) {
for (i = 0; i < nodes; i++) {
for (j = 0; j < nrow; j++) {
long int offset = (long int) MATRIX(*W, j, mpos);
long int v = (i + offset) % nodes;
if (v < 0) {
v += nodes; /* handle negative offsets */
}
VECTOR(edges)[epos++] = i;
VECTOR(edges)[epos++] = v;
}
mpos++; if (mpos == period) {
mpos = 0;
}
}
}
IGRAPH_CHECK(igraph_create(graph, &edges, nodes, directed));
igraph_vector_destroy(&edges);
IGRAPH_FINALLY_CLEAN(1);
return IGRAPH_SUCCESS;
}
/**
* \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(), \ref igraph_extended_chordal_ring()
*
* 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;
}
/**
* \ingroup generators
* \function igraph_from_prufer
* \brief Generates a tree from a Prüfer sequence
*
* A Prüfer sequence is a unique sequence of integers associated
* with a labelled tree. A tree on n vertices can be represented by a
* sequence of n-2 integers, each between 0 and n-1 (inclusive).
*
* The algorithm used by this function is based on
* Paulius Micikevičius, Saverio Caminiti, Narsingh Deo:
* Linear-time Algorithms for Encoding Trees as Sequences of Node Labels
*
* \param graph Pointer to an uninitialized graph object.
* \param prufer The Prüfer sequence
* \return Error code:
* \clist
* \cli IGRAPH_ENOMEM
* there is not enough memory to perform the operation.
* \cli IGRAPH_EINVAL
* invalid Prüfer sequence given
* \endclist
*
* \sa \ref igraph_tree(), \ref igraph_tree_game()
*
*/
int igraph_from_prufer(igraph_t *graph, const igraph_vector_int_t *prufer) {
igraph_vector_int_t degree;
igraph_vector_t edges;
long n;
long i, k;
long u, v; /* vertices */
long ec;
n = igraph_vector_int_size(prufer) + 2;
IGRAPH_VECTOR_INT_INIT_FINALLY(°ree, n); /* initializes vector to zeros */
IGRAPH_VECTOR_INIT_FINALLY(&edges, 2 * (n - 1));
/* build out-degree vector (i.e. number of child vertices) and verify Prufer sequence */
for (i = 0; i < n - 2; ++i) {
long u = VECTOR(*prufer)[i];
if (u >= n || u < 0) {
IGRAPH_ERROR("Invalid Prufer sequence", IGRAPH_EINVAL);
}
VECTOR(degree)[u] += 1;
}
v = 0; /* initialize v now, in case Prufer sequence is empty */
k = 0; /* index into the Prufer vector */
ec = 0; /* index into the edges vector */
for (i = 0; i < n; ++i) {
u = i;
while (k < n - 2 && u <= i && (VECTOR(degree)[u] == 0)) {
/* u is a leaf here */
v = VECTOR(*prufer)[k]; /* parent of u */
/* add edge */
VECTOR(edges)[ec++] = v;
VECTOR(edges)[ec++] = u;
k += 1;
VECTOR(degree)[v] -= 1;
u = v;
}
if (k == n - 2) {
break;
}
}
/* find u for last edge, v is already set */
for (u = i + 1; u < n; ++u)
if ((VECTOR(degree)[u] == 0) && u != v) {
break;
}
/* add last edge */
VECTOR(edges)[ec++] = v;
VECTOR(edges)[ec++] = u;
IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) n, /* directed = */ 0));
igraph_vector_destroy(&edges);
igraph_vector_int_destroy(°ree);
IGRAPH_FINALLY_CLEAN(2);
return IGRAPH_SUCCESS;
}