igraph Reference Manual

For using the igraph C library

Chapter 13. Structural Properties of Graphs

These functions usually calculate some structural property of a graph, like its diameter, the degree of the nodes, etc.

1. Basic Properties

1.1. igraph_are_connected — Decides whether two vertices are connected

int igraph_are_connected(const igraph_t *graph, 
			 igraph_integer_t v1, igraph_integer_t v2,
			 igraph_bool_t *res);

Arguments: 

graph:

The graph object.

v1:

The first vertex.

v2:

The second vertex.

res:

Boolean, TRUE if there is an edge from v1 to v2, FALSE otherwise.

Returns: 

The error code IGRAPH_EINVVID is returned if an invalid vertex ID is given.

The function is of course symmetric for undirected graphs.

Time complexity: O( min(log(d1), log(d2)) ), d1 is the (out-)degree of v1 and d2 is the (in-)degree of v2.

2. Shortest Path Related Functions

2.1. igraph_shortest_paths — The length of the shortest paths between vertices.
2.2. igraph_shortest_paths_dijkstra — Weighted shortest paths from some sources.
2.3. igraph_shortest_paths_bellman_ford — Weighted shortest paths from some sources allowing negative weights.
2.4. igraph_shortest_paths_johnson — Calculate shortest paths from some sources using Johnson's algorithm.
2.5. igraph_get_shortest_paths — Calculates the shortest paths from/to one vertex.
2.6. igraph_get_shortest_path — Shortest path from one vertex to another one.
2.7. igraph_get_shortest_paths_dijkstra — Calculates the weighted shortest paths from/to one vertex.
2.8. igraph_get_shortest_path_dijkstra — Weighted shortest path from one vertex to another one.
2.9. igraph_get_all_shortest_paths — Finds all shortest paths (geodesics) from a vertex to all other vertices.
2.10. igraph_get_all_shortest_paths_dijkstra — Finds all shortest paths (geodesics) from a vertex to all other vertices.
2.11. igraph_average_path_length — Calculates the average geodesic length in a graph.
2.12. igraph_path_length_hist — Create a histogram of all shortest path lengths.
2.13. igraph_diameter — Calculates the diameter of a graph (longest geodesic).
2.14. igraph_diameter_dijkstra — Weighted diameter using Dijkstra's algorithm, non-negative weights only.
2.15. igraph_girth — The girth of a graph is the length of the shortest circle in it.
2.16. igraph_eccentricity — Eccentricity of some vertices
2.17. igraph_radius — Radius of a graph

2.1. igraph_shortest_paths — The length of the shortest paths between vertices.

int igraph_shortest_paths(const igraph_t *graph, igraph_matrix_t *res, 
			  const igraph_vs_t from, const igraph_vs_t to,
			  igraph_neimode_t mode);

Arguments: 

graph:

The graph object.

res:

The result of the calculation, a matrix. A pointer to an initialized matrix, to be more precise. The matrix will be resized if needed. It will have the same number of rows as the length of the from argument, and its number of columns is the number of vertices in the to argument. One row of the matrix shows the distances from/to a given vertex to the ones in to. For the unreachable vertices IGRAPH_INFINITY is returned.

from:

Vector of the vertex ids for which the path length calculations are done.

to:

Vector of the vertex ids to which the path length calculations are done. It is not allowed to have duplicated vertex ids here.

mode:

The type of shortest paths to be used for the calculation in directed graphs. Possible values:

IGRAPH_OUT

the lengths of the outgoing paths are calculated.

IGRAPH_IN

the lengths of the incoming paths are calculated.

IGRAPH_ALL

the directed graph is considered as an undirected one for the computation.

Returns: 

Error code:

IGRAPH_ENOMEM

not enough memory for temporary data.

IGRAPH_EINVVID

invalid vertex id passed.

IGRAPH_EINVMODE

invalid mode argument.

Time complexity: O(n(|V|+|E|)), n is the number of vertices to calculate, |V| and |E| are the number of vertices and edges in the graph.

See also: 

igraph_get_shortest_paths() to get the paths themselves, igraph_shortest_paths_dijkstra() for the weighted version.

2.2. igraph_shortest_paths_dijkstra — Weighted shortest paths from some sources.

int igraph_shortest_paths_dijkstra(const igraph_t *graph,
				   igraph_matrix_t *res,
				   const igraph_vs_t from,
				   const igraph_vs_t to,
				   const igraph_vector_t *weights, 
				   igraph_neimode_t mode);

This function is Dijkstra's algorithm to find the weighted shortest paths to all vertices from a single source. (It is run independently for the given sources.) It uses a binary heap for efficient implementation.

Arguments: 

graph:

The input graph, can be directed.

res:

The result, a matrix. A pointer to an initialized matrix should be passed here. The matrix will be resized as needed. Each row contains the distances from a single source, to the vertices given in the to argument. Unreachable vertices has distance IGRAPH_INFINITY.

from:

The source vertices.

to:

The target vertices. It is not allowed to include a vertex twice or more.

weights:

The edge weights. They must be all non-negative for Dijkstra's algorithm to work. An error code is returned if there is a negative edge weight in the weight vector. If this is a null pointer, then the unweighted version, igraph_shortest_paths() is called.

mode:

For directed graphs; whether to follow paths along edge directions (IGRAPH_OUT), or the opposite (IGRAPH_IN), or ignore edge directions completely (IGRAPH_ALL). It is ignored for undirected graphs.

Returns: 

Error code.

Time complexity: O(s*|E|log|E|+|V|), where |V| is the number of vertices, |E| the number of edges and s the number of sources.

See also: 

igraph_shortest_paths() for a (slightly) faster unweighted version or igraph_shortest_paths_bellman_ford() for a weighted variant that works in the presence of negative edge weights (but no negative loops).

Example 13.1.  File examples/simple/dijkstra.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2008-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.h>

int print_matrix(const igraph_matrix_t *m) {
  long int nrow=igraph_matrix_nrow(m);
  long int ncol=igraph_matrix_ncol(m);
  long int i, j;
  for (i=0; i<nrow; i++) {
    printf("%li:", i);
    for (j=0; j<ncol; j++) {
      printf(" %3.0F", MATRIX(*m, i, j));
    }
    printf("\n");
  }
  return 0;
}

int main() {
  
  igraph_t g;
  igraph_vector_t weights;
  igraph_real_t weights_data[] = { 0,2,1, 0,5,2, 1,1,0, 2,2,8, 1,1,3, 1,1,4, 2,1 };
  igraph_matrix_t res;
  
  igraph_small(&g, 10, IGRAPH_DIRECTED, 
	       0,1, 0,2, 0,3,    1,2, 1,4, 1,5,
	       2,3, 2,6,         3,2, 3,6,
	       4,5, 4,7,         5,6, 5,8, 5,9,
	       7,5, 7,8,         8,9,
	       5,2,
	       2,1,
	       -1);
  
  igraph_vector_view(&weights, weights_data, 
		     sizeof(weights_data)/sizeof(igraph_real_t));
  
  igraph_matrix_init(&res, 0, 0);
  igraph_shortest_paths_dijkstra(&g, &res, igraph_vss_all(), igraph_vss_all(),
				 &weights, IGRAPH_OUT);
  print_matrix(&res);
  
  igraph_matrix_destroy(&res);
  igraph_destroy(&g);

  return 0;
}


2.3. igraph_shortest_paths_bellman_ford — Weighted shortest paths from some sources allowing negative weights.

int igraph_shortest_paths_bellman_ford(const igraph_t *graph,
				       igraph_matrix_t *res,
				       const igraph_vs_t from,
				       const igraph_vs_t to,
				       const igraph_vector_t *weights, 
				       igraph_neimode_t mode);

This function is the Bellman-Ford algorithm to find the weighted shortest paths to all vertices from a single source. (It is run independently for the given sources.). If there are no negative weights, you are better off with igraph_shortest_paths_dijkstra() .

Arguments: 

graph:

The input graph, can be directed.

res:

The result, a matrix. A pointer to an initialized matrix should be passed here, the matrix will be resized if needed. Each row contains the distances from a single source, to all vertices in the graph, in the order of vertex ids. For unreachable vertices the matrix contains IGRAPH_INFINITY.

from:

The source vertices.

weights:

The edge weights. There mustn't be any closed loop in the graph that has a negative total weight (since this would allow us to decrease the weight of any path containing at least a single vertex of this loop infinitely). If this is a null pointer, then the unweighted version, igraph_shortest_paths() is called.

mode:

For directed graphs; whether to follow paths along edge directions (IGRAPH_OUT), or the opposite (IGRAPH_IN), or ignore edge directions completely (IGRAPH_ALL). It is ignored for undirected graphs.

Returns: 

Error code.

Time complexity: O(s*|E|*|V|), where |V| is the number of vertices, |E| the number of edges and s the number of sources.

See also: 

igraph_shortest_paths() for a faster unweighted version or igraph_shortest_paths_dijkstra() if you do not have negative edge weights.

Example 13.2.  File examples/simple/bellman_ford.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2008-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.h>

int print_matrix(const igraph_matrix_t *m) {
  long int nrow=igraph_matrix_nrow(m);
  long int ncol=igraph_matrix_ncol(m);
  long int i, j;
  for (i=0; i<nrow; i++) {
    printf("%li:", i);
    for (j=0; j<ncol; j++) {
      printf(" %3.0F", MATRIX(*m, i, j));
    }
    printf("\n");
  }
  return 0;
}

int main() {
  
  igraph_t g;
  igraph_vector_t weights;
  igraph_real_t weights_data_0[] = { 0,2,1, 0,5,2, 1,1,0, 2,2,8, 1,1,3, 1,1,4, 2,1 };
  igraph_real_t weights_data_1[] = { 6,7,8,-4,-2,-3,9,2,7 };
  igraph_real_t weights_data_2[] = { 6,7,2,-4,-2,-3,9,2,7 };
  igraph_matrix_t res;
  
  /* Graph with only positive weights */
  igraph_small(&g, 10, IGRAPH_DIRECTED, 
	       0,1, 0,2, 0,3,    1,2, 1,4, 1,5,
	       2,3, 2,6,         3,2, 3,6,
	       4,5, 4,7,         5,6, 5,8, 5,9,
	       7,5, 7,8,         8,9,
	       5,2,
	       2,1,
	       -1);
  
  igraph_vector_view(&weights, weights_data_0, 
		     sizeof(weights_data_0)/sizeof(igraph_real_t));
  
  igraph_matrix_init(&res, 0, 0);
  igraph_shortest_paths_bellman_ford(&g, &res, igraph_vss_all(), igraph_vss_all(),
				     &weights, IGRAPH_OUT);
  print_matrix(&res);
  
  igraph_matrix_destroy(&res);
  igraph_destroy(&g);

  printf("\n");

  /***************************************/

  /* Graph with negative weights */
  igraph_small(&g, 5, IGRAPH_DIRECTED, 
	       0,1, 0,3, 1,3, 1,4, 2,1, 3,2, 3,4, 4,0, 4,2, -1);
  
  igraph_vector_view(&weights, weights_data_1, 
		     sizeof(weights_data_1)/sizeof(igraph_real_t));
  
  igraph_matrix_init(&res, 0, 0);
  igraph_shortest_paths_bellman_ford(&g, &res, igraph_vss_all(), 
				     igraph_vss_all(), &weights, IGRAPH_OUT);
  print_matrix(&res);
  
  /***************************************/

  /* Same graph with negative loop */
  igraph_set_error_handler(igraph_error_handler_ignore);
  igraph_vector_view(&weights, weights_data_2, 
		     sizeof(weights_data_2)/sizeof(igraph_real_t));
  if (igraph_shortest_paths_bellman_ford(&g, &res, igraph_vss_all(),
					 igraph_vss_all(),
                                         &weights, IGRAPH_OUT) != IGRAPH_ENEGLOOP)
    return 1;
  
  igraph_matrix_destroy(&res);
  igraph_destroy(&g);

  if (!IGRAPH_FINALLY_STACK_EMPTY) return 1;

  return 0;
}


2.4. igraph_shortest_paths_johnson — Calculate shortest paths from some sources using Johnson's algorithm.

int igraph_shortest_paths_johnson(const igraph_t *graph,
				  igraph_matrix_t *res,
				  const igraph_vs_t from,
				  const igraph_vs_t to,
				  const igraph_vector_t *weights);

See Wikipedia at http://en.wikipedia.org/wiki/Johnson's_algorithm for Johnson's algorithm. This algorithm works even if the graph contains negative edge weights, and it is worth using it if we calculate the shortest paths from many sources.

If no edge weights are supplied, then the unweighted version, igraph_shortest_paths() is called.

If all the supplied edge weights are non-negative, then Dijkstra's algorithm is used by calling igraph_shortest_paths_dijkstra().

Arguments: 

graph:

The input graph, typically it is directed.

res:

Pointer to an initialized matrix, the result will be stored here, one line for each source vertex, one column for each target vertex.

from:

The source vertices.

to:

The target vertices. It is not allowed to include a vertex twice or more.

weights:

Optional edge weights. If it is a null-pointer, then the unweighted breadth-first search based igraph_shortest_paths() will be called.

Returns: 

Error code.

Time complexity: O(s|V|log|V|+|V||E|), |V| and |E| are the number of vertices and edges, s is the number of source vertices.

See also: 

igraph_shortest_paths() for a faster unweighted version or igraph_shortest_paths_dijkstra() if you do not have negative edge weights, igraph_shortest_paths_bellman_ford() if you only need to calculate shortest paths from a couple of sources.

2.5. igraph_get_shortest_paths — Calculates the shortest paths from/to one vertex.

int igraph_get_shortest_paths(const igraph_t *graph, 
			      igraph_vector_ptr_t *vertices,
			      igraph_vector_ptr_t *edges,
			      igraph_integer_t from, const igraph_vs_t to, 
			      igraph_neimode_t mode,
                              igraph_vector_long_t *predecessors,
                              igraph_vector_long_t *inbound_edges);

If there is more than one geodesic between two vertices, this function gives only one of them.

Arguments: 

graph:

The graph object.

vertices:

The result, the ids of the vertices along the paths. This is a pointer vector, each element points to a vector object. These should be initialized before passing them to the function, which will properly clear and/or resize them and fill the ids of the vertices along the geodesics from/to the vertices. Supply a null pointer here if you don't need these vectors.

edges:

The result, the ids of the edges along the paths. This is a pointer vector, each element points to a vector object. These should be initialized before passing them to the function, which will properly clear and/or resize them and fill the ids of the vertices along the geodesics from/to the vertices. Supply a null pointer here if you don't need these vectors.

from:

The id of the vertex from/to which the geodesics are calculated.

to:

Vertex sequence with the ids of the vertices to/from which the shortest paths will be calculated. A vertex might be given multiple times.

mode:

The type of shortest paths to be used for the calculation in directed graphs. Possible values:

IGRAPH_OUT

the outgoing paths are calculated.

IGRAPH_IN

the incoming paths are calculated.

IGRAPH_ALL

the directed graph is considered as an undirected one for the computation.

predecessors:

A pointer to an initialized igraph vector or null. If not null, a vector containing the predecessor of each vertex in the single source shortest path tree is returned here. The predecessor of vertex i in the tree is the vertex from which vertex i was reached. The predecessor of the start vertex (in the from argument) is itself by definition. If the predecessor is -1, it means that the given vertex was not reached from the source during the search. Note that the search terminates if all the vertices in to are reached.

inbound_edges:

A pointer to an initialized igraph vector or null. If not null, a vector containing the inbound edge of each vertex in the single source shortest path tree is returned here. The inbound edge of vertex i in the tree is the edge via which vertex i was reached. The start vertex and vertices that were not reached during the search will have -1 in the corresponding entry of the vector. Note that the search terminates if all the vertices in to are reached.

Returns: 

Error code:

IGRAPH_ENOMEM

not enough memory for temporary data.

IGRAPH_EINVVID

from is invalid vertex id, or the length of to is not the same as the length of res.

IGRAPH_EINVMODE

invalid mode argument.

Time complexity: O(|V|+|E|), |V| is the number of vertices, |E| the number of edges in the graph.

See also: 

igraph_shortest_paths() if you only need the path length but not the paths themselves.

Example 13.3.  File examples/simple/igraph_get_shortest_paths.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

#include <stdlib.h>

void print_vector(igraph_vector_t *v) {
  long int i, l=igraph_vector_size(v);
  for (i=0; i<l; i++) {
    printf(" %li", (long int) VECTOR(*v)[i]);
  }
  printf("\n");
}

int check_evecs(const igraph_t *graph, const igraph_vector_ptr_t *vecs,
		const igraph_vector_ptr_t *evecs, int error_code) {

  igraph_bool_t directed=igraph_is_directed(graph);
  long int i, n=igraph_vector_ptr_size(vecs);
  if (igraph_vector_ptr_size(evecs) != n) { exit(error_code+1); }
  
  for (i=0; i<n; i++) {
    igraph_vector_t *vvec=VECTOR(*vecs)[i];
    igraph_vector_t *evec=VECTOR(*evecs)[i];
    long int j, n2=igraph_vector_size(evec);
    if (igraph_vector_size(vvec) == 0 && n2==0) { continue; }
    if (igraph_vector_size(vvec) != n2+1) { exit(error_code+2); }
    for (j=0; j<n2; j++) {
      long int edge=VECTOR(*evec)[j];
      long int from=VECTOR(*vvec)[j];
      long int to=VECTOR(*vvec)[j+1];
      if (directed) {
	if (from != IGRAPH_FROM(graph, edge) ||
	    to   != IGRAPH_TO  (graph, edge)) {
	  exit(error_code);
	}
      } else {
	long int from2=IGRAPH_FROM(graph, edge);
	long int to2=IGRAPH_TO(graph, edge);
	long int min1= from < to ? from : to;
	long int max1= from < to ? to : from;
	long int min2= from2 < to2 ? from2 : to2;
	long int max2= from2 < to2 ? to2 : from2;
	if (min1 != min2 || max1 != max2) { exit(error_code+3); }
      }
    }
  }

  return 0;
}

int main() {

  igraph_t g;
  igraph_vector_ptr_t vecs, evecs;
  igraph_vector_long_t pred, inbound;
  long int i;
  igraph_vs_t vs;

  igraph_ring(&g, 10, IGRAPH_DIRECTED, 0, 1);
  
  igraph_vector_ptr_init(&vecs, 5);
  igraph_vector_ptr_init(&evecs, 5);
  igraph_vector_long_init(&pred, 0);
  igraph_vector_long_init(&inbound, 0);

  for (i=0; i<igraph_vector_ptr_size(&vecs); i++) {
    VECTOR(vecs)[i] = calloc(1, sizeof(igraph_vector_t));
    igraph_vector_init(VECTOR(vecs)[i], 0);
    VECTOR(evecs)[i] = calloc(1, sizeof(igraph_vector_t));
    igraph_vector_init(VECTOR(evecs)[i], 0);
  }
  igraph_vs_vector_small(&vs, 1, 3, 5, 2, 1,  -1);
  
  igraph_get_shortest_paths(&g, &vecs, &evecs, 0, vs, IGRAPH_OUT, &pred, &inbound);

  check_evecs(&g, &vecs, &evecs, 10);
  
  for (i=0; i<igraph_vector_ptr_size(&vecs); i++) {
    print_vector(VECTOR(vecs)[i]);
    igraph_vector_destroy(VECTOR(vecs)[i]);
    free(VECTOR(vecs)[i]);
    igraph_vector_destroy(VECTOR(evecs)[i]);
    free(VECTOR(evecs)[i]);
  }

  igraph_vector_long_print(&pred);
  igraph_vector_long_print(&inbound);

  igraph_vector_ptr_destroy(&vecs);
  igraph_vector_ptr_destroy(&evecs);
  igraph_vector_long_destroy(&pred);
  igraph_vector_long_destroy(&inbound);
  igraph_vs_destroy(&vs);
  igraph_destroy(&g);

  if (!IGRAPH_FINALLY_STACK_EMPTY) return 1;
  
  return 0;
}


2.6. igraph_get_shortest_path — Shortest path from one vertex to another one.

int igraph_get_shortest_path(const igraph_t *graph, 
			     igraph_vector_t *vertices,
			     igraph_vector_t *edges, 
			     igraph_integer_t from,
			     igraph_integer_t to,
			     igraph_neimode_t mode);

Calculates and returns a single unweighted shortest path from a given vertex to another one. If there are more than one shortest paths between the two vertices, then an arbitrary one is returned.

This function is a wrapper to igraph_get_shortest_paths(), for the special case when only one target vertex is considered.

Arguments: 

graph:

The input graph, it can be directed or undirected. Directed paths are considered in directed graphs.

vertices:

Pointer to an initialized vector or a null pointer. If not a null pointer, then the vertex ids along the path are stored here, including the source and target vertices.

edges:

Pointer to an uninitialized vector or a null pointer. If not a null pointer, then the edge ids along the path are stored here.

from:

The id of the source vertex.

to:

The id of the target vertex.

mode:

A constant specifying how edge directions are considered in directed graphs. Valid modes are: IGRAPH_OUT, follows edge directions; IGRAPH_IN, follows the opposite directions; and IGRAPH_ALL, ignores edge directions. This argument is ignored for undirected graphs.

Returns: 

Error code.

Time complexity: O(|V|+|E|), linear in the number of vertices and edges in the graph.

See also: 

igraph_get_shortest_paths() for the version with more target vertices.

2.7. igraph_get_shortest_paths_dijkstra — Calculates the weighted shortest paths from/to one vertex.

int igraph_get_shortest_paths_dijkstra(const igraph_t *graph,
                                       igraph_vector_ptr_t *vertices,
				       igraph_vector_ptr_t *edges,
				       igraph_integer_t from,
				       igraph_vs_t to,
				       const igraph_vector_t *weights,
				       igraph_neimode_t mode,
                                       igraph_vector_long_t *predecessors,
                                       igraph_vector_long_t *inbound_edges);

If there is more than one path with the smallest weight between two vertices, this function gives only one of them.

Arguments: 

graph:

The graph object.

vertices:

The result, the ids of the vertices along the paths. This is a pointer vector, each element points to a vector object. These should be initialized before passing them to the function, which will properly clear and/or resize them and fill the ids of the vertices along the geodesics from/to the vertices. Supply a null pointer here if you don't need these vectors. Normally, either this argument, or the edges should be non-null, but no error or warning is given if they are both null pointers.

edges:

The result, the ids of the edges along the paths. This is a pointer vector, each element points to a vector object. These should be initialized before passing them to the function, which will properly clear and/or resize them and fill the ids of the vertices along the geodesics from/to the vertices. Supply a null pointer here if you don't need these vectors. Normally, either this argument, or the vertices should be non-null, but no error or warning is given if they are both null pointers.

from:

The id of the vertex from/to which the geodesics are calculated.

to:

Vertex sequence with the ids of the vertices to/from which the shortest paths will be calculated. A vertex might be given multiple times.

weights:

a vector holding the edge weights. All weights must be positive.

mode:

The type of shortest paths to be use for the calculation in directed graphs. Possible values:

IGRAPH_OUT

the outgoing paths are calculated.

IGRAPH_IN

the incoming paths are calculated.

IGRAPH_ALL

the directed graph is considered as an undirected one for the computation.

predecessors:

A pointer to an initialized igraph vector or null. If not null, a vector containing the predecessor of each vertex in the single source shortest path tree is returned here. The predecessor of vertex i in the tree is the vertex from which vertex i was reached. The predecessor of the start vertex (in the from argument) is itself by definition. If the predecessor is -1, it means that the given vertex was not reached from the source during the search. Note that the search terminates if all the vertices in to are reached.

inbound_edges:

A pointer to an initialized igraph vector or null. If not null, a vector containing the inbound edge of each vertex in the single source shortest path tree is returned here. The inbound edge of vertex i in the tree is the edge via which vertex i was reached. The start vertex and vertices that were not reached during the search will have -1 in the corresponding entry of the vector. Note that the search terminates if all the vertices in to are reached.

Returns: 

Error code:

IGRAPH_ENOMEM

not enough memory for temporary data.

IGRAPH_EINVVID

from is invalid vertex id, or the length of to is not the same as the length of res.

IGRAPH_EINVMODE

invalid mode argument.

Time complexity: O(|E|log|E|+|V|), where |V| is the number of vertices and |E| is the number of edges

See also: 

igraph_shortest_paths_dijkstra() if you only need the path length but not the paths themselves, igraph_get_shortest_paths() if all edge weights are equal.

Example 13.4.  File examples/simple/igraph_get_shortest_paths_dijkstra.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

#include <stdlib.h>

void print_vector(igraph_vector_t *v) {
  long int i, l=igraph_vector_size(v);
  for (i=0; i<l; i++) {
    printf(" %li", (long int) VECTOR(*v)[i]);
  }
  printf("\n");
}

int check_evecs(const igraph_t *graph, const igraph_vector_ptr_t *vecs,
		const igraph_vector_ptr_t *evecs, int error_code) {

  igraph_bool_t directed=igraph_is_directed(graph);
  long int i, n=igraph_vector_ptr_size(vecs);
  if (igraph_vector_ptr_size(evecs) != n) { exit(error_code+1); }
  
  for (i=0; i<n; i++) {
    igraph_vector_t *vvec=VECTOR(*vecs)[i];
    igraph_vector_t *evec=VECTOR(*evecs)[i];
    long int j, n2=igraph_vector_size(evec);
    if (igraph_vector_size(vvec) == 0 && n2==0) { continue; }
    if (igraph_vector_size(vvec) != n2+1) { exit(error_code+2); }
    for (j=0; j<n2; j++) {
      long int edge=VECTOR(*evec)[j];
      long int from=VECTOR(*vvec)[j];
      long int to=VECTOR(*vvec)[j+1];
      if (directed) {
	if (from != IGRAPH_FROM(graph, edge) ||
	    to   != IGRAPH_TO  (graph, edge)) {
	  exit(error_code);
	}
      } else {
	long int from2=IGRAPH_FROM(graph, edge);
	long int to2=IGRAPH_TO(graph, edge);
	long int min1= from < to ? from : to;
	long int max1= from < to ? to : from;
	long int min2= from2 < to2 ? from2 : to2;
	long int max2= from2 < to2 ? to2 : from2;
	if (min1 != min2 || max1 != max2) { exit(error_code+3); }
      }
    }
  }

  return 0;
}

int check_pred_inbound(const igraph_t* graph, const igraph_vector_long_t* pred,
        const igraph_vector_long_t* inbound, int start, int error_code) {
  long int i, n = igraph_vcount(graph);

  if (igraph_vector_long_size(pred) != n ||
      igraph_vector_long_size(inbound) != n) {
    exit(error_code);
  }

  if (VECTOR(*pred)[start] != start || VECTOR(*inbound)[start] != -1)
    exit(error_code+1);

  for (i = 0; i < n; i++) {
    if (VECTOR(*pred)[i] == -1) {
      if (VECTOR(*inbound)[i] != -1) {
        exit(error_code+2);
      }
    } else if (VECTOR(*pred)[i] == i) {
      if (i != start) {
        exit(error_code+3);
      }
      if (VECTOR(*inbound)[i] != -1) {
        exit(error_code+4);
      }
    } else {
      long int eid = VECTOR(*inbound)[i];
      long int u = IGRAPH_FROM(graph, eid), v = IGRAPH_TO(graph, eid);
      if (v != i && !igraph_is_directed(graph)) {
        long int dummy = u;
        u = v; v = dummy;
      }
      if (v != i) {
        exit(error_code+5);
      } else if (u != VECTOR(*pred)[i]) {
        exit(error_code+6);
      }
    }
  }

  return 0;
}

int main() {

  igraph_t g;
  igraph_vector_ptr_t vecs, evecs;
  igraph_vector_long_t pred, inbound;
  long int i;
  igraph_real_t weights[] = { 1, 2, 3, 4, 5, 1, 1, 1, 1, 1 }; 
  igraph_real_t weights2[] = { 0,2,1, 0,5,2, 1,1,0, 2,2,8, 1,1,3, 1,1,4, 2,1 };
  igraph_vector_t weights_vec;
  igraph_vs_t vs;

  /* Simple ring graph without weights */

  igraph_ring(&g, 10, IGRAPH_UNDIRECTED, 0, 1);
  
  igraph_vector_ptr_init(&vecs, 5);
  igraph_vector_ptr_init(&evecs, 5);
  igraph_vector_long_init(&pred, 0);
  igraph_vector_long_init(&inbound, 0);

  for (i=0; i<igraph_vector_ptr_size(&vecs); i++) {
    VECTOR(vecs)[i] = calloc(1, sizeof(igraph_vector_t));
    igraph_vector_init(VECTOR(vecs)[i], 0);
    VECTOR(evecs)[i] = calloc(1, sizeof(igraph_vector_t));
    igraph_vector_init(VECTOR(evecs)[i], 0);
  }
  igraph_vs_vector_small(&vs, 1, 3, 5, 2, 1,  -1);
  
  igraph_get_shortest_paths_dijkstra(&g, /*vertices=*/ &vecs, 
				     /*edges=*/ &evecs, /*from=*/ 0, /*to=*/ vs, 
				     /*weights=*/ 0, /*mode=*/ IGRAPH_OUT,
				     /*predecessors=*/ &pred,
				     /*inbound_edges=*/ &inbound);

  check_evecs(&g, &vecs, &evecs, 10);
  check_pred_inbound(&g, &pred, &inbound, /* from= */ 0, 40);

  for (i=0; i<igraph_vector_ptr_size(&vecs); i++) {
    print_vector(VECTOR(vecs)[i]);
  }

  /* Same ring, but with weights */

  igraph_vector_view(&weights_vec, weights, sizeof(weights)/sizeof(igraph_real_t));
  igraph_get_shortest_paths_dijkstra(&g, /*vertices=*/ &vecs, 
				     /*edges=*/ &evecs, /*from=*/ 0, /*to=*/ vs, 
				     &weights_vec, IGRAPH_OUT,
				     /*predecessors=*/ &pred,
				     /*inbound_edges=*/ &inbound);
  
  check_evecs(&g, &vecs, &evecs, 20);
  check_pred_inbound(&g, &pred, &inbound, /* from= */ 0, 50);

  for (i=0; i<igraph_vector_ptr_size(&vecs); i++) {
    print_vector(VECTOR(vecs)[i]);
  }

  igraph_destroy(&g);

  /* More complicated example */

  igraph_small(&g, 10, IGRAPH_DIRECTED, 
	       0,1, 0,2, 0,3,    1,2, 1,4, 1,5,
	       2,3, 2,6,         3,2, 3,6,
	       4,5, 4,7,         5,6, 5,8, 5,9,
	       7,5, 7,8,         8,9,
	       5,2,
	       2,1,
	       -1);
  
  igraph_vector_view(&weights_vec, weights2, sizeof(weights2)/sizeof(igraph_real_t));
  igraph_get_shortest_paths_dijkstra(&g, /*vertices=*/ &vecs, 
				     /*edges=*/ &evecs, /*from=*/ 0, /*to=*/ vs, 
				     &weights_vec, IGRAPH_OUT,
				     /*predecessors=*/ &pred,
				     /*inbound_edges=*/ &inbound);

  check_evecs(&g, &vecs, &evecs, 30);
  check_pred_inbound(&g, &pred, &inbound, /* from= */ 0, 60);
  
  for (i=0; i<igraph_vector_ptr_size(&vecs); i++) {
    print_vector(VECTOR(vecs)[i]);
    igraph_vector_destroy(VECTOR(vecs)[i]);
    free(VECTOR(vecs)[i]);
    igraph_vector_destroy(VECTOR(evecs)[i]);
    free(VECTOR(evecs)[i]);
  }

  igraph_vector_ptr_destroy(&vecs);
  igraph_vector_ptr_destroy(&evecs);
  igraph_vector_long_destroy(&pred);
  igraph_vector_long_destroy(&inbound);
  
  igraph_vs_destroy(&vs);
  igraph_destroy(&g);

  if (!IGRAPH_FINALLY_STACK_EMPTY) return 1;

  return 0;
}


2.8. igraph_get_shortest_path_dijkstra — Weighted shortest path from one vertex to another one.

int igraph_get_shortest_path_dijkstra(const igraph_t *graph,
				      igraph_vector_t *vertices,
				      igraph_vector_t *edges,
				      igraph_integer_t from,
				      igraph_integer_t to,
				      const igraph_vector_t *weights,
				      igraph_neimode_t mode);

Calculates a single (positively) weighted shortest path from a single vertex to another one, using Dijkstra's algorithm.

This function is a special case (and a wrapper) to igraph_get_shortest_paths_dijkstra().

Arguments: 

graph:

The input graph, it can be directed or undirected.

vertices:

Pointer to an initialized vector or a null pointer. If not a null pointer, then the vertex ids along the path are stored here, including the source and target vertices.

edges:

Pointer to an uninitialized vector or a null pointer. If not a null pointer, then the edge ids along the path are stored here.

from:

The id of the source vertex.

to:

The id of the target vertex.

weights:

Vector of edge weights, in the order of edge ids. They must be non-negative, otherwise the algorithm does not work.

mode:

A constant specifying how edge directions are considered in directed graphs. IGRAPH_OUT follows edge directions, IGRAPH_IN follows the opposite directions, and IGRAPH_ALL ignores edge directions. This argument is ignored for undirected graphs.

Returns: 

Error code.

Time complexity: O(|E|log|E|+|V|), |V| is the number of vertices, |E| is the number of edges in the graph.

See also: 

igraph_get_shortest_paths_dijkstra() for the version with more target vertices.

2.9. igraph_get_all_shortest_paths — Finds all shortest paths (geodesics) from a vertex to all other vertices.

int igraph_get_all_shortest_paths(const igraph_t *graph,
				  igraph_vector_ptr_t *res, 
				  igraph_vector_t *nrgeo,
				  igraph_integer_t from, const igraph_vs_t to,
				  igraph_neimode_t mode);

Arguments: 

graph:

The graph object.

res:

Pointer to an initialized pointer vector, the result will be stored here in igraph_vector_t objects. Each vector object contains the vertices along a shortest path from from to another vertex. The vectors are ordered according to their target vertex: first the shortest paths to vertex 0, then to vertex 1, etc. No data is included for unreachable vertices.

nrgeo:

Pointer to an initialized igraph_vector_t object or NULL. If not NULL the number of shortest paths from from are stored here for every vertex in the graph. Note that the values will be accurate only for those vertices that are in the target vertex sequence (see to), since the search terminates as soon as all the target vertices have been found.

from:

The id of the vertex from/to which the geodesics are calculated.

to:

Vertex sequence with the ids of the vertices to/from which the shortest paths will be calculated. A vertex might be given multiple times.

mode:

The type of shortest paths to be use for the calculation in directed graphs. Possible values:

IGRAPH_OUT

the lengths of the outgoing paths are calculated.

IGRAPH_IN

the lengths of the incoming paths are calculated.

IGRAPH_ALL

the directed graph is considered as an undirected one for the computation.

Returns: 

Error code:

IGRAPH_ENOMEM

not enough memory for temporary data.

IGRAPH_EINVVID

from is invalid vertex id.

IGRAPH_EINVMODE

invalid mode argument.

Added in version 0.2.

Time complexity: O(|V|+|E|) for most graphs, O(|V|^2) in the worst case.

2.10. igraph_get_all_shortest_paths_dijkstra — Finds all shortest paths (geodesics) from a vertex to all other vertices.

int igraph_get_all_shortest_paths_dijkstra(const igraph_t *graph,
               igraph_vector_ptr_t *res, 
               igraph_vector_t *nrgeo,
               igraph_integer_t from, igraph_vs_t to,
               const igraph_vector_t *weights,
               igraph_neimode_t mode);

Arguments: 

graph:

The graph object.

res:

Pointer to an initialized pointer vector, the result will be stored here in igraph_vector_t objects. Each vector object contains the vertices along a shortest path from from to another vertex. The vectors are ordered according to their target vertex: first the shortest paths to vertex 0, then to vertex 1, etc. No data is included for unreachable vertices.

nrgeo:

Pointer to an initialized igraph_vector_t object or NULL. If not NULL the number of shortest paths from from are stored here for every vertex in the graph. Note that the values will be accurate only for those vertices that are in the target vertex sequence (see to), since the search terminates as soon as all the target vertices have been found.

from:

The id of the vertex from/to which the geodesics are calculated.

to:

Vertex sequence with the ids of the vertices to/from which the shortest paths will be calculated. A vertex might be given multiple times.

weights:

a vector holding the edge weights. All weights must be non-negative.

mode:

The type of shortest paths to be use for the calculation in directed graphs. Possible values:

IGRAPH_OUT

the outgoing paths are calculated.

IGRAPH_IN

the incoming paths are calculated.

IGRAPH_ALL

the directed graph is considered as an undirected one for the computation.

Returns: 

Error code:

IGRAPH_ENOMEM

not enough memory for temporary data.

IGRAPH_EINVVID

from is invalid vertex id, or the length of to is not the same as the length of res.

IGRAPH_EINVMODE

invalid mode argument.

Time complexity: O(|E|log|E|+|V|), where |V| is the number of vertices and |E| is the number of edges

See also: 

igraph_shortest_paths_dijkstra() if you only need the path length but not the paths themselves, igraph_get_all_shortest_paths() if all edge weights are equal.

Example 13.5.  File examples/simple/igraph_get_all_shortest_paths_dijkstra.c

/* -*- mode: C -*-  */
/* vim:set ts=2 sw=2 sts=2 et: */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

#include <stdlib.h>

void check_nrgeo(igraph_t *graph, igraph_vs_t vs,
                 igraph_vector_ptr_t* paths,
                 igraph_vector_t* nrgeo) {
  long int i, n;
  igraph_vector_t nrgeo2, *path;
  igraph_vit_t vit;

  n = igraph_vcount(graph);
  igraph_vector_init(&nrgeo2, n);
  if (igraph_vector_size(nrgeo) != n) {
    printf("nrgeo vector length must be %ld, was %ld", n,
        igraph_vector_size(nrgeo));
    return;
  }

  n = igraph_vector_ptr_size(paths);
  for (i = 0; i < n; i++) {
    path = VECTOR(*paths)[i];
    if (path == 0) {
      printf("Null path found in result vector at index %ld\n", i);
      return;
    }
    if (igraph_vector_size(path) == 0) {
      printf("Empty path found in result vector at index %ld\n", i);
      return;
    }
    VECTOR(nrgeo2)[(long int)igraph_vector_tail(path)] += 1;
  }

  igraph_vit_create(graph, vs, &vit);
  for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
    long int node = IGRAPH_VIT_GET(vit);
    if (VECTOR(*nrgeo)[node] - VECTOR(nrgeo2)[node]) {
      printf("nrgeo[%ld] invalid, observed = %ld, expected = %ld\n",
          node, (long int)VECTOR(*nrgeo)[node], (long int)VECTOR(nrgeo2)[node]);
    }
  }
  igraph_vit_destroy(&vit);

  igraph_vector_destroy(&nrgeo2);
}

int main() {

  igraph_t g;
  igraph_vector_ptr_t res;
  long int i;
  igraph_real_t weights[] = { 1, 2, 3, 4, 5, 1, 1, 1, 1, 1 }; 
  igraph_real_t weights2[] = { 0,2,1, 0,5,2, 1,1,0, 2,2,8, 1,1,3, 1,1,4, 2,1 };
  igraph_real_t dim[] = { 4, 4 };

  igraph_vector_t weights_vec, dim_vec, nrgeo;
  igraph_vs_t vs;

  igraph_vector_init(&nrgeo, 0);

  /* Simple ring graph without weights */

  igraph_ring(&g, 10, IGRAPH_UNDIRECTED, 0, 1);
  
  igraph_vector_ptr_init(&res, 5);
  igraph_vs_vector_small(&vs, 1, 3, 4, 5, 2, 1,  -1);
  
  igraph_get_all_shortest_paths_dijkstra(&g, /*res=*/ &res, 
				     /*nrgeo=*/ &nrgeo, /*from=*/ 0, /*to=*/ vs, 
				     /*weights=*/ 0, /*mode=*/ IGRAPH_OUT);
  check_nrgeo(&g, vs, &res, &nrgeo);

  for (i=0; i<igraph_vector_ptr_size(&res); i++) {
    igraph_vector_print(VECTOR(res)[i]);
    igraph_vector_destroy(VECTOR(res)[i]);
    free(VECTOR(res)[i]);
    VECTOR(res)[i] = 0;
  }

  /* Same ring, but with weights */

  igraph_vector_view(&weights_vec, weights, sizeof(weights)/sizeof(igraph_real_t));
  igraph_get_all_shortest_paths_dijkstra(&g, /*res=*/ &res, 
				     /*nrgeo=*/ &nrgeo, /*from=*/ 0, /*to=*/ vs, 
				     /*weights=*/ &weights_vec, /*mode=*/ IGRAPH_OUT);
  check_nrgeo(&g, vs, &res, &nrgeo);
  
  for (i=0; i<igraph_vector_ptr_size(&res); i++) {
    igraph_vector_print(VECTOR(res)[i]);
    igraph_vector_destroy(VECTOR(res)[i]);
    free(VECTOR(res)[i]);
    VECTOR(res)[i] = 0;
  }

  igraph_destroy(&g);

  /* More complicated example */

  igraph_small(&g, 10, IGRAPH_DIRECTED, 
	       0,1, 0,2, 0,3,    1,2, 1,4, 1,5,
	       2,3, 2,6,         3,2, 3,6,
	       4,5, 4,7,         5,6, 5,8, 5,9,
	       7,5, 7,8,         8,9,
	       5,2,
	       2,1,
	       -1);
  
  igraph_vector_view(&weights_vec, weights2, sizeof(weights2)/sizeof(igraph_real_t));
  igraph_get_all_shortest_paths_dijkstra(&g, /*res=*/ &res, 
				     /*nrgeo=*/ &nrgeo, /*from=*/ 0, /*to=*/ vs, 
				     /*weights=*/ &weights_vec, /*mode=*/ IGRAPH_OUT);

  check_nrgeo(&g, vs, &res, &nrgeo);

  for (i=0; i<igraph_vector_ptr_size(&res); i++) {
    igraph_vector_print(VECTOR(res)[i]);
    igraph_vector_destroy(VECTOR(res)[i]);
    free(VECTOR(res)[i]);
    VECTOR(res)[i] = 0;
  }

  igraph_vs_destroy(&vs);
  igraph_destroy(&g);

  /* Regular lattice with some heavyweight edges */
  igraph_vector_view(&dim_vec, dim, sizeof(dim)/sizeof(igraph_real_t));
  igraph_lattice(&g, &dim_vec, 1, 0, 0, 0);
  igraph_vs_vector_small(&vs, 3, 12, 15, -1);
  igraph_vector_init(&weights_vec, 24);
  igraph_vector_fill(&weights_vec, 1);
  VECTOR(weights_vec)[2] = 100; VECTOR(weights_vec)[8] = 100; /* 1-->2, 4-->8 */
  igraph_get_all_shortest_paths_dijkstra(&g, /*res=*/ 0,
				     /*nrgeo=*/ &nrgeo, /*from=*/ 0, /*to=*/ vs, 
				     /*weights=*/ &weights_vec, /*mode=*/ IGRAPH_OUT);
  igraph_vector_destroy(&weights_vec);
  igraph_vs_destroy(&vs);
  igraph_destroy(&g);

  printf("%ld ", (long int)VECTOR(nrgeo)[3]);
  printf("%ld ", (long int)VECTOR(nrgeo)[12]);
  printf("%ld\n", (long int)VECTOR(nrgeo)[15]);

  igraph_vector_ptr_destroy(&res);
  igraph_vector_destroy(&nrgeo);

  if (!IGRAPH_FINALLY_STACK_EMPTY) return 1;

  return 0;
}


2.11. igraph_average_path_length — Calculates the average geodesic length in a graph.

int igraph_average_path_length(const igraph_t *graph, igraph_real_t *res,
			       igraph_bool_t directed, igraph_bool_t unconn);

Arguments: 

graph:

The graph object.

res:

Pointer to a real number, this will contain the result.

directed:

Boolean, whether to consider directed paths. Ignored for undirected graphs.

unconn:

What to do if the graph is not connected. If TRUE the average of the geodesics within the components will be returned, otherwise the number of vertices is used for the length of non-existing geodesics. (The rationale behind this is that this is always longer than the longest possible geodesic in a graph.)

Returns: 

Error code: IGRAPH_ENOMEM, not enough memory for data structures

Time complexity: O(|V||E|), the number of vertices times the number of edges.

Example 13.6.  File examples/simple/igraph_average_path_length.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2006-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.h>

int main() {
  
  igraph_t g;
  igraph_real_t result;
  
  igraph_barabasi_game(&g, 30, /*power=*/ 1, 30, 0, 0, /*A=*/ 1, 
		       IGRAPH_DIRECTED, IGRAPH_BARABASI_BAG,
		       /*start_from=*/ 0);
  igraph_average_path_length(&g, &result, IGRAPH_UNDIRECTED, 1);
  
/*   printf("Length of the average shortest paths: %f\n", (float) result); */
  
  igraph_destroy(&g);
  return 0;
}


2.12. igraph_path_length_hist — Create a histogram of all shortest path lengths.

int igraph_path_length_hist(const igraph_t *graph, igraph_vector_t *res,
			    igraph_real_t *unconnected, igraph_bool_t directed);

This function calculates a histogram, by calculating the shortest path length between each pair of vertices. For directed graphs both directions might be considered and then every pair of vertices appears twice in the histogram.

Arguments: 

graph:

The input graph.

res:

Pointer to an initialized vector, the result is stored here. The first (i.e. zeroth) element contains the number of shortest paths of length 1, etc. The supplied vector is resized as needed.

unconnected:

Pointer to a real number, the number of pairs for which the second vertex is not reachable from the first is stored here.

directed:

Whether to consider directed paths in a directed graph (if not zero). This argument is ignored for undirected graphs.

Returns: 

Error code.

Time complexity: O(|V||E|), the number of vertices times the number of edges.

See also: 

2.13. igraph_diameter — Calculates the diameter of a graph (longest geodesic).

int igraph_diameter(const igraph_t *graph, igraph_integer_t *pres, 
		    igraph_integer_t *pfrom, igraph_integer_t *pto, 
		    igraph_vector_t *path,
		    igraph_bool_t directed, igraph_bool_t unconn);

Arguments: 

graph:

The graph object.

pres:

Pointer to an integer, if not NULL then it will contain the diameter (the actual distance).

pfrom:

Pointer to an integer, if not NULL it will be set to the source vertex of the diameter path.

pto:

Pointer to an integer, if not NULL it will be set to the target vertex of the diameter path.

path:

Pointer to an initialized vector. If not NULL the actual longest geodesic path will be stored here. The vector will be resized as needed.

directed:

Boolean, whether to consider directed paths. Ignored for undirected graphs.

unconn:

What to do if the graph is not connected. If TRUE the longest geodesic within a component will be returned, otherwise the number of vertices is returned. (The rationale behind the latter is that this is always longer than the longest possible diameter in a graph.)

Returns: 

Error code: IGRAPH_ENOMEM, not enough memory for temporary data.

Time complexity: O(|V||E|), the number of vertices times the number of edges.

Example 13.7.  File examples/simple/igraph_diameter.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2006-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.h>

void print_vector(igraph_vector_t *v) {
  long int i, n=igraph_vector_size(v);
  for (i=0; i<n; i++) {
    printf(" %li", (long int) VECTOR(*v)[i]);
  }
  printf("\n");
}

int main() {
  
  igraph_t g;
  igraph_integer_t result;
  igraph_integer_t from, to;
  igraph_vector_t path;
  
  igraph_barabasi_game(&g, 30, /*power=*/ 1, 30, 0, 0, /*A=*/ 1, 
		       IGRAPH_DIRECTED, IGRAPH_BARABASI_BAG, 
		       /*start_from=*/ 0);
  igraph_diameter(&g, &result, 0, 0, 0, IGRAPH_UNDIRECTED, 1);
  
/*   printf("Diameter: %li\n", (long int) result); */
  
  igraph_destroy(&g);

  igraph_ring(&g, 10, IGRAPH_DIRECTED, 0, 0);
  igraph_vector_init(&path, 0);
  igraph_diameter(&g, &result, &from, &to, &path, IGRAPH_DIRECTED, 1);
  printf("diameter: %li, from %li to %li\n", (long int) result,
	 (long int) from, (long int) to);
  print_vector(&path);
  
  igraph_vector_destroy(&path);
  igraph_destroy(&g);

  return 0;
}


2.14. igraph_diameter_dijkstra — Weighted diameter using Dijkstra's algorithm, non-negative weights only.

int igraph_diameter_dijkstra(const igraph_t *graph,
			     const igraph_vector_t *weights,
			     igraph_real_t *pres,
			     igraph_integer_t *pfrom,
			     igraph_integer_t *pto,
			     igraph_vector_t *path,
			     igraph_bool_t directed,
			     igraph_bool_t unconn);

The diameter of a graph is its longest geodesic. I.e. the (weighted) shortest path is calculated for all pairs of vertices and the longest one is the diameter.

Arguments: 

graph:

The input graph, can be directed or undirected.

pres:

Pointer to a real number, if not NULL then it will contain the diameter (the actual distance).

pfrom:

Pointer to an integer, if not NULL it will be set to the source vertex of the diameter path.

pto:

Pointer to an integer, if not NULL it will be set to the target vertex of the diameter path.

path:

Pointer to an initialized vector. If not NULL the actual longest geodesic path will be stored here. The vector will be resized as needed.

directed:

Boolean, whether to consider directed paths. Ignored for undirected graphs.

unconn:

What to do if the graph is not connected. If TRUE the longest geodesic within a component will be returned, otherwise IGRAPH_INFINITY is returned.

Returns: 

Error code.

Time complexity: O(|V||E|*log|E|), |V| is the number of vertices, |E| is the number of edges.

2.15. igraph_girth — The girth of a graph is the length of the shortest circle in it.

int igraph_girth(const igraph_t *graph, igraph_integer_t *girth, 
		 igraph_vector_t *circle);

The current implementation works for undirected graphs only, directed graphs are treated as undirected graphs. Loop edges and multiple edges are ignored.

If the graph is a forest (ie. acyclic), then zero is returned.

This implementation is based on Alon Itai and Michael Rodeh: Finding a minimum circuit in a graph Proceedings of the ninth annual ACM symposium on Theory of computing , 1-10, 1977. The first implementation of this function was done by Keith Briggs, thanks Keith.

Arguments: 

graph:

The input graph.

girth:

Pointer to an integer, if not NULL then the result will be stored here.

circle:

Pointer to an initialized vector, the vertex ids in the shortest circle will be stored here. If NULL then it is ignored.

Returns: 

Error code.

Time complexity: O((|V|+|E|)^2), |V| is the number of vertices, |E| is the number of edges in the general case. If the graph has no circles at all then the function needs O(|V|+|E|) time to realize this and then it stops.

Example 13.8.  File examples/simple/igraph_girth.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

int main() { 
  
  igraph_t g;
  igraph_integer_t girth;
  igraph_vector_t v;
  igraph_real_t chord[] = { 0, 50 };
  igraph_ring(&g, 100, IGRAPH_UNDIRECTED, 0, 1);
  igraph_vector_view(&v, chord, sizeof(chord)/sizeof(igraph_real_t));
  igraph_add_edges(&g, &v, 0);
  igraph_girth(&g, &girth, 0);
  if (girth != 51) {
    return 1;
  }
  
  igraph_destroy(&g);
  return 0;
}


2.16. igraph_eccentricity — Eccentricity of some vertices

int igraph_eccentricity(const igraph_t *graph, 
			igraph_vector_t *res,
			igraph_vs_t vids,
			igraph_neimode_t mode);

The eccentricity of a vertex is calculated by measuring the shortest distance from (or to) the vertex, to (or from) all vertices in the graph, and taking the maximum.

This implementation ignores vertex pairs that are in different components. Isolated vertices have eccentricity zero.

Arguments: 

graph:

The input graph, it can be directed or undirected.

res:

Pointer to an initialized vector, the result is stored here.

vids:

The vertices for which the eccentricity is calculated.

mode:

What kind of paths to consider for the calculation: IGRAPH_OUT, paths that follow edge directions; IGRAPH_IN, paths that follow the opposite directions; and IGRAPH_ALL, paths that ignore edge directions. This argument is ignored for undirected graphs.

Returns: 

Error code.

Time complexity: O(v*(|V|+|E|)), where |V| is the number of vertices, |E| is the number of edges and v is the number of vertices for which eccentricity is calculated.

See also: 

Example 13.9.  File examples/simple/igraph_eccentricity.c

/* -*- mode: C -*-  */
/* vim:set ts=2 sts=2 sw=2 et: */
/* 
   IGraph library.
   Copyright (C) 2011-12  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.h>

int main() {

  igraph_t g;
  igraph_vector_t ecc;

  igraph_vector_init(&ecc, 0);
  
  igraph_star(&g, 10, IGRAPH_STAR_UNDIRECTED, 0);
  igraph_eccentricity(&g, &ecc, igraph_vss_all(), IGRAPH_OUT);
  igraph_vector_print(&ecc);
  igraph_destroy(&g);
  
  igraph_star(&g, 10, IGRAPH_STAR_OUT, 0);
  igraph_eccentricity(&g, &ecc, igraph_vss_all(), IGRAPH_ALL);
  igraph_vector_print(&ecc);
  igraph_destroy(&g);

  igraph_star(&g, 10, IGRAPH_STAR_OUT, 0);
  igraph_eccentricity(&g, &ecc, igraph_vss_all(), IGRAPH_OUT);
  igraph_vector_print(&ecc);
  igraph_destroy(&g);  

  igraph_vector_destroy(&ecc);
  
  return 0;
}


2.17. igraph_radius — Radius of a graph

int igraph_radius(const igraph_t *graph, igraph_real_t *radius, 
		  igraph_neimode_t mode);

The radius of a graph is the defined as the minimum eccentricity of its vertices, see igraph_eccentricity().

Arguments: 

graph:

The input graph, it can be directed or undirected.

radius:

Pointer to a real variable, the result is stored here.

mode:

What kind of paths to consider for the calculation: IGRAPH_OUT, paths that follow edge directions; IGRAPH_IN, paths that follow the opposite directions; and IGRAPH_ALL, paths that ignore edge directions. This argument is ignored for undirected graphs.

Returns: 

Error code.

Time complexity: O(|V|(|V|+|E|)), where |V| is the number of vertices and |E| is the number of edges.

See also: 

Example 13.10.  File examples/simple/igraph_radius.c

/* -*- mode: C -*-  */
/* vim:set ts=2 sts=2 sw=2 et: */
/* 
   IGraph library.
   Copyright (C) 2011-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.h>

int main() {

  igraph_t g;
  igraph_real_t radius;

  igraph_star(&g, 10, IGRAPH_STAR_UNDIRECTED, 0);
  igraph_radius(&g, &radius, IGRAPH_OUT);
  if (radius != 1) { return 1; }
  igraph_destroy(&g);
  
  igraph_star(&g, 10, IGRAPH_STAR_OUT, 0);
  igraph_radius(&g, &radius, IGRAPH_ALL);
  if (radius != 1) { return 2; }
  igraph_destroy(&g);

  igraph_star(&g, 10, IGRAPH_STAR_OUT, 0);
  igraph_radius(&g, &radius, IGRAPH_OUT);
  if (radius != 0) { return 3; }
  igraph_destroy(&g);  

  return 0;
}


3. Neighborhood of a vertex

3.1. igraph_neighborhood_size — Calculates the size of the neighborhood of a given vertex.

int igraph_neighborhood_size(const igraph_t *graph, igraph_vector_t *res,
			     igraph_vs_t vids, igraph_integer_t order,
			     igraph_neimode_t mode);

The neighborhood of a given order of a vertex includes all vertices which are closer to the vertex than the order. Ie. order 0 is always the vertex itself, order 1 is the vertex plus its immediate neighbors, order 2 is order 1 plus the immediate neighbors of the vertices in order 1, etc.

This function calculates the size of the neighborhood of the given order for the given vertices.

Arguments: 

graph:

The input graph.

res:

Pointer to an initialized vector, the result will be stored here. It will be resized as needed.

vids:

The vertices for which the calculation is performed.

order:

Integer giving the order of the neighborhood.

mode:

Specifies how to use the direction of the edges if a directed graph is analyzed. For IGRAPH_OUT only the outgoing edges are followed, so all vertices reachable from the source vertex in at most order steps are counted. For IGRAPH_IN all vertices from which the source vertex is reachable in at most order steps are counted. IGRAPH_ALL ignores the direction of the edges. This argument is ignored for undirected graphs.

Returns: 

Error code.

See also: 

igraph_neighborhood() for calculating the actual neighborhood, igraph_neighborhood_graphs() for creating separate graphs from the neighborhoods.

Time complexity: O(n*d*o), where n is the number vertices for which the calculation is performed, d is the average degree, o is the order.

3.2. igraph_neighborhood — Calculate the neighborhood of vertices.

int igraph_neighborhood(const igraph_t *graph, igraph_vector_ptr_t *res,
			igraph_vs_t vids, igraph_integer_t order,
			igraph_neimode_t mode);

The neighborhood of a given order of a vertex includes all vertices which are closer to the vertex than the order. Ie. order 0 is always the vertex itself, order 1 is the vertex plus its immediate neighbors, order 2 is order 1 plus the immediate neighbors of the vertices in order 1, etc.

This function calculates the vertices within the neighborhood of the specified vertices.

Arguments: 

graph:

The input graph.

res:

An initialized pointer vector. Note that the objects (pointers) in the vector will not be freed, but the pointer vector will be resized as needed. The result of the calculation will be stored here in vector_t objects.

vids:

The vertices for which the calculation is performed.

order:

Integer giving the order of the neighborhood.

mode:

Specifies how to use the direction of the edges if a directed graph is analyzed. For IGRAPH_OUT only the outgoing edges are followed, so all vertices reachable from the source vertex in at most order steps are included. For IGRAPH_IN all vertices from which the source vertex is reachable in at most order steps are included. IGRAPH_ALL ignores the direction of the edges. This argument is ignored for undirected graphs.

Returns: 

Error code.

See also: 

igraph_neighborhood_size() to calculate the size of the neighborhood, igraph_neighborhood_graphs() for creating graphs from the neighborhoods.

Time complexity: O(n*d*o), n is the number of vertices for which the calculation is performed, d is the average degree, o is the order.

3.3. igraph_neighborhood_graphs — Create graphs from the neighborhood(s) of some vertex/vertices.

int igraph_neighborhood_graphs(const igraph_t *graph, igraph_vector_ptr_t *res,
			       igraph_vs_t vids, igraph_integer_t order,
			       igraph_neimode_t mode);

The neighborhood of a given order of a vertex includes all vertices which are closer to the vertex than the order. Ie. order 0 is always the vertex itself, order 1 is the vertex plus its immediate neighbors, order 2 is order 1 plus the immediate neighbors of the vertices in order 1, etc.

This function finds every vertex in the neighborhood of a given parameter vertex and creates a graph from these vertices.

The first version of this function was written by Vincent Matossian, thanks Vincent.

Arguments: 

graph:

The input graph.

res:

Pointer to a pointer vector, the result will be stored here, ie. res will contain pointers to igraph_t objects. It will be resized if needed but note that the objects in the pointer vector will not be freed.

vids:

The vertices for which the calculation is performed.

order:

Integer giving the order of the neighborhood.

mode:

Specifies how to use the direction of the edges if a directed graph is analyzed. For IGRAPH_OUT only the outgoing edges are followed, so all vertices reachable from the source vertex in at most order steps are counted. For IGRAPH_IN all vertices from which the source vertex is reachable in at most order steps are counted. IGRAPH_ALL ignores the direction of the edges. This argument is ignored for undirected graphs.

Returns: 

Error code.

See also: 

igraph_neighborhood_size() for calculating the neighborhood sizes only, igraph_neighborhood() for calculating the neighborhoods (but not creating graphs).

Time complexity: O(n*(|V|+|E|)), where n is the number vertices for which the calculation is performed, |V| and |E| are the number of vertices and edges in the original input graph.

4. Graph Components

4.1. igraph_subcomponent — The vertices in the same component as a given vertex.

int igraph_subcomponent(const igraph_t *graph, igraph_vector_t *res, igraph_real_t vertex, 
			igraph_neimode_t mode);

Arguments: 

graph:

The graph object.

res:

The result, vector with the ids of the vertices in the same component.

vertex:

The id of the vertex of which the component is searched.

mode:

Type of the component for directed graphs, possible values:

IGRAPH_OUT

the set of vertices reachable from the vertex,

IGRAPH_IN

the set of vertices from which the vertex is reachable.

IGRAPH_ALL

the graph is considered as an undirected graph. Note that this is not the same as the union of the previous two.

Returns: 

Error code:

IGRAPH_ENOMEM

not enough memory for temporary data.

IGRAPH_EINVVID

vertex is an invalid vertex id

IGRAPH_EINVMODE

invalid mode argument passed.

Time complexity: O(|V|+|E|), |V| and |E| are the number of vertices and edges in the graph.

See also: 

igraph_subgraph() if you want a graph object consisting only a given set of vertices and the edges between them.

4.2. igraph_induced_subgraph — Creates a subgraph induced by the specified vertices.

int igraph_induced_subgraph(const igraph_t *graph, igraph_t *res, 
		    const igraph_vs_t vids, igraph_subgraph_implementation_t impl);

This function collects the specified vertices and all edges between them to a new graph. As the vertex ids in a graph always start with zero, this function very likely needs to reassign ids to the vertices.

Arguments: 

graph:

The graph object.

res:

The subgraph, another graph object will be stored here, do not initialize this object before calling this function, and call igraph_destroy() on it if you don't need it any more.

vids:

A vertex selector describing which vertices to keep.

impl:

This parameter selects which implementation should we use when constructing the new graph. Basically there are two possibilities: IGRAPH_SUBGRAPH_COPY_AND_DELETE copies the existing graph and deletes the vertices that are not needed in the new graph, while IGRAPH_SUBGRAPH_CREATE_FROM_SCRATCH constructs the new graph from scratch without copying the old one. The latter is more efficient if you are extracting a relatively small subpart of a very large graph, while the former is better if you want to extract a subgraph whose size is comparable to the size of the whole graph. There is a third possibility: IGRAPH_SUBGRAPH_AUTO will select one of the two methods automatically based on the ratio of the number of vertices in the new and the old graph.

Returns: 

Error code: IGRAPH_ENOMEM, not enough memory for temporary data. IGRAPH_EINVVID, invalid vertex id in vids.

Time complexity: O(|V|+|E|), |V| and |E| are the number of vertices and edges in the original graph.

See also: 

igraph_delete_vertices() to delete the specified set of vertices from a graph, the opposite of this function.

4.3. igraph_subgraph_edges — Creates a subgraph with the specified edges and their endpoints.

int igraph_subgraph_edges(const igraph_t *graph, igraph_t *res, 
		    const igraph_es_t eids, igraph_bool_t delete_vertices);

This function collects the specified edges and their endpoints to a new graph. As the vertex ids in a graph always start with zero, this function very likely needs to reassign ids to the vertices.

Arguments: 

graph:

The graph object.

res:

The subgraph, another graph object will be stored here, do not initialize this object before calling this function, and call igraph_destroy() on it if you don't need it any more.

eids:

An edge selector describing which edges to keep.

delete_vertices:

Whether to delete the vertices not incident on any of the specified edges as well. If FALSE, the number of vertices in the result graph will always be equal to the number of vertices in the input graph.

Returns: 

Error code: IGRAPH_ENOMEM, not enough memory for temporary data. IGRAPH_EINVEID, invalid edge id in eids.

Time complexity: O(|V|+|E|), |V| and |E| are the number of vertices and edges in the original graph.

See also: 

igraph_delete_edges() to delete the specified set of edges from a graph, the opposite of this function.

4.4. igraph_subgraph — Creates a subgraph induced by the specified vertices.

int igraph_subgraph(const igraph_t *graph, igraph_t *res, 
		    const igraph_vs_t vids);

This function is an alias to igraph_induced_subgraph(), it is left here to ensure API compatibility with igraph versions prior to 0.6.

This function collects the specified vertices and all edges between them to a new graph. As the vertex ids in a graph always start with zero, this function very likely needs to reassign ids to the vertices.

Arguments: 

graph:

The graph object.

res:

The subgraph, another graph object will be stored here, do not initialize this object before calling this function, and call igraph_destroy() on it if you don't need it any more.

vids:

A vertex selector describing which vertices to keep.

Returns: 

Error code: IGRAPH_ENOMEM, not enough memory for temporary data. IGRAPH_EINVVID, invalid vertex id in vids.

Time complexity: O(|V|+|E|), |V| and |E| are the number of vertices and edges in the original graph.

See also: 

igraph_delete_vertices() to delete the specified set of vertices from a graph, the opposite of this function.

4.5. igraph_clusters — Calculates the (weakly or strongly) connected components in a graph.

int igraph_clusters(const igraph_t *graph, igraph_vector_t *membership, 
		    igraph_vector_t *csize, igraph_integer_t *no,
		    igraph_connectedness_t mode);

Arguments: 

graph:

The graph object to analyze.

membership:

First half of the result will be stored here. For every vertex the id of its component is given. The vector has to be preinitialized and will be resized. Alternatively this argument can be NULL, in which case it is ignored.

csize:

The second half of the result. For every component it gives its size, the order is defined by the component ids. The vector has to be preinitialized and will be resized. Alternatively this argument can be NULL, in which case it is ignored.

no:

Pointer to an integer, if not NULL then the number of clusters will be stored here.

mode:

For directed graph this specifies whether to calculate weakly or strongly connected components. Possible values: IGRAPH_WEAK, IGRAPH_STRONG. This argument is ignored for undirected graphs.

Returns: 

Error code: IGRAPH_EINVAL: invalid mode argument.

Time complexity: O(|V|+|E|), |V| and |E| are the number of vertices and edges in the graph.

4.6. igraph_is_connected — Decides whether the graph is (weakly or strongly) connected.

int igraph_is_connected(const igraph_t *graph, igraph_bool_t *res, 
			igraph_connectedness_t mode);

A graph with zero vertices (i.e. the null graph) is connected by definition.

Arguments: 

graph:

The graph object to analyze.

res:

Pointer to a logical variable, the result will be stored here.

mode:

For a directed graph this specifies whether to calculate weak or strong connectedness. Possible values: IGRAPH_WEAK, IGRAPH_STRONG. This argument is ignored for undirected graphs.

Returns: 

Error code: IGRAPH_EINVAL: invalid mode argument.

Time complexity: O(|V|+|E|), the number of vertices plus the number of edges in the graph.

4.7. igraph_decompose — Decompose a graph into connected components.

int igraph_decompose(const igraph_t *graph, igraph_vector_ptr_t *components, 
		     igraph_connectedness_t mode,
		     long int maxcompno, long int minelements);

Create separate graph for each component of a graph. Note that the vertex ids in the new graphs will be different than in the original graph. (Except if there is only one component in the original graph.)

Arguments: 

graph:

The original graph.

components:

This pointer vector will contain pointers to the subcomponent graphs. It should be initialized before calling this function and will be resized to hold the graphs. Don't forget to call igraph_destroy() and free() on the elements of this pointer vector to free unneeded memory. Alternatively, you can simply call igraph_decompose_destroy() that does this for you.

mode:

Either IGRAPH_WEAK or IGRAPH_STRONG for weakly and strongly connected components respectively. Right now only the former is implemented.

maxcompno:

The maximum number of components to return. The first maxcompno components will be returned (which hold at least minelements vertices, see the next parameter), the others will be ignored. Supply -1 here if you don't want to limit the number of components.

minelements:

The minimum number of vertices a component should contain in order to place it in the components vector. Eg. supply 2 here to ignore isolated vertices.

Returns: 

Error code, IGRAPH_ENOMEM if there is not enough memory to perform the operation.

Added in version 0.2.

Time complexity: O(|V|+|E|), the number of vertices plus the number of edges.

Example 13.11.  File examples/simple/igraph_decompose.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2006-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.h>
#include <stdlib.h>

void free_complist(igraph_vector_ptr_t *complist) {
  long int i;
  for (i=0; i<igraph_vector_ptr_size(complist); i++) {
    igraph_destroy(VECTOR(*complist)[i]);
    free(VECTOR(*complist)[i]);
  }
}

int main() {
  
  igraph_t ring, g;
  igraph_vector_ptr_t complist;
  long int i;
  igraph_real_t edges[]= { 0,1,1,2,2,0,
		    3,4,4,5,5,6,
		    8,9,9,10 };
  igraph_vector_t v;

  /* A ring, a single component */
  igraph_ring(&ring, 10, IGRAPH_UNDIRECTED, 0, 1);
  
  igraph_vector_ptr_init(&complist, 0);
  igraph_decompose(&ring, &complist, IGRAPH_WEAK, -1, 0);
  igraph_write_graph_edgelist(VECTOR(complist)[0], stdout);
  free_complist(&complist);
  igraph_destroy(&ring);
  
  /* random graph with a giant component */
  igraph_erdos_renyi_game(&g, IGRAPH_ERDOS_RENYI_GNP, 100, 4.0/100, 
			  IGRAPH_UNDIRECTED, 0);
  igraph_decompose(&g, &complist, IGRAPH_WEAK, -1, 20);
  if (igraph_vector_ptr_size(&complist) != 1) { 
    return 1;
  }
  free_complist(&complist);
  igraph_destroy(&g);
  
  /* a toy graph, three components maximum, with at least 2 vertices each */
  igraph_create(&g, 
		igraph_vector_view(&v, edges, sizeof(edges)/sizeof(igraph_real_t)), 
		0, IGRAPH_DIRECTED);
  igraph_decompose(&g, &complist, IGRAPH_WEAK, 3, 2);
  for (i=0; i<igraph_vector_ptr_size(&complist); i++) {
    igraph_write_graph_edgelist(VECTOR(complist)[i], stdout);
  }
  free_complist(&complist);
  igraph_destroy(&g);

  /* The same graph, this time with vertex attributes */
/*   igraph_vector_init_seq(&idvect, 0, igraph_vcount(&g)-1); */
/*   igraph_add_vertex_attribute(&g, "id", IGRAPH_ATTRIBUTE_NUM); */
/*   igraph_set_vertex_attributes(&g, "id", IGRAPH_VS_ALL(&g), &idvect); */
/*   igraph_vector_destroy(&idvect); */

/*   igraph_decompose(&g, &complist, IGRAPH_WEAK, 3, 2); */
/*   for (i=0; i<igraph_vector_ptr_size(&complist); i++) { */
/*     igraph_t *comp=VECTOR(complist)[i]; */
/*     igraph_es_t es; */
/*     igraph_es_all(comp, &es); */
/*     while (!igraph_es_end(comp, &es)) { */
/*       igraph_real_t *from, *to;  */
/*       igraph_get_vertex_attribute(comp, "id", igraph_es_from(comp, &es), */
/* 				  (void**) &from, 0); */
/*       igraph_get_vertex_attribute(comp, "id", igraph_es_to(comp, &es), */
/* 				  (void**) &to, 0); */
/*       printf("%li %li\n", (long int) *from, (long int) *to); */
/*       igraph_es_next(comp, &es); */
/*     } */
/*   } */
  
/*   free_complist(&complist); */
/*   igraph_destroy(&g);   */
  
  igraph_vector_ptr_destroy(&complist);

  return 0;
}


4.8. igraph_decompose_destroy — Free the memory allocated by igraph_decompose().

void igraph_decompose_destroy(igraph_vector_ptr_t *complist);

Arguments: 

complist:

The list of graph components, as returned by igraph_decompose().

Time complexity: O(c), c is the number of components.

4.9. igraph_biconnected_components — Calculate biconnected components

int igraph_biconnected_components(const igraph_t *graph,
				  igraph_integer_t *no,
				  igraph_vector_ptr_t *tree_edges,
				  igraph_vector_ptr_t *component_edges,
				  igraph_vector_ptr_t *components,
				  igraph_vector_t *articulation_points);

A graph is biconnected if the removal of any single vertex (and its incident edges) does not disconnect it.

A biconnected component of a graph is a maximal biconnected subgraph of it. The biconnected components of a graph can be given by the partition of its edges: every edge is a member of exactly one biconnected component. Note that this is not true for vertices: the same vertex can be part of many biconnected components.

Arguments: 

graph:

The input graph.

no:

The number of biconnected components will be stored here.

tree_edges:

If not a NULL pointer, then the found components are stored here, in a list of vectors. Every vector in the list is a biconnected component, represented by its edges. More precisely, a spanning tree of the biconnected component is returned. Note you'll have to destroy each vector first by calling igraph_vector_destroy() and then free() on it, plus you need to call igraph_vector_ptr_destroy() on the list to regain all allocated memory.

component_edges:

If not a NULL pointer, then the edges of the biconnected components are stored here, in the same form as for tree_edges.

components:

If not a NULL pointer, then the vertices of the biconnected components are stored here, in the same format as for the previous two arguments.

articulation_points:

If not a NULL pointer, then the articulation points of the graph are stored in this vector. A vertex is an articulation point if its removal increases the number of (weakly) connected components in the graph.

Returns: 

Error code.

Time complexity: O(|V|+|E|), linear in the number of vertices and edges, but only if you do not calculate components and component_edges. If you calculate components, then it is quadratic in the number of vertices. If you calculate component_edges as well, then it is cubic in the number of vertices.

See also: 

Example 13.12.  File examples/simple/igraph_biconnected_components.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2006-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.h>
#include <stdlib.h>

void sort_and_print_vector(igraph_vector_t *v) {
  long int i, n=igraph_vector_size(v);
  igraph_vector_sort(v);
  for (i=0; i<n; i++) {
    printf(" %li", (long int) VECTOR(*v)[i]);
  }
  printf("\n");
}

void warning_handler_ignore(const char* reason,const char* file,int line,int e) {
}

int main() {
  
  igraph_t g;
  igraph_vector_ptr_t result;
  igraph_integer_t no;
  long int i;
 
  igraph_set_warning_handler(warning_handler_ignore);

  igraph_vector_ptr_init(&result, 0);
  igraph_small(&g, 7, 0, 0, 1, 1, 2, 2, 3, 3, 0, 2, 4, 4, 5, 2, 5, -1);
  
  igraph_biconnected_components(&g, &no, 0, 0, &result, 0);
  if (no != 2 || no != igraph_vector_ptr_size(&result)) return 1;
  for (i = 0; i < no; i++) {
    sort_and_print_vector((igraph_vector_t*)VECTOR(result)[i]);
    igraph_vector_destroy((igraph_vector_t*)VECTOR(result)[i]);
    free((igraph_vector_t*)VECTOR(result)[i]);
  }

  igraph_biconnected_components(&g, &no, 0, &result, 0, 0);
  if (no != 2 || no != igraph_vector_ptr_size(&result)) return 2;
  for (i = 0; i < no; i++) {
    sort_and_print_vector((igraph_vector_t*)VECTOR(result)[i]);
    igraph_vector_destroy((igraph_vector_t*)VECTOR(result)[i]);
    free((igraph_vector_t*)VECTOR(result)[i]);
  }

  igraph_biconnected_components(&g, &no, &result, 0, 0, 0);
  if (no != 2 || no != igraph_vector_ptr_size(&result)) return 3;
  for (i = 0; i < no; i++) {
    sort_and_print_vector((igraph_vector_t*)VECTOR(result)[i]);
    igraph_vector_destroy((igraph_vector_t*)VECTOR(result)[i]);
    free((igraph_vector_t*)VECTOR(result)[i]);
  }

  igraph_vector_ptr_destroy(&result);
  igraph_destroy(&g);

  return 0;
}


4.10. igraph_articulation_points — Find the articulation points in a graph.

int igraph_articulation_points(const igraph_t *graph,
			       igraph_vector_t *res);

A vertex is an articulation point if its removal increases the number of connected components in the graph.

Arguments: 

graph:

The input graph.

res:

Pointer to an initialized vector, the articulation points will be stored here.

Returns: 

Error code.

Time complexity: O(|V|+|E|), linear in the number of vertices and edges.

See also: 

5. Degree Sequences

5.1. igraph_is_degree_sequence — Determines whether a degree sequence is valid.

int igraph_is_degree_sequence(const igraph_vector_t *out_degrees,
    const igraph_vector_t *in_degrees, igraph_bool_t *res);

A sequence of n integers is a valid degree sequence if there exists some graph where the degree of the i-th vertex is equal to the i-th element of the sequence. Note that the graph may contain multiple or loop edges; if you are interested in whether the degrees of some simple graph may realize the given sequence, use igraph_is_graphical_degree_sequence.

In particular, the function checks whether all the degrees are non-negative. For undirected graphs, it also checks whether the sum of degrees is even. For directed graphs, the function checks whether the lengths of the two degree vectors are equal and whether their sums are also equal. These are known sufficient and necessary conditions for a degree sequence to be valid.

Arguments: 

out_degrees:

an integer vector specifying the degree sequence for undirected graphs or the out-degree sequence for directed graphs.

in_degrees:

an integer vector specifying the in-degrees of the vertices for directed graphs. For undirected graphs, this must be null.

res:

pointer to a boolean variable, the result will be stored here

Returns: 

Error code.

Time complexity: O(n), where n is the length of the degree sequence.

5.2. igraph_is_graphical_degree_sequence — Determines whether a sequence of integers can be a degree sequence of some

int igraph_is_graphical_degree_sequence(const igraph_vector_t *out_degrees,
    const igraph_vector_t *in_degrees, igraph_bool_t *res);

simple graph.

References:

Hakimi SL: On the realizability of a set of integers as degrees of the vertices of a simple graph. J SIAM Appl Math 10:496-506, 1962.

PL Erdos, I Miklos and Z Toroczkai: A simple Havel-Hakimi type algorithm to realize graphical degree sequences of directed graphs. The Electronic Journal of Combinatorics 17(1):R66, 2010.

Arguments: 

out_degrees:

an integer vector specifying the degree sequence for undirected graphs or the out-degree sequence for directed graphs.

in_degrees:

an integer vector specifying the in-degrees of the vertices for directed graphs. For undirected graphs, this must be null.

res:

pointer to a boolean variable, the result will be stored here

Returns: 

Error code.

Time complexity: O(n^2 log n) where n is the length of the degree sequence.

6. Centrality Measures

6.1. igraph_closeness — Closeness centrality calculations for some vertices.

int igraph_closeness(const igraph_t *graph, igraph_vector_t *res,
                     const igraph_vs_t vids, igraph_neimode_t mode, 
		     const igraph_vector_t *weights,
		     igraph_bool_t normalized);

The closeness centrality of a vertex measures how easily other vertices can be reached from it (or the other way: how easily it can be reached from the other vertices). It is defined as the number of the number of vertices minus one divided by the sum of the lengths of all geodesics from/to the given vertex.

If the graph is not connected, and there is no path between two vertices, the number of vertices is used instead the length of the geodesic. This is always longer than the longest possible geodesic.

Arguments: 

graph:

The graph object.

res:

The result of the computation, a vector containing the closeness centrality scores for the given vertices.

vids:

Vector giving the vertices for which the closeness centrality scores will be computed.

mode:

The type of shortest paths to be used for the calculation in directed graphs. Possible values:

IGRAPH_OUT

the lengths of the outgoing paths are calculated.

IGRAPH_IN

the lengths of the incoming paths are calculated.

IGRAPH_ALL

the directed graph is considered as an undirected one for the computation.

weights:

An optional vector containing edge weights for weighted closeness. Supply a null pointer here for traditional, unweighted closeness.

normalized:

Boolean, whether to normalize results by multiplying by the number of vertices minus one.

Returns: 

Error code:

IGRAPH_ENOMEM

not enough memory for temporary data.

IGRAPH_EINVVID

invalid vertex id passed.

IGRAPH_EINVMODE

invalid mode argument.

Time complexity: O(n|E|), n is the number of vertices for which the calculation is done and |E| is the number of edges in the graph.

See also: 

Other centrality types: igraph_degree(), igraph_betweenness(). See igraph_closeness_estimate() to estimate closeness values.

6.2. igraph_betweenness — Betweenness centrality of some vertices.

int igraph_betweenness(const igraph_t *graph, igraph_vector_t *res,
		       const igraph_vs_t vids, igraph_bool_t directed, 
		       const igraph_vector_t* weights, igraph_bool_t nobigint);

The betweenness centrality of a vertex is the number of geodesics going through it. If there are more than one geodesic between two vertices, the value of these geodesics are weighted by one over the number of geodesics.

Arguments: 

graph:

The graph object.

res:

The result of the computation, a vector containing the betweenness scores for the specified vertices.

vids:

The vertices of which the betweenness centrality scores will be calculated.

directed:

Logical, if true directed paths will be considered for directed graphs. It is ignored for undirected graphs.

weights:

An optional vector containing edge weights for calculating weighted betweenness. Supply a null pointer here for unweighted betweenness.

nobigint:

Logical, if true, then we don't use big integers for the calculation, setting this to 1 (=true) should work for most graphs. It is currently ignored for weighted graphs.

Returns: 

Error code: IGRAPH_ENOMEM, not enough memory for temporary data. IGRAPH_EINVVID, invalid vertex id passed in vids.

Time complexity: O(|V||E|), |V| and |E| are the number of vertices and edges in the graph. Note that the time complexity is independent of the number of vertices for which the score is calculated.

See also: 

Other centrality types: igraph_degree(), igraph_closeness(). See igraph_edge_betweenness() for calculating the betweenness score of the edges in a graph. See igraph_betweenness_estimate() to estimate the betweenness score of the vertices in a graph.

Example 13.13.  File examples/simple/igraph_betweenness.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2008-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.h>

void print_vector(igraph_vector_t *v, FILE *f) {
  long int i;
  for (i=0; i<igraph_vector_size(v); i++) {
    fprintf(f, " %li", (long int) VECTOR(*v)[i]);
  }
  fprintf(f, "\n");
}

int main() {
  
  igraph_t g;
  igraph_vector_t bet, bet2, weights, edges;
  
  igraph_real_t nontriv[] = { 0, 19, 0, 16, 0, 20, 1, 19, 2, 5, 3, 7, 3, 8, 
			      4, 15, 4, 11, 5, 8, 5, 19, 6, 7, 6, 10, 6, 8, 
			      6, 9, 7, 20, 9, 10, 9, 20, 10, 19, 
			      11, 12, 11, 20, 12, 15, 13, 15, 
			      14, 18, 14, 16, 14, 17, 15, 16, 17, 18 };
  
  igraph_real_t nontriv_weights[] = { 0.5249, 1, 0.1934, 0.6274, 0.5249, 
				      0.0029, 0.3831, 0.05, 0.6274, 0.3831, 
				      0.5249, 0.0587, 0.0579, 0.0562, 0.0562, 
				      0.1934, 0.6274, 0.6274, 0.6274, 0.0418, 
				      0.6274, 0.3511, 0.3511, 0.1486, 1, 1, 
				      0.0711, 0.2409 };

  igraph_real_t nontriv_res[] = { 20, 0, 0, 0, 0, 19, 80, 85, 32, 0, 10, 
				  75, 70, 0, 36, 81, 60, 0, 19, 19, 86 };

  /*******************************************************/

  igraph_barabasi_game(/* graph= */    &g,
		       /* n= */        1000,
		       /* power= */    1,
		       /* m= */        3,
		       /* outseq= */   0,
		       /* outpref= */  0,
		       /* A= */        1,
		       /* directed= */ 0,
		       /* algo= */     IGRAPH_BARABASI_BAG,
		       /* start_from= */ 0);
  
  igraph_simplify(&g, /* multiple= */ 1, /* loops= */ 1, /*edge_comb=*/ 0);
  
  igraph_vector_init(&bet, 0);
  
  igraph_betweenness_estimate(/* graph=     */ &g,
			      /* res=       */ &bet,
			      /* vids=      */ igraph_vss_all(),
			      /* directed = */ 0,
			      /* cutoff=    */ 2,
			      /* weights=   */ 0, 
			      /* nobigint=  */ 1);
  
  igraph_vector_destroy(&bet);
  igraph_destroy(&g);

  /*******************************************************/

  igraph_tree(&g, 20000, 10, IGRAPH_TREE_UNDIRECTED);
  
  igraph_vector_init(&bet, 0);
  
  igraph_betweenness_estimate(/* graph=     */ &g,
			      /* res=       */ &bet,
			      /* vids=      */ igraph_vss_all(),
			      /* directed = */ 0,
			      /* cutoff=    */ 3,
			      /* weights=   */ 0, 
			      /* nobigint=  */ 1);

  igraph_vector_init(&bet2, 0);
  igraph_vector_init(&weights, igraph_ecount(&g));
  igraph_vector_fill(&weights, 1.0);
  
  igraph_betweenness_estimate(/* graph=     */ &g,
			      /* res=       */ &bet2,
			      /* vids=      */ igraph_vss_all(),
			      /* directed = */ 0,
			      /* cutoff=    */ 3,
			      /* weights=   */ &weights, 
			      /* nobigint=  */ 1);

  if (!igraph_vector_all_e(&bet, &bet2)) {
    return 1;
  }

  igraph_vector_destroy(&bet);
  igraph_vector_destroy(&bet2);
  igraph_vector_destroy(&weights);
  igraph_destroy(&g);

  /* Non-trivial weighted graph */
  igraph_vector_view(&edges, nontriv, sizeof(nontriv)/sizeof(igraph_real_t));
  igraph_create(&g, &edges, 0, /* directed= */ 0);
  igraph_vector_view(&weights, nontriv_weights, 
		     sizeof(nontriv_weights)/sizeof(igraph_real_t));
  igraph_vector_init(&bet, 0);

  igraph_betweenness(/*graph=*/ &g, /*res=*/ &bet, /*vids=*/ igraph_vss_all(), 
		     /*directed=*/0, /*weights=*/ &weights, /*nobigint=*/ 1);

  igraph_vector_view(&bet2, nontriv_res, 
		     sizeof(nontriv_res)/sizeof(igraph_real_t));

  if (!igraph_vector_all_e(&bet, &bet2)) {
    return 2;
  }
  
  igraph_vector_destroy(&bet);
  igraph_destroy(&g);

  return 0;
}


6.3. igraph_edge_betweenness — Betweenness centrality of the edges.

int igraph_edge_betweenness(const igraph_t *graph, igraph_vector_t *result,
                            igraph_bool_t directed, 
			    const igraph_vector_t *weights);

The betweenness centrality of an edge is the number of geodesics going through it. If there are more than one geodesics between two vertices, the value of these geodesics are weighted by one over the number of geodesics.

Arguments: 

graph:

The graph object.

result:

The result of the computation, vector containing the betweenness scores for the edges.

directed:

Logical, if true directed paths will be considered for directed graphs. It is ignored for undirected graphs.

weights:

An optional weight vector for weighted edge betweenness. Supply a null pointer here for the unweighted version.

Returns: 

Error code: IGRAPH_ENOMEM, not enough memory for temporary data.

Time complexity: O(|V||E|), |V| and |E| are the number of vertices and edges in the graph.

See also: 

Other centrality types: igraph_degree(), igraph_closeness(). See igraph_edge_betweenness() for calculating the betweenness score of the edges in a graph. See igraph_edge_betweenness_estimate() to estimate the betweenness score of the edges in a graph.

Example 13.14.  File examples/simple/igraph_edge_betweenness.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2006-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.h>

void print_vector(igraph_vector_t *v, FILE *f) {
  long int i;
  for (i=0; i<igraph_vector_size(v); i++) {
    fprintf(f, "%.5f\n", (double) VECTOR(*v)[i]);
  }
  fprintf(f, "\n");
}

int main() {

  igraph_t g;
  igraph_vector_t eb; 

  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 
	       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,  8,  2,  9,  2, 13,  2, 27,
	       2, 28,  2, 32,  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, 29,
	       23, 32, 23, 33, 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,
	       -1);
  
  igraph_vector_init(&eb, igraph_ecount(&g));
  igraph_edge_betweenness(&g, &eb, IGRAPH_UNDIRECTED, /*weights=*/ 0);
  print_vector(&eb, stdout);
  igraph_vector_destroy(&eb);
  igraph_destroy(&g);

  igraph_small(&g, 0, IGRAPH_UNDIRECTED,
    0, 1, 0, 2, 0, 3, 1, 4, -1);
  igraph_vector_init(&eb, igraph_ecount(&g));
  igraph_edge_betweenness_estimate(&g, &eb, IGRAPH_UNDIRECTED, 2, 
				   /*weights=*/ 0);
  print_vector(&eb, stdout);
  igraph_vector_destroy(&eb);
  igraph_destroy(&g);

  igraph_small(&g, 0, IGRAPH_UNDIRECTED,
    0, 1, 0, 3, 1, 2, 1, 4, 2, 5, 3, 4, 3, 6, 4, 5, 4, 7, 5, 8,
    6, 7, 7, 8, -1);
  igraph_vector_init(&eb, igraph_ecount(&g));
  igraph_edge_betweenness_estimate(&g, &eb, IGRAPH_UNDIRECTED, 2,
				   /*weights=*/ 0);
  print_vector(&eb, stdout);
  igraph_vector_destroy(&eb);
  igraph_destroy(&g);

  return 0;
}


6.4. igraph_pagerank_algo_t — PageRank algorithm implementation

typedef enum {
  IGRAPH_PAGERANK_ALGO_POWER=0,
  IGRAPH_PAGERANK_ALGO_ARPACK=1,
  IGRAPH_PAGERANK_ALGO_PRPACK=2
} igraph_pagerank_algo_t;

Algorithms to calculate PageRank.

Values: 

IGRAPH_PAGERANK_ALGO_POWER:

Use a simple power iteration, as it was implemented before igraph version 0.5.

IGRAPH_PAGERANK_ALGO_ARPACK:

Use the ARPACK library, this was the PageRank implementation in igraph from version 0.5, until version 0.7.

IGRAPH_PAGERANK_ALGO_PRPACK:

Use the PRPACK library. Currently this implementation is recommended.

6.5. igraph_pagerank_power_options_t — Options for the power method

typedef struct igraph_pagerank_power_options_t {
  igraph_integer_t niter;
  igraph_real_t eps;
} igraph_pagerank_power_options_t;

Values: 

niter:

The number of iterations to perform, integer.

eps:

The algorithm will consider the calculation as complete if the difference of values between iterations change less than this value for every vertex.

6.6. igraph_pagerank — Calculates the Google PageRank for the specified vertices.

int igraph_pagerank(const igraph_t *graph, igraph_pagerank_algo_t algo,
		    igraph_vector_t *vector,
		    igraph_real_t *value, const igraph_vs_t vids,
		    igraph_bool_t directed, igraph_real_t damping, 
		    const igraph_vector_t *weights, void *options);

Starting from version 0.7, igraph has three PageRank implementations, and the user can choose between them. The first implementation is IGRAPH_PAGERANK_ALGO_POWER, also available as the (now deprecated) function igraph_pagerank_old(). The second implementation is based on the ARPACK library, this was the default before igraph version 0.7: IGRAPH_PAGERANK_ALGO_ARPACK. The third and recommmended implementation is IGRAPH_PAGERANK_ALGO_PRPACK. This is using the the PRPACK package, see https://github.com/dgleich/prpack .

Please note that the PageRank of a given vertex depends on the PageRank of all other vertices, so even if you want to calculate the PageRank for only some of the vertices, all of them must be calculated. Requesting the PageRank for only some of the vertices does not result in any performance increase at all.

For the explanation of the PageRank algorithm, see the following webpage: http://infolab.stanford.edu/~backrub/google.html , or the following reference:

Sergey Brin and Larry Page: The Anatomy of a Large-Scale Hypertextual Web Search Engine. Proceedings of the 7th World-Wide Web Conference, Brisbane, Australia, April 1998.

Arguments: 

graph:

The graph object.

algo:

The PageRank implementation to use. Possible values: IGRAPH_PAGERANK_ALGO_POWER, IGRAPH_PAGERANK_ALGO_ARPACK, IGRAPH_PAGERANK_ALGO_PRPACK.

vector:

Pointer to an initialized vector, the result is stored here. It is resized as needed.

value:

Pointer to a real variable, the eigenvalue corresponding to the PageRank vector is stored here. It should be always exactly one.

vids:

The vertex ids for which the PageRank is returned.

directed:

Boolean, whether to consider the directedness of the edges. This is ignored for undirected graphs.

damping:

The damping factor ("d" in the original paper)

weights:

Optional edge weights, it is either a null pointer, then the edges are not weighted, or a vector of the same length as the number of edges.

options:

Options to the power method or ARPACK. For the power method, IGRAPH_PAGERANK_ALGO_POWER it must be a pointer to a igraph_pagerank_power_options_t object. For IGRAPH_PAGERANK_ALGO_ARPACK it must be a pointer to an igraph_arpack_options_t object. See igraph_arpack_options_t for details. Note that the function overwrites the n (number of vertices), nev (1), ncv (3) and which (LM) parameters and it always starts the calculation from a non-random vector calculated based on the degree of the vertices.

Returns: 

Error code: IGRAPH_ENOMEM, not enough memory for temporary data. IGRAPH_EINVVID, invalid vertex id in vids.

Time complexity: depends on the input graph, usually it is O(|E|), the number of edges.

See also: 

igraph_pagerank_old() for the old implementation, igraph_personalized_pagerank() and igraph_personalized_pagerank_vs() for the personalized PageRank measure, igraph_arpack_rssolve() and igraph_arpack_rnsolve() for the underlying machinery.

Example 13.15.  File examples/simple/igraph_pagerank.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>
#include <unistd.h>
#include <libgen.h>

void warning_handler_stdout (const char *reason, const char *file,
			     int line, int igraph_errno) {
  IGRAPH_UNUSED(igraph_errno);
  printf("Warning: %s\n", reason);
}

void print_vector(igraph_vector_t *v, FILE *f) {
  long int i;
  for (i=0; i<igraph_vector_size(v); i++) {
    fprintf(f, " %4.2f", VECTOR(*v)[i]);
  }
  fprintf(f, "\n");
}

igraph_warning_handler_t *oldwarn;

int main() {

  igraph_t g;
  igraph_vector_t v, res, reset, weights;
  igraph_arpack_options_t arpack_options;
  igraph_real_t value;
  int ret;
  igraph_pagerank_power_options_t power_options;

  /* Test graphs taken from http://www.iprcom.com/papers/pagerank/ */
  igraph_vector_init(&v, 10);
  VECTOR(v)[0]=0; VECTOR(v)[1]=1;
  VECTOR(v)[2]=1; VECTOR(v)[3]=2;
  VECTOR(v)[4]=2; VECTOR(v)[5]=0;
  VECTOR(v)[6]=3; VECTOR(v)[7]=2;
  VECTOR(v)[8]=0; VECTOR(v)[9]=2;
  igraph_create(&g, &v, 0, 1);

  igraph_vector_init(&res, 0);
  oldwarn=igraph_set_warning_handler(warning_handler_stdout);
  igraph_pagerank_old(&g, &res, igraph_vss_all(), 1, 1000, 0.001, 0.85, 0);
  print_vector(&res, stdout);
  igraph_vector_destroy(&res);
  igraph_vector_destroy(&v);
  
  igraph_destroy(&g);

  igraph_vector_init(&v, 28);
  VECTOR(v)[ 0]=0; VECTOR(v)[ 1]=1;
  VECTOR(v)[ 2]=0; VECTOR(v)[ 3]=2;
  VECTOR(v)[ 4]=0; VECTOR(v)[ 5]=3;
  VECTOR(v)[ 6]=1; VECTOR(v)[ 7]=0;
  VECTOR(v)[ 8]=2; VECTOR(v)[ 9]=0;
  VECTOR(v)[10]=3; VECTOR(v)[11]=0;
  VECTOR(v)[12]=3; VECTOR(v)[13]=4;
  VECTOR(v)[14]=3; VECTOR(v)[15]=5;
  VECTOR(v)[16]=3; VECTOR(v)[17]=6;
  VECTOR(v)[18]=3; VECTOR(v)[19]=7;
  VECTOR(v)[20]=4; VECTOR(v)[21]=0;
  VECTOR(v)[22]=5; VECTOR(v)[23]=0;
  VECTOR(v)[24]=6; VECTOR(v)[25]=0;
  VECTOR(v)[26]=7; VECTOR(v)[27]=0;
  igraph_create(&g, &v, 0, 1);

  igraph_vector_init(&res, 0);
  igraph_pagerank_old(&g, &res, igraph_vss_all(), 1, 10000, 0.0001, 0.85, 0);
  print_vector(&res, stdout);
  igraph_vector_destroy(&res);
  igraph_vector_destroy(&v);
  igraph_destroy(&g);

  igraph_set_warning_handler(oldwarn);

  /* New PageRank */
  igraph_star(&g, 11, IGRAPH_STAR_UNDIRECTED, 0);
  igraph_vector_init(&res, 0);
  igraph_arpack_options_init(&arpack_options);
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, 0,
		  igraph_vss_all(), 0, 0.85, 0, &arpack_options);
  print_vector(&res, stdout);
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, 0,
		  igraph_vss_all(), 0, 0.85, 0, 0);
  print_vector(&res, stdout);
  /* Check twice more for consistency */
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, 0,
		  igraph_vss_all(), 0, 0.85, 0, &arpack_options);
  print_vector(&res, stdout);
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, 0,
		  igraph_vss_all(), 0, 0.85, 0, 0);
  print_vector(&res, stdout);

  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, 0,
		  igraph_vss_all(), 0, 0.85, 0, &arpack_options);
  print_vector(&res, stdout);
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, 0,
		  igraph_vss_all(), 0, 0.85, 0, 0);
  print_vector(&res, stdout);

  /* Check personalized PageRank */
  igraph_personalized_pagerank_vs(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, 0,
				  igraph_vss_all(), 0, 0.5,
				  igraph_vss_1(1), 0, &arpack_options);
  print_vector(&res, stdout);
  igraph_personalized_pagerank_vs(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, 0,
				  igraph_vss_all(), 0, 0.5,
				  igraph_vss_1(1), 0, 0);
  print_vector(&res, stdout);

  /* Errors */
  power_options.niter = -1; power_options.eps=0.0001;
  igraph_set_error_handler(igraph_error_handler_ignore);
  igraph_set_warning_handler(igraph_warning_handler_ignore);
  ret=igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_POWER, &res,
		      /*value=*/ 0, igraph_vss_all(), 1, 0.85,
		      /*weights=*/ 0, &power_options);
  if (ret != IGRAPH_EINVAL) {
    return 1;
  }
  
  power_options.niter=10000; power_options.eps=-1;
  ret=igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_POWER, &res,
		      /*value=*/ 0, igraph_vss_all(), 1, 0.85,
		      /*weights=*/ 0, &power_options);
  if (ret != IGRAPH_EINVAL) {
    return 2;
  }

  power_options.niter=10000; power_options.eps=0.0001;
  ret=igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_POWER, &res,
		      /*value=*/ 0, igraph_vss_all(), 1, 1.2,
		      /*weights=*/ 0, &power_options);
  if (ret != IGRAPH_EINVAL) {
    return 3;
  }

  igraph_vector_init(&reset, 2);
  ret=igraph_personalized_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, 0,
				   igraph_vss_all(), 0, 0.85, &reset, 0,
				   &arpack_options);
  if (ret != IGRAPH_EINVAL) {
    return 4;
  }
  ret=igraph_personalized_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, 0,
				   igraph_vss_all(), 0, 0.85, &reset, 0, 0);
  if (ret != IGRAPH_EINVAL) {
    return 4;
  }
  igraph_vector_resize(&reset, 10);
  igraph_vector_fill(&reset, 0);
  ret=igraph_personalized_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK,
				   &res, 0, igraph_vss_all(), 0, 0.85,
				   &reset, 0, &arpack_options);
  if (ret != IGRAPH_EINVAL) {
    return 5;
  }
  ret=igraph_personalized_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK,
				   &res, 0, igraph_vss_all(), 0, 0.85,
				   &reset, 0, 0);
  if (ret != IGRAPH_EINVAL) {
    return 5;
  }
  igraph_vector_destroy(&reset);
  igraph_destroy(&g);
  igraph_set_error_handler(igraph_error_handler_abort);

  /* Special cases: check for empty graph */
  igraph_empty(&g, 10, 0);
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, &value,
		  igraph_vss_all(), 1, 0.85, 0, &arpack_options);
  if (value != 1.0) {
    return 6;
  }
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, &value,
		  igraph_vss_all(), 1, 0.85, 0, 0);
  if (value != 1.0) {
    return 6;
  }
  print_vector(&res, stdout);
  igraph_destroy(&g);

  /* Special cases: check for full graph, zero weights */
  igraph_full(&g, 10, 0, 0);
  igraph_vector_init(&v, 45);
  igraph_vector_fill(&v, 0);
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, &value,
		  igraph_vss_all(), 1, 0.85, &v, &arpack_options);
  if (value != 1.0) {
    return 7;
  }
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, &value,
		  igraph_vss_all(), 1, 0.85, &v, 0);
  if (value != 1.0) {
    return 7;
  }
  igraph_vector_destroy(&v);
  print_vector(&res, stdout);
  igraph_destroy(&g);

  /* Another test case for PageRank (bug #792352) */
  igraph_small(&g, 9, 1, 0, 5, 1, 5, 2, 0, 3, 1, 5, 4, 5, 7, 6, 0, 8, 0, 8, 1, -1);
  igraph_vector_init(&weights, 9);
  VECTOR(weights)[0] = 4; VECTOR(weights)[1] = 5; VECTOR(weights)[2] = 5;
  VECTOR(weights)[3] = 4; VECTOR(weights)[4] = 4; VECTOR(weights)[5] = 4;
  VECTOR(weights)[6] = 3; VECTOR(weights)[7] = 4; VECTOR(weights)[8] = 4;
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_ARPACK, &res, 0,
		  igraph_vss_all(), 1, 0.85, &weights, &arpack_options);
  print_vector(&res, stdout);
  igraph_pagerank(&g, IGRAPH_PAGERANK_ALGO_PRPACK, &res, 0,
		  igraph_vss_all(), 1, 0.85, &weights, 0);
  print_vector(&res, stdout);
  igraph_vector_destroy(&weights);
  igraph_destroy(&g);

  igraph_vector_destroy(&res);
  return 0;
}


6.7. igraph_pagerank_old — Calculates the Google PageRank for the specified vertices.

int igraph_pagerank_old(const igraph_t *graph, igraph_vector_t *res, 
			const igraph_vs_t vids, igraph_bool_t directed,
			igraph_integer_t niter, igraph_real_t eps, 
			igraph_real_t damping, igraph_bool_t old);

This is an old implementation, it is provided for compatibility with igraph versions earlier than 0.5. Please use the new implementation igraph_pagerank() in new projects.

From version 0.7 this function is deprecated and its use gives a warning message.

Please note that the PageRank of a given vertex depends on the PageRank of all other vertices, so even if you want to calculate the PageRank for only some of the vertices, all of them must be calculated. Requesting the PageRank for only some of the vertices does not result in any performance increase at all.

Since the calculation is an iterative process, the algorithm is stopped after a given count of iterations or if the PageRank value differences between iterations are less than a predefined value.

For the explanation of the PageRank algorithm, see the following webpage: http://infolab.stanford.edu/~backrub/google.html , or the following reference:

Sergey Brin and Larry Page: The Anatomy of a Large-Scale Hypertextual Web Search Engine. Proceedings of the 7th World-Wide Web Conference, Brisbane, Australia, April 1998.

Arguments: 

graph:

The graph object.

res:

The result vector containing the PageRank values for the given nodes.

vids:

Vector with the vertex ids

directed:

Logical, if true directed paths will be considered for directed graphs. It is ignored for undirected graphs.

niter:

The maximum number of iterations to perform

eps:

The algorithm will consider the calculation as complete if the difference of PageRank values between iterations change less than this value for every node

damping:

The damping factor ("d" in the original paper)

old:

Boolean, whether to use the pre-igraph 0.5 way to calculate page rank. Not recommended for new applications, only included for compatibility. If this is non-zero then the damping factor is not divided by the number of vertices before adding it to the weighted page rank scores to calculate the new scores. I.e. the formula in the original PageRank paper is used. Furthermore, if this is non-zero then the PageRank vector is renormalized after each iteration.

Returns: 

Error code: IGRAPH_ENOMEM, not enough memory for temporary data. IGRAPH_EINVVID, invalid vertex id in vids.

Time complexity: O(|V|+|E|) per iteration. A handful iterations should be enough. Note that if the old-style dumping is used then the iteration might not converge at all.

See also: 

igraph_pagerank() for the new implementation.

6.8. igraph_personalized_pagerank — Calculates the personalized Google PageRank for the specified vertices.

int igraph_personalized_pagerank(const igraph_t *graph, 
		    igraph_pagerank_algo_t algo, igraph_vector_t *vector,
		    igraph_real_t *value, const igraph_vs_t vids,
		    igraph_bool_t directed, igraph_real_t damping, 
		    igraph_vector_t *reset,
		    const igraph_vector_t *weights,
		    void *options);

The personalized PageRank is similar to the original PageRank measure, but the random walk is reset in every step with probability 1-damping to a non-uniform distribution (instead of the uniform distribution in the original PageRank measure.

Please note that the personalized PageRank of a given vertex depends on the personalized PageRank of all other vertices, so even if you want to calculate the personalized PageRank for only some of the vertices, all of them must be calculated. Requesting the personalized PageRank for only some of the vertices does not result in any performance increase at all.

Arguments: 

graph:

The graph object.

algo:

The PageRank implementation to use. Possible values: IGRAPH_PAGERANK_ALGO_POWER, IGRAPH_PAGERANK_ALGO_ARPACK, IGRAPH_PAGERANK_ALGO_PRPACK.

vector:

Pointer to an initialized vector, the result is stored here. It is resized as needed.

value:

Pointer to a real variable, the eigenvalue corresponding to the PageRank vector is stored here. It should be always exactly one.

vids:

The vertex ids for which the PageRank is returned.

directed:

Boolean, whether to consider the directedness of the edges. This is ignored for undirected graphs.

damping:

The damping factor ("d" in the original paper)

reset:

The probability distribution over the vertices used when resetting the random walk. It is either a null pointer (denoting a uniform choice that results in the original PageRank measure) or a vector of the same length as the number of vertices.

weights:

Optional edge weights, it is either a null pointer, then the edges are not weighted, or a vector of the same length as the number of edges.

options:

Options to the power method or ARPACK. For the power method, IGRAPH_PAGERANK_ALGO_POWER it must be a pointer to a igraph_pagerank_power_options_t object. For IGRAPH_PAGERANK_ALGO_ARPACK it must be a pointer to an igraph_arpack_options_t object. See igraph_arpack_options_t for details. Note that the function overwrites the n (number of vertices), nev (1), ncv (3) and which (LM) parameters and it always starts the calculation from a non-random vector calculated based on the degree of the vertices.

Returns: 

Error code: IGRAPH_ENOMEM, not enough memory for temporary data. IGRAPH_EINVVID, invalid vertex id in vids or an invalid reset vector in reset.

Time complexity: depends on the input graph, usually it is O(|E|), the number of edges.

See also: 

igraph_pagerank() for the non-personalized implementation, igraph_arpack_rssolve() and igraph_arpack_rnsolve() for the underlying machinery.

6.9. igraph_personalized_pagerank_vs — Calculates the personalized Google PageRank for the specified vertices.

int igraph_personalized_pagerank_vs(const igraph_t *graph, 
		    igraph_pagerank_algo_t algo, igraph_vector_t *vector,
		    igraph_real_t *value, const igraph_vs_t vids,
		    igraph_bool_t directed, igraph_real_t damping, 
		    igraph_vs_t reset_vids,
		    const igraph_vector_t *weights,
		    void *options);

The personalized PageRank is similar to the original PageRank measure, but the random walk is reset in every step with probability 1-damping to a non-uniform distribution (instead of the uniform distribution in the original PageRank measure.

This simplified interface takes a vertex sequence and resets the random walk to one of the vertices in the specified vertex sequence, chosen uniformly. A typical application of personalized PageRank is when the random walk is reset to the same vertex every time - this can easily be achieved using igraph_vss_1() which generates a vertex sequence containing only a single vertex.

Please note that the personalized PageRank of a given vertex depends on the personalized PageRank of all other vertices, so even if you want to calculate the personalized PageRank for only some of the vertices, all of them must be calculated. Requesting the personalized PageRank for only some of the vertices does not result in any performance increase at all.

Arguments: 

graph:

The graph object.

algo:

The PageRank implementation to use. Possible values: IGRAPH_PAGERANK_ALGO_POWER, IGRAPH_PAGERANK_ALGO_ARPACK, IGRAPH_PAGERANK_ALGO_PRPACK.

vector:

Pointer to an initialized vector, the result is stored here. It is resized as needed.

value:

Pointer to a real variable, the eigenvalue corresponding to the PageRank vector is stored here. It should be always exactly one.

vids:

The vertex ids for which the PageRank is returned.

directed:

Boolean, whether to consider the directedness of the edges. This is ignored for undirected graphs.

damping:

The damping factor ("d" in the original paper)

reset_vids:

IDs of the vertices used when resetting the random walk.

weights:

Optional edge weights, it is either a null pointer, then the edges are not weighted, or a vector of the same length as the number of edges.

options:

Options to the power method or ARPACK. For the power method, IGRAPH_PAGERANK_ALGO_POWER it must be a pointer to a igraph_pagerank_power_options_t object. For IGRAPH_PAGERANK_ALGO_ARPACK it must be a pointer to an igraph_arpack_options_t object. See igraph_arpack_options_t for details. Note that the function overwrites the n (number of vertices), nev (1), ncv (3) and which (LM) parameters and it always starts the calculation from a non-random vector calculated based on the degree of the vertices.

Returns: 

Error code: IGRAPH_ENOMEM, not enough memory for temporary data. IGRAPH_EINVVID, invalid vertex id in vids or an empty reset vertex sequence in vids_reset.

Time complexity: depends on the input graph, usually it is O(|E|), the number of edges.

See also: 

igraph_pagerank() for the non-personalized implementation, igraph_arpack_rssolve() and igraph_arpack_rnsolve() for the underlying machinery.

6.10. igraph_constraint — Burt's constraint scores.

int igraph_constraint(const igraph_t *graph, igraph_vector_t *res,
		      igraph_vs_t vids, const igraph_vector_t *weights);

This function calculates Burt's constraint scores for the given vertices, also known as structural holes.

Burt's constraint is higher if ego has less, or mutually stronger related (i.e. more redundant) contacts. Burt's measure of constraint, C[i], of vertex i's ego network V[i], is defined for directed and valued graphs,

C[i] = sum( sum( (p[i,q] p[q,j])^2, q in V[i], q != i,j ), j in V[], j != i)

for a graph of order (ie. number of vertices) N, where proportional tie strengths are defined as

p[i,j]=(a[i,j]+a[j,i]) / sum(a[i,k]+a[k,i], k in V[i], k != i),

a[i,j] are elements of A and the latter being the graph adjacency matrix. For isolated vertices, constraint is undefined.

Burt, R.S. (2004). Structural holes and good ideas. American Journal of Sociology 110, 349-399.

The first R version of this function was contributed by Jeroen Bruggeman.

Arguments: 

graph:

A graph object.

res:

Pointer to an initialized vector, the result will be stored here. The vector will be resized to have the appropriate size for holding the result.

vids:

Vertex selector containing the vertices for which the constraint should be calculated.

weights:

Vector giving the weights of the edges. If it is NULL then each edge is supposed to have the same weight.

Returns: 

Error code.

Time complexity: O(|V|+E|+n*d^2), n is the number of vertices for which the constraint is calculated and d is the average degree, |V| is the number of vertices, |E| the number of edges in the graph. If the weights argument is NULL then the time complexity is O(|V|+n*d^2).

6.11. igraph_maxdegree — Calculate the maximum degree in a graph (or set of vertices).

int igraph_maxdegree(const igraph_t *graph, igraph_integer_t *res,
		     igraph_vs_t vids, igraph_neimode_t mode, 
		     igraph_bool_t loops);

The largest in-, out- or total degree of the specified vertices is calculated.

Arguments: 

graph:

The input graph.

res:

Pointer to an integer (igraph_integer_t), the result will be stored here.

vids:

Vector giving the vertex IDs for which the maximum degree will be calculated.

mode:

Defines the type of the degree. IGRAPH_OUT, out-degree, IGRAPH_IN, in-degree, IGRAPH_ALL, total degree (sum of the in- and out-degree). This parameter is ignored for undirected graphs.

loops:

Boolean, gives whether the self-loops should be counted.

Returns: 

Error code: IGRAPH_EINVVID: invalid vertex id. IGRAPH_EINVMODE: invalid mode argument.

Time complexity: O(v) if loops is TRUE, and O(v*d) otherwise. v is the number vertices for which the degree will be calculated, and d is their (average) degree.

6.12. igraph_strength — Strength of the vertices, weighted vertex degree in other words.

int igraph_strength(const igraph_t *graph, igraph_vector_t *res,
		    const igraph_vs_t vids, igraph_neimode_t mode,
		    igraph_bool_t loops, const igraph_vector_t *weights);

In a weighted network the strength of a vertex is the sum of the weights of all incident edges. In a non-weighted network this is exactly the vertex degree.

Arguments: 

graph:

The input graph.

res:

Pointer to an initialized vector, the result is stored here. It will be resized as needed.

vids:

The vertices for which the calculation is performed.

mode:

Gives whether to count only outgoing (IGRAPH_OUT), incoming (IGRAPH_IN) edges or both (IGRAPH_ALL).

loops:

A logical scalar, whether to count loop edges as well.

weights:

A vector giving the edge weights. If this is a NULL pointer, then igraph_degree() is called to perform the calculation.

Returns: 

Error code.

Time complexity: O(|V|+|E|), linear in the number vertices and edges.

See also: 

igraph_degree() for the traditional, non-weighted version.

6.13. igraph_eigenvector_centrality — Eigenvector centrality of the vertices

int igraph_eigenvector_centrality(const igraph_t *graph, 
				  igraph_vector_t *vector,
				  igraph_real_t *value, 
				  igraph_bool_t directed, igraph_bool_t scale,
				  const igraph_vector_t *weights,
				  igraph_arpack_options_t *options);

Eigenvector centrality is a measure of the importance of a node in a network. It assigns relative scores to all nodes in the network based on the principle that connections to high-scoring nodes contribute more to the score of the node in question than equal connections to low-scoring nodes. In practice, this is determined by calculating the eigenvector corresponding to the largest positive eigenvalue of the adjacency matrix. The centrality scores returned by igraph are always normalized such that the largest eigenvector centrality score is one (with one exception, see below).

Since the eigenvector centrality scores of nodes in different components do not affect each other, it may be beneficial for large graphs to decompose it first into weakly connected components and calculate the centrality scores individually for each component.

Also note that the adjacency matrix of a directed acyclic graph or the adjacency matrix of an empty graph does not possess positive eigenvalues, therefore the eigenvector centrality is not defined for these graphs. igraph will return an eigenvalue of zero in such cases. The eigenvector centralities will all be equal for an empty graph and will all be zeros for a directed acyclic graph. Such pathological cases can be detected by asking igraph to calculate the eigenvalue as well (using the value parameter, see below) and checking whether the eigenvalue is very close to zero.

Arguments: 

graph:

The input graph. It might be directed.

vector:

Pointer to an initialized vector, it will be resized as needed. The result of the computation is stored here. It can be a null pointer, then it is ignored.

value:

If not a null pointer, then the eigenvalue corresponding to the found eigenvector is stored here.

directed:

Boolean scalar, whether to consider edge directions in a directed graph. It is ignored for undirected graphs.

scale:

If not zero then the result will be scaled such that the absolute value of the maximum centrality is one.

weights:

A null pointer (=no edge weights), or a vector giving the weights of the edges. The algorithm might result complex numbers is some weights are negative. In this case only the real part is reported.

options:

Options to ARPACK. See igraph_arpack_options_t for details. Note that the function overwrites the n (number of vertices) parameter and it always starts the calculation from a non-random vector calculated based on the degree of the vertices.

Returns: 

Error code.

Time complexity: depends on the input graph, usually it is O(|V|+|E|).

See also: 

igraph_pagerank and igraph_personalized_pagerank for modifications of eigenvector centrality.

Example 13.16.  File examples/simple/eigenvector_centrality.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2007-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.h"

#include <math.h>

int main() {
  
  igraph_t g;
  igraph_vector_t v, weights;
  long int i;
  igraph_real_t value;
  igraph_arpack_options_t options;
  
  igraph_star(&g, 100, IGRAPH_STAR_UNDIRECTED, 0);

  igraph_arpack_options_init(&options);
  igraph_vector_init(&v, 0);
  igraph_eigenvector_centrality(&g, &v, &value, /*directed=*/ 0, 
				/*scale=*/0, /*weights=*/0, 
				&options);

  if (options.info != 0) {
    return 1;
  }

  for (i=0; i<igraph_vector_size(&v); i++) {
    printf(" %.3f", fabs(VECTOR(v)[i]));
  }
  printf("\n");
  
  igraph_destroy(&g);

  /* Special cases: check for empty graph */
  igraph_empty(&g, 10, 0);
  igraph_eigenvector_centrality(&g, &v, &value, 0, 0, 0, &options);
  if (value != 0.0) {
    return 1;
  }
  for (i=0; i<igraph_vector_size(&v); i++) {
    printf(" %.2f", fabs(VECTOR(v)[i]));
  }
  printf("\n");
  igraph_destroy(&g);

  /* Special cases: check for full graph, zero weights */
  igraph_full(&g, 10, 0, 0);
  igraph_vector_init(&weights, 45);
  igraph_vector_fill(&weights, 0);
  igraph_eigenvector_centrality(&g, &v, &value, 0, 0, &weights, &options);
  igraph_vector_destroy(&weights);
  if (value != 0.0) {
    return 2;
  }
  for (i=0; i<igraph_vector_size(&v); i++) {
    printf(" %.2f", fabs(VECTOR(v)[i]));
  }
  printf("\n");
  igraph_destroy(&g);

  igraph_vector_destroy(&v);

  return 0;
}


6.14. igraph_hub_score — Kleinberg's hub scores

int igraph_hub_score(const igraph_t *graph, igraph_vector_t *vector,
		     igraph_real_t *value, igraph_bool_t scale,
			 const igraph_vector_t *weights,
		     igraph_arpack_options_t *options);

The hub scores of the vertices are defined as the principal eigenvector of A*A^T , where A is the adjacency matrix of the graph, A^T is its transposed.

See the following reference on the meaning of this score: J. Kleinberg. Authoritative sources in a hyperlinked environment. Proc. 9th ACM-SIAM Symposium on Discrete Algorithms, 1998. Extended version in Journal of the ACM 46(1999). Also appears as IBM Research Report RJ 10076, May 1997.

Arguments: 

graph:

The input graph. Can be directed and undirected.

vector:

Pointer to an initialized vector, the result is stored here. If a null pointer then it is ignored.

value:

If not a null pointer then the eigenvalue corresponding to the calculated eigenvector is stored here.

scale:

If not zero then the result will be scaled such that the absolute value of the maximum centrality is one.

weights:

A null pointer (=no edge weights), or a vector giving the weights of the edges.

options:

Options to ARPACK. See igraph_arpack_options_t for details. Note that the function overwrites the n (number of vertices) parameter and it always starts the calculation from a non-random vector calculated based on the degree of the vertices.

Returns: 

Error code.

Time complexity: depends on the input graph, usually it is O(|V|), the number of vertices.

See also: 

6.15. igraph_authority_score — Kleinerg's authority scores

int igraph_authority_score(const igraph_t *graph, igraph_vector_t *vector,
			   igraph_real_t *value, igraph_bool_t scale,
			   const igraph_vector_t *weights,
			   igraph_arpack_options_t *options);

The authority scores of the vertices are defined as the principal eigenvector of A^T*A , where A is the adjacency matrix of the graph, A^T is its transposed.

See the following reference on the meaning of this score: J. Kleinberg. Authoritative sources in a hyperlinked environment. Proc. 9th ACM-SIAM Symposium on Discrete Algorithms, 1998. Extended version in Journal of the ACM 46(1999). Also appears as IBM Research Report RJ 10076, May 1997.

Arguments: 

graph:

The input graph. Can be directed and undirected.

vector:

Pointer to an initialized vector, the result is stored here. If a null pointer then it is ignored.

value:

If not a null pointer then the eigenvalue corresponding to the calculated eigenvector is stored here.

scale:

If not zero then the result will be scaled such that the absolute value of the maximum centrality is one.

weights:

A null pointer (=no edge weights), or a vector giving the weights of the edges.

options:

Options to ARPACK. See igraph_arpack_options_t for details. Note that the function overwrites the n (number of vertices) parameter and it always starts the calculation from a non-random vector calculated based on the degree of the vertices.

Returns: 

Error code.

Time complexity: depends on the input graph, usually it is O(|V|), the number of vertices.

See also: 

7. Estimating Centrality Measures

7.1. igraph_closeness_estimate — Closeness centrality estimations for some vertices.

int igraph_closeness_estimate(const igraph_t *graph, igraph_vector_t *res, 
		              const igraph_vs_t vids, igraph_neimode_t mode,
                              igraph_real_t cutoff,
			      const igraph_vector_t *weights,
			      igraph_bool_t normalized);

The closeness centrality of a vertex measures how easily other vertices can be reached from it (or the other way: how easily it can be reached from the other vertices). It is defined as the number of the number of vertices minus one divided by the sum of the lengths of all geodesics from/to the given vertex. When estimating closeness centrality, igraph considers paths having a length less than or equal to a prescribed cutoff value.

If the graph is not connected, and there is no such path between two vertices, the number of vertices is used instead the length of the geodesic. This is always longer than the longest possible geodesic.

Since the estimation considers vertex pairs with a distance greater than the given value as disconnected, the resulting estimation will always be lower than the actual closeness centrality.

Arguments: 

graph:

The graph object.

res:

The result of the computation, a vector containing the closeness centrality scores for the given vertices.

vids:

Vector giving the vertices for which the closeness centrality scores will be computed.

mode:

The type of shortest paths to be used for the calculation in directed graphs. Possible values:

IGRAPH_OUT

the lengths of the outgoing paths are calculated.

IGRAPH_IN

the lengths of the incoming paths are calculated.

IGRAPH_ALL

the directed graph is considered as an undirected one for the computation.

cutoff:

The maximal length of paths that will be considered. If zero or negative, the exact closeness will be calculated (no upper limit on path lengths).

weights:

An optional vector containing edge weights for weighted closeness. Supply a null pointer here for traditional, unweighted closeness.

normalized:

Boolean, whether to normalize results by multiplying by the number of vertices minus one.

Returns: 

Error code:

IGRAPH_ENOMEM

not enough memory for temporary data.

IGRAPH_EINVVID

invalid vertex id passed.

IGRAPH_EINVMODE

invalid mode argument.

Time complexity: O(n|E|), n is the number of vertices for which the calculation is done and |E| is the number of edges in the graph.

See also: 

Other centrality types: igraph_degree(), igraph_betweenness().

7.2. igraph_betweenness_estimate — Estimated betweenness centrality of some vertices.

int igraph_betweenness_estimate(const igraph_t *graph, igraph_vector_t *res, 
				const igraph_vs_t vids, igraph_bool_t directed,
				igraph_real_t cutoff, 
				const igraph_vector_t *weights, 
				igraph_bool_t nobigint);

The betweenness centrality of a vertex is the number of geodesics going through it. If there are more than one geodesic between two vertices, the value of these geodesics are weighted by one over the number of geodesics. When estimating betweenness centrality, igraph takes into consideration only those paths that are shorter than or equal to a prescribed length. Note that the estimated centrality will always be less than the real one.

Arguments: 

graph:

The graph object.

res:

The result of the computation, a vector containing the estimated betweenness scores for the specified vertices.

vids:

The vertices of which the betweenness centrality scores will be estimated.

directed:

Logical, if true directed paths will be considered for directed graphs. It is ignored for undirected graphs.

cutoff:

The maximal length of paths that will be considered. If zero or negative, the exact betweenness will be calculated (no upper limit on path lengths).

weights:

An optional vector containing edge weights for calculating weighted betweenness. Supply a null pointer here for unweighted betweenness.

nobigint:

Logical, if true, then we don't use big integers for the calculation, setting this to 1 (=true) should work for most graphs. It is currently ignored for weighted graphs.

Returns: 

Error code: IGRAPH_ENOMEM, not enough memory for temporary data. IGRAPH_EINVVID, invalid vertex id passed in vids.

Time complexity: O(|V||E|), |V| and |E| are the number of vertices and edges in the graph. Note that the time complexity is independent of the number of vertices for which the score is calculated.

See also: 

Other centrality types: igraph_degree(), igraph_closeness(). See igraph_edge_betweenness() for calculating the betweenness score of the edges in a graph.

7.3. igraph_edge_betweenness_estimate — Estimated betweenness centrality of the edges.

int igraph_edge_betweenness_estimate(const igraph_t *graph, igraph_vector_t *result,
                                     igraph_bool_t directed, igraph_real_t cutoff,
				     const igraph_vector_t *weights);

The betweenness centrality of an edge is the number of geodesics going through it. If there are more than one geodesics between two vertices, the value of these geodesics are weighted by one over the number of geodesics. When estimating betweenness centrality, igraph takes into consideration only those paths that are shorter than or equal to a prescribed length. Note that the estimated centrality will always be less than the real one.

Arguments: 

graph:

The graph object.

result:

The result of the computation, vector containing the betweenness scores for the edges.

directed:

Logical, if true directed paths will be considered for directed graphs. It is ignored for undirected graphs.

cutoff:

The maximal length of paths that will be considered. If zero or negative, the exact betweenness will be calculated (no upper limit on path lengths).

weights:

An optional weight vector for weighted betweenness. Supply a null pointer here for unweighted betweenness.

Returns: 

Error code: IGRAPH_ENOMEM, not enough memory for temporary data.

Time complexity: O(|V||E|), |V| and |E| are the number of vertices and edges in the graph.

See also: 

Other centrality types: igraph_degree(), igraph_closeness(). See igraph_betweenness() for calculating the betweenness score of the vertices in a graph.

8. Centralization

8.1. igraph_centralization — Calculate the centralization score from the node level scores

igraph_real_t igraph_centralization(const igraph_vector_t *scores,
				    igraph_real_t theoretical_max,
				    igraph_bool_t normalized);

For a centrality score defined on the vertices of a graph, it is possible to define a graph level centralization index, by calculating the sum of the deviation from the maximum centrality score. Consequently, the higher the centralization index of the graph, the more centralized the structure is.

In order to make graphs of different sizes comparable, the centralization index is usually normalized to a number between zero and one, by dividing the (unnormalized) centralization score of the most centralized structure with the same number of vertices.

For most centrality indices the most centralized structure is the star graph, a single center connected to all other nodes in the network. There are some variation depending on whether the graph is directed or not, whether loop edges are allowed, etc.

This function simply calculates the graph level index, if the node level scores and the theoretical maximum are given. It is called by all the measure-specific centralization functions.

Arguments: 

scores:

A vector containing the node-level centrality scores.

theoretical_max:

The graph level centrality score of the most centralized graph with the same number of vertices. Only used if normalized set to true.

normalized:

Boolean, whether to normalize the centralization by dividing the supplied theoretical maximum.

Returns: 

The graph level index.

See also: 

Time complexity: O(n), the length of the score vector.

Example 13.17.  File examples/simple/centralization.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2009-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.h>
#include <math.h>

#define ALMOST_EQUALS(a, b) (fabs((a)-(b)) < 1e-8)

int main() {

  igraph_t g;
  igraph_real_t cent;
  igraph_arpack_options_t arpack_options;

  /****************************/
  /* in-star */
  igraph_star(&g, 10, IGRAPH_STAR_IN, /*center=*/ 0);
  
  igraph_centralization_degree(&g, /*res=*/ 0,
			       /*mode=*/ IGRAPH_IN, IGRAPH_NO_LOOPS,
			       &cent, /*theoretical_max=*/ 0, 
			       /*normalized=*/ 1);
  if (cent != 1.0) { 
    fprintf(stderr, "in-star, degree: %g\n", cent); 
    return 1; 
  }

  igraph_centralization_betweenness(&g, /*res=*/ 0,
				    IGRAPH_UNDIRECTED, /*nobigint=*/ 1, &cent, 
				    /*theoretical_max=*/ 0,
				    /*normalized=*/ 1);
  if (cent != 1.0) { 
    fprintf(stderr, "in-star, betweenness: %g\n", cent); 
    return 2; 
  }

  igraph_centralization_closeness(&g, /*res=*/ 0,
				  IGRAPH_IN, &cent, 
				  /*theoretical_max=*/ 0,
				  /*normalization=*/ 1);
  
  if (!ALMOST_EQUALS(cent, 1.0)) {
    fprintf(stderr, "in-star, closeness: %g\n", cent);
    return 3;
  }

  igraph_destroy(&g);
  
  /****************************/
  /* out-star */
  igraph_star(&g, 10, IGRAPH_STAR_OUT, /*center=*/ 0);
  
  igraph_centralization_degree(&g, /*res=*/ 0,
			       /*mode=*/ IGRAPH_OUT, IGRAPH_NO_LOOPS,
			       &cent, /*theoretical_max=*/ 0,
			       /*normalized=*/ 1);
  if (cent != 1.0) { 
    fprintf(stderr, "out-star, degree: %g\n", cent); 
    return 11; 
  }

  igraph_centralization_betweenness(&g, /*res=*/ 0,
				    IGRAPH_UNDIRECTED, /*nobigint=*/ 1, &cent,
				    /*theoretical_max=*/ 0,
				    /*normalized=*/ 1);
  if (cent != 1.0) { 
    fprintf(stderr, "out-star, betweenness: %g\n", cent); 
    return 12; 
  }

  igraph_centralization_closeness(&g, /*res=*/ 0,
				  IGRAPH_OUT, &cent, 
				  /*theoretical_max=*/ 0,
				  /*normalization=*/ 1);
  
  if (!ALMOST_EQUALS(cent, 1.0)) {
    fprintf(stderr, "out-star, closeness: %g\n", cent);
    return 13;
  }

  igraph_destroy(&g);
  
  /****************************/
  /* undricted star */
  igraph_star(&g, 10, IGRAPH_STAR_UNDIRECTED, /*center=*/ 0);
  
  igraph_centralization_degree(&g, /*res=*/ 0,
			       /*mode=*/ IGRAPH_ALL, IGRAPH_NO_LOOPS,
			       &cent, /*theoretical_max=*/ 0,
			       /*normalized=*/ 1);
  if (cent != 1.0) { 
    fprintf(stderr, "undirected star, degree: %g\n", cent); 
    return 21; 
  }

  igraph_centralization_betweenness(&g, /*res=*/ 0,
				    IGRAPH_UNDIRECTED, /*nobigint=*/ 1, &cent,
				    /*theoretical_max=*/ 0,
				    /*normalized=*/ 1);
  if (cent != 1.0) { 
    fprintf(stderr, "undirected star, betweenness: %g\n", cent); 
    return 22; 
  }

  igraph_centralization_closeness(&g, /*res=*/ 0,
				  IGRAPH_ALL, &cent, 
				  /*theoretical_max=*/ 0,
				  /*normalization=*/ 1);
  
  if (!ALMOST_EQUALS(cent, 1.0)) {
    fprintf(stderr, "undirected star, closeness: %g\n", cent);
    return 23;
  }
  
  igraph_destroy(&g);

  /****************************/
  /* single dyad */
  
  igraph_small(&g, /*n=*/ 10, /*directed=*/ 0, 
	       0,1, -1);
  
  igraph_arpack_options_init(&arpack_options);
  igraph_centralization_eigenvector_centrality(&g, /*vector=*/ 0,
					       /*value=*/ 0, 
					       /*directed=*/ 1,
					       /*scale=*/ 1,
					       &arpack_options, &cent,
					       /*theoretical_max=*/ 0,
					       /*normalization=*/ 1);
  
  if (!ALMOST_EQUALS(cent, 1.0)) {
    fprintf(stderr, "dyad, eigenvector centrality: %g\n", cent);
    return 24;
  }

  igraph_centralization_eigenvector_centrality(&g, /*vector=*/ 0,
					       /*value=*/ 0, 
					       /*directed=*/ 1,
					       /*scale=*/ 0,
					       &arpack_options, &cent,
					       /*theoretical_max=*/ 0,
					       /*normalization=*/ 1);
  
  if (!ALMOST_EQUALS(cent, 1.0)) {
    fprintf(stderr, "dyad, eigenvector centrality, not scaled: %g\n", cent);
    return 25;
  }
    
  igraph_destroy(&g);
  
  return 0;
}


8.2. igraph_centralization_degree — Calculate vertex degree and graph centralization

int igraph_centralization_degree(const igraph_t *graph, igraph_vector_t *res, 
				 igraph_neimode_t mode, igraph_bool_t loops,
				 igraph_real_t *centralization,
				 igraph_real_t *theoretical_max,
				 igraph_bool_t normalized);

This function calculates the degree of the vertices by passing its arguments to igraph_degree(); and it calculates the graph level centralization index based on the results by calling igraph_centralization().

Arguments: 

graph:

The input graph.

res:

A vector if you need the node-level degree scores, or a null pointer otherwise.

mode:

Constant the specifies the type of degree for directed graphs. Possible values: IGRAPH_IN, IGRAPH_OUT and IGRAPH_ALL. This argument is ignored for undirected graphs.

loops:

Boolean, whether to consider loop edges when calculating the degree (and the centralization).

centralization:

Pointer to a real number, the centralization score is placed here.

theoretical_max:

Pointer to real number or a null pointer. If not a null pointer, then the theoretical maximum graph centrality score for a graph with the same number vertices is stored here.

normalized:

Boolean, whether to calculate a normalized centralization score. See igraph_centralization() for how the normalization is done.

Returns: 

Error code.

See also: 

Time complexity: the complexity of igraph_degree() plus O(n), the number of vertices queried, for calculating the centralization score.

8.3. igraph_centralization_betweenness — Calculate vertex betweenness and graph centralization

int igraph_centralization_betweenness(const igraph_t *graph, 
				      igraph_vector_t *res,
				      igraph_bool_t directed,
				      igraph_bool_t nobigint,
				      igraph_real_t *centralization,
				      igraph_real_t *theoretical_max,
				      igraph_bool_t normalized);

This function calculates the betweenness centrality of the vertices by passing its arguments to igraph_betweenness(); and it calculates the graph level centralization index based on the results by calling igraph_centralization().

Arguments: 

graph:

The input graph.

res:

A vector if you need the node-level betweenness scores, or a null pointer otherwise.

directed:

Boolean, whether to consider directed paths when calculating betweenness.

nobigint:

Logical, if true, then we don't use big integers for the calculation, setting this to zero (=false) should work for most graphs. It is currently ignored for weighted graphs.

centralization:

Pointer to a real number, the centralization score is placed here.

theoretical_max:

Pointer to real number or a null pointer. If not a null pointer, then the theoretical maximum graph centrality score for a graph with the same number vertices is stored here.

normalized:

Boolean, whether to calculate a normalized centralization score. See igraph_centralization() for how the normalization is done.

Returns: 

Error code.

See also: 

Time complexity: the complexity of igraph_betweenness() plus O(n), the number of vertices queried, for calculating the centralization score.

8.4. igraph_centralization_closeness — Calculate vertex closeness and graph centralization

int igraph_centralization_closeness(const igraph_t *graph, 
				    igraph_vector_t *res, 
				    igraph_neimode_t mode, 
				    igraph_real_t *centralization,
				    igraph_real_t *theoretical_max,
				    igraph_bool_t normalized);

This function calculates the closeness centrality of the vertices by passing its arguments to igraph_closeness(); and it calculates the graph level centralization index based on the results by calling igraph_centralization().

Arguments: 

graph:

The input graph.

res:

A vector if you need the node-level closeness scores, or a null pointer otherwise.

mode:

Constant the specifies the type of closeness for directed graphs. Possible values: IGRAPH_IN, IGRAPH_OUT and IGRAPH_ALL. This argument is ignored for undirected graphs. See igraph_closeness() argument with the same name for more.

centralization:

Pointer to a real number, the centralization score is placed here.

theoretical_max:

Pointer to real number or a null pointer. If not a null pointer, then the theoretical maximum graph centrality score for a graph with the same number vertices is stored here.

normalized:

Boolean, whether to calculate a normalized centralization score. See igraph_centralization() for how the normalization is done.

Returns: 

Error code.

See also: 

Time complexity: the complexity of igraph_closeness() plus O(n), the number of vertices queried, for calculating the centralization score.

8.5. igraph_centralization_eigenvector_centrality — Calculate eigenvector centrality scores and graph centralization

int igraph_centralization_eigenvector_centrality(
					 const igraph_t *graph,
					 igraph_vector_t *vector,
					 igraph_real_t *value,
					 igraph_bool_t directed,
					 igraph_bool_t scale,
					 igraph_arpack_options_t *options,
					 igraph_real_t *centralization,
					 igraph_real_t *theoretical_max,
					 igraph_bool_t normalized);

This function calculates the eigenvector centrality of the vertices by passing its arguments to igraph_eigenvector_centrality); and it calculates the graph level centralization index based on the results by calling igraph_centralization().

Arguments: 

graph:

The input graph.

vector:

A vector if you need the node-level eigenvector centrality scores, or a null pointer otherwise.

value:

If not a null pointer, then the leading eigenvalue is stored here.

scale:

If not zero then the result will be scaled, such that the absolute value of the maximum centrality is one.

options:

Options to ARPACK. See igraph_arpack_options_t for details. Note that the function overwrites the n (number of vertices) parameter and it always starts the calculation from a non-random vector calculated based on the degree of the vertices.

centralization:

Pointer to a real number, the centralization score is placed here.

theoretical_max:

Pointer to real number or a null pointer. If not a null pointer, then the theoretical maximum graph centrality score for a graph with the same number vertices is stored here.

normalized:

Boolean, whether to calculate a normalized centralization score. See igraph_centralization() for how the normalization is done.

Returns: 

Error code.

See also: 

Time complexity: the complexity of igraph_eigenvector_centrality() plus O(|V|), the number of vertices for the calculating the centralization.

8.6. igraph_centralization_degree_tmax — Theoretical maximum for graph centralization based on degree

int igraph_centralization_degree_tmax(const igraph_t *graph, 
				      igraph_integer_t nodes,
				      igraph_neimode_t mode,
				      igraph_bool_t loops,
				      igraph_real_t *res);

This function returns the theoretical maximum graph centrality based on vertex degree.

There are two ways to call this function, the first is to supply a graph as the graph argument, and then the number of vertices is taken from this object, and its directedness is considered as well. The nodes argument is ignored in this case. The mode argument is also ignored if the supplied graph is undirected.

The other way is to supply a null pointer as the graph argument. In this case the nodes and mode arguments are considered.

The most centralized structure is the star. More specifically, for undirected graphs it is the star, for directed graphs it is the in-star or the out-star.

Arguments: 

graph:

A graph object or a null pointer, see the description above.

nodes:

The number of nodes. This is ignored if the graph argument is not a null pointer.

mode:

Constant, whether the calculation is based on in-degree ( IGRAPH_IN ), out-degree ( IGRAPH_OUT ) or total degree ( IGRAPH_ALL ). This is ignored if the graph argument is not a null pointer and the given graph is undirected.

loops:

Boolean scalar, whether to consider loop edges in the calculation.

res:

Pointer to a real variable, the result is stored here.

Returns: 

Error code.

Time complexity: O(1).

See also: 

8.7. igraph_centralization_betweenness_tmax — Theoretical maximum for graph centralization based on betweenness

int igraph_centralization_betweenness_tmax(const igraph_t *graph, 
					   igraph_integer_t nodes,
					   igraph_bool_t directed,
					   igraph_real_t *res);

This function returns the theoretical maximum graph centrality based on vertex betweenness.

There are two ways to call this function, the first is to supply a graph as the graph argument, and then the number of vertices is taken from this object, and its directedness is considered as well. The nodes argument is ignored in this case. The directed argument is also ignored if the supplied graph is undirected.

The other way is to supply a null pointer as the graph argument. In this case the nodes and directed arguments are considered.

The most centralized structure is the star.

Arguments: 

graph:

A graph object or a null pointer, see the description above.

nodes:

The number of nodes. This is ignored if the graph argument is not a null pointer.

directed:

Boolean scalar, whether to use directed paths in the betweenness calculation. This argument is ignored if graph is not a null pointer and it is undirected.

res:

Pointer to a real variable, the result is stored here.

Returns: 

Error code.

Time complexity: O(1).

See also: 

8.8. igraph_centralization_closeness_tmax — Theoretical maximum for graph centralization based on closeness

int igraph_centralization_closeness_tmax(const igraph_t *graph,
					 igraph_integer_t nodes,
					 igraph_neimode_t mode,
					 igraph_real_t *res);

This function returns the theoretical maximum graph centrality based on vertex closeness.

There are two ways to call this function, the first is to supply a graph as the graph argument, and then the number of vertices is taken from this object, and its directedness is considered as well. The nodes argument is ignored in this case. The mode argument is also ignored if the supplied graph is undirected.

The other way is to supply a null pointer as the graph argument. In this case the nodes and mode arguments are considered.

The most centralized structure is the star.

Arguments: 

graph:

A graph object or a null pointer, see the description above.

nodes:

The number of nodes. This is ignored if the graph argument is not a null pointer.

mode:

Constant, specifies what kinf of distances to consider to calculate closeness. See the mode argument of igraph_closeness() for details. This argument is ignored if graph is not a null pointer and it is undirected.

res:

Pointer to a real variable, the result is stored here.

Returns: 

Error code.

Time complexity: O(1).

See also: 

8.9. igraph_centralization_eigenvector_centrality_tmax — Theoretical maximum centralization for eigenvector centrality

int igraph_centralization_eigenvector_centrality_tmax(
					 const igraph_t *graph,
					 igraph_integer_t nodes,
					 igraph_bool_t directed,
					 igraph_bool_t scale, 
					 igraph_real_t *res);

This function returns the theoretical maximum graph centrality based on vertex eigenvector centrality.

There are two ways to call this function, the first is to supply a graph as the graph argument, and then the number of vertices is taken from this object, and its directedness is considered as well. The nodes argument is ignored in this case. The directed argument is also ignored if the supplied graph is undirected.

The other way is to supply a null pointer as the graph argument. In this case the nodes and directed arguments are considered.

The most centralized directed structure is the in-star. The most centralized undirected structure is the graph with a single edge.

Arguments: 

graph:

A graph object or a null pointer, see the description above.

nodes:

The number of nodes. This is ignored if the graph argument is not a null pointer.

directed:

Boolean scalar, whether to consider edge directions. This argument is ignored if graph is not a null pointer and it is undirected.

scale:

Whether to rescale the node-level centrality scores to have a maximum of one.

res:

Pointer to a real variable, the result is stored here.

Returns: 

Error code.

Time complexity: O(1).

See also: 

9. Similarity Measures

9.1. igraph_bibcoupling — Bibliographic coupling.

int igraph_bibcoupling(const igraph_t *graph, igraph_matrix_t *res, 
                       const igraph_vs_t vids);

The bibliographic coupling of two vertices is the number of other vertices they both cite, igraph_bibcoupling() calculates this. The bibliographic coupling score for each given vertex and all other vertices in the graph will be calculated.

Arguments: 

graph:

The graph object to analyze.

res:

Pointer to a matrix, the result of the calculation will be stored here. The number of its rows is the same as the number of vertex ids in vids, the number of columns is the number of vertices in the graph.

vids:

The vertex ids of the vertices for which the calculation will be done.

Returns: 

Error code: IGRAPH_EINVVID: invalid vertex id.

Time complexity: O(|V|d^2), |V| is the number of vertices in the graph, d is the (maximum) degree of the vertices in the graph.

See also: 

9.2. igraph_cocitation — Cocitation coupling.

int igraph_cocitation(const igraph_t *graph, igraph_matrix_t *res, 
                      const igraph_vs_t vids);

Two vertices are cocited if there is another vertex citing both of them. igraph_cocitation() simply counts how many times two vertices are cocited. The cocitation score for each given vertex and all other vertices in the graph will be calculated.

Arguments: 

graph:

The graph object to analyze.

res:

Pointer to a matrix, the result of the calculation will be stored here. The number of its rows is the same as the number of vertex ids in vids, the number of columns is the number of vertices in the graph.

vids:

The vertex ids of the vertices for which the calculation will be done.

Returns: 

Error code: IGRAPH_EINVVID: invalid vertex id.

Time complexity: O(|V|d^2), |V| is the number of vertices in the graph, d is the (maximum) degree of the vertices in the graph.

See also: 

Example 13.18.  File examples/simple/igraph_cocitation.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2006-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.h>

void print_matrix(igraph_matrix_t *m, FILE *f) {
  long int i, j;
  for (i=0; i<igraph_matrix_nrow(m); i++) {
    for (j=0; j<igraph_matrix_ncol(m); j++) {
      fprintf(f, " %li", (long int) MATRIX(*m, i, j));
    }
    fprintf(f, "\n");
  }
}

int main() {
  
  igraph_t g;
  igraph_matrix_t m;
  
  igraph_small(&g, 0, IGRAPH_DIRECTED, 
	       0,1, 2,1, 2,0, 3,0, 
	       -1);
  
  igraph_matrix_init(&m, 0, 0);
  igraph_bibcoupling(&g, &m, igraph_vss_all());
  print_matrix(&m, stdout);
  
  igraph_cocitation(&g, &m, igraph_vss_all());
  print_matrix(&m, stdout);
  
  igraph_matrix_destroy(&m);
  igraph_destroy(&g);
  
  return 0;
}


9.3. igraph_similarity_jaccard — Jaccard similarity coefficient for the given vertices.

int igraph_similarity_jaccard(const igraph_t *graph, igraph_matrix_t *res,
    const igraph_vs_t vids, igraph_neimode_t mode, igraph_bool_t loops);

The Jaccard similarity coefficient of two vertices is the number of common neighbors divided by the number of vertices that are neighbors of at least one of the two vertices being considered. This function calculates the pairwise Jaccard similarities for some (or all) of the vertices.

Arguments: 

graph:

The graph object to analyze

res:

Pointer to a matrix, the result of the calculation will be stored here. The number of its rows and columns is the same as the number of vertex ids in vids.

vids:

The vertex ids of the vertices for which the calculation will be done.

mode:

The type of neighbors to be used for the calculation in directed graphs. Possible values:

IGRAPH_OUT

the outgoing edges will be considered for each node.

IGRAPH_IN

the incoming edges will be considered for each node.

IGRAPH_ALL

the directed graph is considered as an undirected one for the computation.

loops:

Whether to include the vertices themselves in the neighbor sets.

Returns: 

Error code:

IGRAPH_ENOMEM

not enough memory for temporary data.

IGRAPH_EINVVID

invalid vertex id passed.

IGRAPH_EINVMODE

invalid mode argument.

Time complexity: O(|V|^2 d), |V| is the number of vertices in the vertex iterator given, d is the (maximum) degree of the vertices in the graph.

See also: 

igraph_similarity_dice(), a measure very similar to the Jaccard coefficient

Example 13.19.  File examples/simple/igraph_similarity.c

/* -*- mode: C -*-  */
/* vim:set ts=2 sw=2 sts=2 et: */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

void print_matrix(igraph_matrix_t *m, FILE *f) {
  long int i, j;
  for (i=0; i<igraph_matrix_nrow(m); i++) {
    for (j=0; j<igraph_matrix_ncol(m); j++) {
      fprintf(f, " %.2f", MATRIX(*m, i, j));
    }
    fprintf(f, "\n");
  }
  fprintf(f, "==========\n");
}

int check_jaccard_all(const igraph_t* g, igraph_matrix_t* m,
		igraph_neimode_t mode, igraph_bool_t loops) {
  igraph_vector_t pairs, res;
  long int i, j, k, n;
  igraph_eit_t eit;

  igraph_vector_init(&res, 0);

  /* First, query the similarities for all the vertices to a matrix */
  igraph_similarity_jaccard(g, m, igraph_vss_all(), mode, loops);

  /* Second, query the similarities for all pairs using a pair vector */
  n = igraph_vcount(g);
  igraph_vector_init(&pairs, 0);
  for (i = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--) {
      igraph_vector_push_back(&pairs, i);
      igraph_vector_push_back(&pairs, j);
    }
  }
  igraph_similarity_jaccard_pairs(g, &res, &pairs, mode, loops);
  for (i = 0, k = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--, k++) {
      if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
        fprintf(stderr, "Jaccard similarity calculation for vertex pair %ld-%ld "
            "does not match the value in the full matrix (%.6f vs %.6f)\n",
            i, j, VECTOR(res)[k], MATRIX(*m, i, j));
        return 1;
      }
    }
  }
  igraph_vector_destroy(&pairs);

  /* Third, query the similarities for all edges */
  igraph_similarity_jaccard_es(g, &res, igraph_ess_all(IGRAPH_EDGEORDER_FROM), mode, loops);
  igraph_eit_create(g, igraph_ess_all(IGRAPH_EDGEORDER_FROM), &eit);
  k = 0;
  while (!IGRAPH_EIT_END(eit)) {
    long int eid = IGRAPH_EIT_GET(eit);
    i = IGRAPH_FROM(g, eid); j = IGRAPH_TO(g, eid);
    if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
      fprintf(stderr, "Jaccard similarity calculation for edge %ld-%ld (ID=%ld) "
          "does not match the value in the full matrix (%.6f vs %.6f)\n",
          i, j, eid, VECTOR(res)[k], MATRIX(*m, i, j));
      return 1;
    }
    IGRAPH_EIT_NEXT(eit);
    k++;
  }

  igraph_eit_destroy(&eit);

  igraph_vector_destroy(&res);

  return 0;
}

int check_dice_all(const igraph_t* g, igraph_matrix_t* m,
		igraph_neimode_t mode, igraph_bool_t loops) {
  igraph_vector_t pairs, res;
  long int i, j, k, n;
  igraph_eit_t eit;

  igraph_vector_init(&res, 0);

  /* First, query the similarities for all the vertices to a matrix */
  igraph_similarity_dice(g, m, igraph_vss_all(), mode, loops);

  /* Second, query the similarities for all pairs using a pair vector */
  n = igraph_vcount(g);
  igraph_vector_init(&pairs, 0);
  for (i = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--) {
      igraph_vector_push_back(&pairs, i);
      igraph_vector_push_back(&pairs, j);
    }
  }
  igraph_similarity_dice_pairs(g, &res, &pairs, mode, loops);
  for (i = 0, k = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--, k++) {
      if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
        fprintf(stderr, "Dice similarity calculation for vertex pair %ld-%ld "
            "does not match the value in the full matrix (%.6f vs %.6f)\n",
            i, j, VECTOR(res)[k], MATRIX(*m, i, j));
        return 1;
      }
    }
  }
  igraph_vector_destroy(&pairs);

  /* Third, query the similarities for all edges */
  igraph_similarity_dice_es(g, &res, igraph_ess_all(IGRAPH_EDGEORDER_FROM), mode, loops);
  igraph_eit_create(g, igraph_ess_all(IGRAPH_EDGEORDER_FROM), &eit);
  k = 0;
  while (!IGRAPH_EIT_END(eit)) {
    long int eid = IGRAPH_EIT_GET(eit);
    i = IGRAPH_FROM(g, eid); j = IGRAPH_TO(g, eid);
    if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
      fprintf(stderr, "Dice similarity calculation for edge %ld-%ld (ID=%ld) "
          "does not match the value in the full matrix (%.6f vs %.6f)\n",
          i, j, eid, VECTOR(res)[k], MATRIX(*m, i, j));
      return 1;
    }
    IGRAPH_EIT_NEXT(eit);
    k++;
  }

  igraph_eit_destroy(&eit);

  igraph_vector_destroy(&res);

  return 0;
}

int main() {
  
  igraph_t g;
  igraph_matrix_t m;
  int ret;

  igraph_small(&g, 0, IGRAPH_DIRECTED, 
	       0,1, 2,1, 2,0, 3,0, 
	       -1);
  
  igraph_matrix_init(&m, 0, 0);

  ret = check_jaccard_all(&g, &m, IGRAPH_ALL, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 1;
  
  igraph_similarity_jaccard(&g, &m, igraph_vss_seq(1, 2), IGRAPH_ALL, 0);
  print_matrix(&m, stdout);
  
  ret = check_jaccard_all(&g, &m, IGRAPH_OUT, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 3;
  
  ret = check_jaccard_all(&g, &m, IGRAPH_IN, 0);
  print_matrix(&m, stdout);
  if (ret)
    return 4;
  
  ret = check_dice_all(&g, &m, IGRAPH_ALL, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 5;
  
  ret = check_dice_all(&g, &m, IGRAPH_OUT, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 6;

  ret = check_dice_all(&g, &m, IGRAPH_IN, 0);
  print_matrix(&m, stdout);
  if (ret)
    return 7;

  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_ALL);
  print_matrix(&m, stdout);
  
  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_OUT);
  print_matrix(&m, stdout);
  
  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_IN);
  print_matrix(&m, stdout);
  
  igraph_matrix_destroy(&m);
  igraph_destroy(&g);
  
  return 0;
}


9.4. igraph_similarity_jaccard_pairs — Jaccard similarity coefficient for given vertex pairs.

int igraph_similarity_jaccard_pairs(const igraph_t *graph, igraph_vector_t *res,
	const igraph_vector_t *pairs, igraph_neimode_t mode, igraph_bool_t loops);

The Jaccard similarity coefficient of two vertices is the number of common neighbors divided by the number of vertices that are neighbors of at least one of the two vertices being considered. This function calculates the pairwise Jaccard similarities for a list of vertex pairs.

Arguments: 

graph:

The graph object to analyze

res:

Pointer to a vector, the result of the calculation will be stored here. The number of elements is the same as the number of pairs in pairs.

pairs:

A vector that contains the pairs for which the similarity will be calculated. Each pair is defined by two consecutive elements, i.e. the first and second element of the vector specifies the first pair, the third and fourth element specifies the second pair and so on.

mode:

The type of neighbors to be used for the calculation in directed graphs. Possible values:

IGRAPH_OUT

the outgoing edges will be considered for each node.

IGRAPH_IN

the incoming edges will be considered for each node.

IGRAPH_ALL

the directed graph is considered as an undirected one for the computation.

loops:

Whether to include the vertices themselves in the neighbor sets.

Returns: 

Error code:

IGRAPH_ENOMEM

not enough memory for temporary data.

IGRAPH_EINVVID

invalid vertex id passed.

IGRAPH_EINVMODE

invalid mode argument.

Time complexity: O(nd), n is the number of pairs in the given vector, d is the (maximum) degree of the vertices in the graph.

See also: 

igraph_similarity_jaccard() to calculate the Jaccard similarity between all pairs of a vertex set, or igraph_similarity_dice() and igraph_similarity_dice_pairs() for a measure very similar to the Jaccard coefficient

Example 13.20.  File examples/simple/igraph_similarity.c

/* -*- mode: C -*-  */
/* vim:set ts=2 sw=2 sts=2 et: */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

void print_matrix(igraph_matrix_t *m, FILE *f) {
  long int i, j;
  for (i=0; i<igraph_matrix_nrow(m); i++) {
    for (j=0; j<igraph_matrix_ncol(m); j++) {
      fprintf(f, " %.2f", MATRIX(*m, i, j));
    }
    fprintf(f, "\n");
  }
  fprintf(f, "==========\n");
}

int check_jaccard_all(const igraph_t* g, igraph_matrix_t* m,
		igraph_neimode_t mode, igraph_bool_t loops) {
  igraph_vector_t pairs, res;
  long int i, j, k, n;
  igraph_eit_t eit;

  igraph_vector_init(&res, 0);

  /* First, query the similarities for all the vertices to a matrix */
  igraph_similarity_jaccard(g, m, igraph_vss_all(), mode, loops);

  /* Second, query the similarities for all pairs using a pair vector */
  n = igraph_vcount(g);
  igraph_vector_init(&pairs, 0);
  for (i = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--) {
      igraph_vector_push_back(&pairs, i);
      igraph_vector_push_back(&pairs, j);
    }
  }
  igraph_similarity_jaccard_pairs(g, &res, &pairs, mode, loops);
  for (i = 0, k = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--, k++) {
      if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
        fprintf(stderr, "Jaccard similarity calculation for vertex pair %ld-%ld "
            "does not match the value in the full matrix (%.6f vs %.6f)\n",
            i, j, VECTOR(res)[k], MATRIX(*m, i, j));
        return 1;
      }
    }
  }
  igraph_vector_destroy(&pairs);

  /* Third, query the similarities for all edges */
  igraph_similarity_jaccard_es(g, &res, igraph_ess_all(IGRAPH_EDGEORDER_FROM), mode, loops);
  igraph_eit_create(g, igraph_ess_all(IGRAPH_EDGEORDER_FROM), &eit);
  k = 0;
  while (!IGRAPH_EIT_END(eit)) {
    long int eid = IGRAPH_EIT_GET(eit);
    i = IGRAPH_FROM(g, eid); j = IGRAPH_TO(g, eid);
    if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
      fprintf(stderr, "Jaccard similarity calculation for edge %ld-%ld (ID=%ld) "
          "does not match the value in the full matrix (%.6f vs %.6f)\n",
          i, j, eid, VECTOR(res)[k], MATRIX(*m, i, j));
      return 1;
    }
    IGRAPH_EIT_NEXT(eit);
    k++;
  }

  igraph_eit_destroy(&eit);

  igraph_vector_destroy(&res);

  return 0;
}

int check_dice_all(const igraph_t* g, igraph_matrix_t* m,
		igraph_neimode_t mode, igraph_bool_t loops) {
  igraph_vector_t pairs, res;
  long int i, j, k, n;
  igraph_eit_t eit;

  igraph_vector_init(&res, 0);

  /* First, query the similarities for all the vertices to a matrix */
  igraph_similarity_dice(g, m, igraph_vss_all(), mode, loops);

  /* Second, query the similarities for all pairs using a pair vector */
  n = igraph_vcount(g);
  igraph_vector_init(&pairs, 0);
  for (i = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--) {
      igraph_vector_push_back(&pairs, i);
      igraph_vector_push_back(&pairs, j);
    }
  }
  igraph_similarity_dice_pairs(g, &res, &pairs, mode, loops);
  for (i = 0, k = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--, k++) {
      if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
        fprintf(stderr, "Dice similarity calculation for vertex pair %ld-%ld "
            "does not match the value in the full matrix (%.6f vs %.6f)\n",
            i, j, VECTOR(res)[k], MATRIX(*m, i, j));
        return 1;
      }
    }
  }
  igraph_vector_destroy(&pairs);

  /* Third, query the similarities for all edges */
  igraph_similarity_dice_es(g, &res, igraph_ess_all(IGRAPH_EDGEORDER_FROM), mode, loops);
  igraph_eit_create(g, igraph_ess_all(IGRAPH_EDGEORDER_FROM), &eit);
  k = 0;
  while (!IGRAPH_EIT_END(eit)) {
    long int eid = IGRAPH_EIT_GET(eit);
    i = IGRAPH_FROM(g, eid); j = IGRAPH_TO(g, eid);
    if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
      fprintf(stderr, "Dice similarity calculation for edge %ld-%ld (ID=%ld) "
          "does not match the value in the full matrix (%.6f vs %.6f)\n",
          i, j, eid, VECTOR(res)[k], MATRIX(*m, i, j));
      return 1;
    }
    IGRAPH_EIT_NEXT(eit);
    k++;
  }

  igraph_eit_destroy(&eit);

  igraph_vector_destroy(&res);

  return 0;
}

int main() {
  
  igraph_t g;
  igraph_matrix_t m;
  int ret;

  igraph_small(&g, 0, IGRAPH_DIRECTED, 
	       0,1, 2,1, 2,0, 3,0, 
	       -1);
  
  igraph_matrix_init(&m, 0, 0);

  ret = check_jaccard_all(&g, &m, IGRAPH_ALL, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 1;
  
  igraph_similarity_jaccard(&g, &m, igraph_vss_seq(1, 2), IGRAPH_ALL, 0);
  print_matrix(&m, stdout);
  
  ret = check_jaccard_all(&g, &m, IGRAPH_OUT, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 3;
  
  ret = check_jaccard_all(&g, &m, IGRAPH_IN, 0);
  print_matrix(&m, stdout);
  if (ret)
    return 4;
  
  ret = check_dice_all(&g, &m, IGRAPH_ALL, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 5;
  
  ret = check_dice_all(&g, &m, IGRAPH_OUT, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 6;

  ret = check_dice_all(&g, &m, IGRAPH_IN, 0);
  print_matrix(&m, stdout);
  if (ret)
    return 7;

  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_ALL);
  print_matrix(&m, stdout);
  
  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_OUT);
  print_matrix(&m, stdout);
  
  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_IN);
  print_matrix(&m, stdout);
  
  igraph_matrix_destroy(&m);
  igraph_destroy(&g);
  
  return 0;
}


9.5. igraph_similarity_jaccard_es — Jaccard similarity coefficient for a given edge selector.

int igraph_similarity_jaccard_es(const igraph_t *graph, igraph_vector_t *res,
	const igraph_es_t es, igraph_neimode_t mode, igraph_bool_t loops);

The Jaccard similarity coefficient of two vertices is the number of common neighbors divided by the number of vertices that are neighbors of at least one of the two vertices being considered. This function calculates the pairwise Jaccard similarities for the endpoints of edges in a given edge selector.

Arguments: 

graph:

The graph object to analyze

res:

Pointer to a vector, the result of the calculation will be stored here. The number of elements is the same as the number of edges in es.

es:

An edge selector that specifies the edges to be included in the result.

mode:

The type of neighbors to be used for the calculation in directed graphs. Possible values:

IGRAPH_OUT

the outgoing edges will be considered for each node.

IGRAPH_IN

the incoming edges will be considered for each node.

IGRAPH_ALL

the directed graph is considered as an undirected one for the computation.

loops:

Whether to include the vertices themselves in the neighbor sets.

Returns: 

Error code:

IGRAPH_ENOMEM

not enough memory for temporary data.

IGRAPH_EINVVID

invalid vertex id passed.

IGRAPH_EINVMODE

invalid mode argument.

Time complexity: O(nd), n is the number of edges in the edge selector, d is the (maximum) degree of the vertices in the graph.

See also: 

igraph_similarity_jaccard() and igraph_similarity_jaccard_pairs() to calculate the Jaccard similarity between all pairs of a vertex set or some selected vertex pairs, or igraph_similarity_dice(), igraph_similarity_dice_pairs() and igraph_similarity_dice_es() for a measure very similar to the Jaccard coefficient

Example 13.21.  File examples/simple/igraph_similarity.c

/* -*- mode: C -*-  */
/* vim:set ts=2 sw=2 sts=2 et: */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

void print_matrix(igraph_matrix_t *m, FILE *f) {
  long int i, j;
  for (i=0; i<igraph_matrix_nrow(m); i++) {
    for (j=0; j<igraph_matrix_ncol(m); j++) {
      fprintf(f, " %.2f", MATRIX(*m, i, j));
    }
    fprintf(f, "\n");
  }
  fprintf(f, "==========\n");
}

int check_jaccard_all(const igraph_t* g, igraph_matrix_t* m,
		igraph_neimode_t mode, igraph_bool_t loops) {
  igraph_vector_t pairs, res;
  long int i, j, k, n;
  igraph_eit_t eit;

  igraph_vector_init(&res, 0);

  /* First, query the similarities for all the vertices to a matrix */
  igraph_similarity_jaccard(g, m, igraph_vss_all(), mode, loops);

  /* Second, query the similarities for all pairs using a pair vector */
  n = igraph_vcount(g);
  igraph_vector_init(&pairs, 0);
  for (i = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--) {
      igraph_vector_push_back(&pairs, i);
      igraph_vector_push_back(&pairs, j);
    }
  }
  igraph_similarity_jaccard_pairs(g, &res, &pairs, mode, loops);
  for (i = 0, k = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--, k++) {
      if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
        fprintf(stderr, "Jaccard similarity calculation for vertex pair %ld-%ld "
            "does not match the value in the full matrix (%.6f vs %.6f)\n",
            i, j, VECTOR(res)[k], MATRIX(*m, i, j));
        return 1;
      }
    }
  }
  igraph_vector_destroy(&pairs);

  /* Third, query the similarities for all edges */
  igraph_similarity_jaccard_es(g, &res, igraph_ess_all(IGRAPH_EDGEORDER_FROM), mode, loops);
  igraph_eit_create(g, igraph_ess_all(IGRAPH_EDGEORDER_FROM), &eit);
  k = 0;
  while (!IGRAPH_EIT_END(eit)) {
    long int eid = IGRAPH_EIT_GET(eit);
    i = IGRAPH_FROM(g, eid); j = IGRAPH_TO(g, eid);
    if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
      fprintf(stderr, "Jaccard similarity calculation for edge %ld-%ld (ID=%ld) "
          "does not match the value in the full matrix (%.6f vs %.6f)\n",
          i, j, eid, VECTOR(res)[k], MATRIX(*m, i, j));
      return 1;
    }
    IGRAPH_EIT_NEXT(eit);
    k++;
  }

  igraph_eit_destroy(&eit);

  igraph_vector_destroy(&res);

  return 0;
}

int check_dice_all(const igraph_t* g, igraph_matrix_t* m,
		igraph_neimode_t mode, igraph_bool_t loops) {
  igraph_vector_t pairs, res;
  long int i, j, k, n;
  igraph_eit_t eit;

  igraph_vector_init(&res, 0);

  /* First, query the similarities for all the vertices to a matrix */
  igraph_similarity_dice(g, m, igraph_vss_all(), mode, loops);

  /* Second, query the similarities for all pairs using a pair vector */
  n = igraph_vcount(g);
  igraph_vector_init(&pairs, 0);
  for (i = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--) {
      igraph_vector_push_back(&pairs, i);
      igraph_vector_push_back(&pairs, j);
    }
  }
  igraph_similarity_dice_pairs(g, &res, &pairs, mode, loops);
  for (i = 0, k = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--, k++) {
      if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
        fprintf(stderr, "Dice similarity calculation for vertex pair %ld-%ld "
            "does not match the value in the full matrix (%.6f vs %.6f)\n",
            i, j, VECTOR(res)[k], MATRIX(*m, i, j));
        return 1;
      }
    }
  }
  igraph_vector_destroy(&pairs);

  /* Third, query the similarities for all edges */
  igraph_similarity_dice_es(g, &res, igraph_ess_all(IGRAPH_EDGEORDER_FROM), mode, loops);
  igraph_eit_create(g, igraph_ess_all(IGRAPH_EDGEORDER_FROM), &eit);
  k = 0;
  while (!IGRAPH_EIT_END(eit)) {
    long int eid = IGRAPH_EIT_GET(eit);
    i = IGRAPH_FROM(g, eid); j = IGRAPH_TO(g, eid);
    if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
      fprintf(stderr, "Dice similarity calculation for edge %ld-%ld (ID=%ld) "
          "does not match the value in the full matrix (%.6f vs %.6f)\n",
          i, j, eid, VECTOR(res)[k], MATRIX(*m, i, j));
      return 1;
    }
    IGRAPH_EIT_NEXT(eit);
    k++;
  }

  igraph_eit_destroy(&eit);

  igraph_vector_destroy(&res);

  return 0;
}

int main() {
  
  igraph_t g;
  igraph_matrix_t m;
  int ret;

  igraph_small(&g, 0, IGRAPH_DIRECTED, 
	       0,1, 2,1, 2,0, 3,0, 
	       -1);
  
  igraph_matrix_init(&m, 0, 0);

  ret = check_jaccard_all(&g, &m, IGRAPH_ALL, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 1;
  
  igraph_similarity_jaccard(&g, &m, igraph_vss_seq(1, 2), IGRAPH_ALL, 0);
  print_matrix(&m, stdout);
  
  ret = check_jaccard_all(&g, &m, IGRAPH_OUT, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 3;
  
  ret = check_jaccard_all(&g, &m, IGRAPH_IN, 0);
  print_matrix(&m, stdout);
  if (ret)
    return 4;
  
  ret = check_dice_all(&g, &m, IGRAPH_ALL, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 5;
  
  ret = check_dice_all(&g, &m, IGRAPH_OUT, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 6;

  ret = check_dice_all(&g, &m, IGRAPH_IN, 0);
  print_matrix(&m, stdout);
  if (ret)
    return 7;

  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_ALL);
  print_matrix(&m, stdout);
  
  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_OUT);
  print_matrix(&m, stdout);
  
  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_IN);
  print_matrix(&m, stdout);
  
  igraph_matrix_destroy(&m);
  igraph_destroy(&g);
  
  return 0;
}


9.6. igraph_similarity_dice — Dice similarity coefficient.

int igraph_similarity_dice(const igraph_t *graph, igraph_matrix_t *res,
    const igraph_vs_t vids, igraph_neimode_t mode, igraph_bool_t loops);

The Dice similarity coefficient of two vertices is twice the number of common neighbors divided by the sum of the degrees of the vertices. This function calculates the pairwise Dice similarities for some (or all) of the vertices.

Arguments: 

graph:

The graph object to analyze

res:

Pointer to a matrix, the result of the calculation will be stored here. The number of its rows and columns is the same as the number of vertex ids in vids.

vids:

The vertex ids of the vertices for which the calculation will be done.

mode:

The type of neighbors to be used for the calculation in directed graphs. Possible values:

IGRAPH_OUT

the outgoing edges will be considered for each node.

IGRAPH_IN

the incoming edges will be considered for each node.

IGRAPH_ALL

the directed graph is considered as an undirected one for the computation.

loops:

Whether to include the vertices themselves as their own neighbors.

Returns: 

Error code:

IGRAPH_ENOMEM

not enough memory for temporary data.

IGRAPH_EINVVID

invalid vertex id passed.

IGRAPH_EINVMODE

invalid mode argument.

Time complexity: O(|V|^2 d), |V| is the number of vertices in the vertex iterator given, d is the (maximum) degree of the vertices in the graph.

See also: 

igraph_similarity_jaccard(), a measure very similar to the Dice coefficient

Example 13.22.  File examples/simple/igraph_similarity.c

/* -*- mode: C -*-  */
/* vim:set ts=2 sw=2 sts=2 et: */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

void print_matrix(igraph_matrix_t *m, FILE *f) {
  long int i, j;
  for (i=0; i<igraph_matrix_nrow(m); i++) {
    for (j=0; j<igraph_matrix_ncol(m); j++) {
      fprintf(f, " %.2f", MATRIX(*m, i, j));
    }
    fprintf(f, "\n");
  }
  fprintf(f, "==========\n");
}

int check_jaccard_all(const igraph_t* g, igraph_matrix_t* m,
		igraph_neimode_t mode, igraph_bool_t loops) {
  igraph_vector_t pairs, res;
  long int i, j, k, n;
  igraph_eit_t eit;

  igraph_vector_init(&res, 0);

  /* First, query the similarities for all the vertices to a matrix */
  igraph_similarity_jaccard(g, m, igraph_vss_all(), mode, loops);

  /* Second, query the similarities for all pairs using a pair vector */
  n = igraph_vcount(g);
  igraph_vector_init(&pairs, 0);
  for (i = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--) {
      igraph_vector_push_back(&pairs, i);
      igraph_vector_push_back(&pairs, j);
    }
  }
  igraph_similarity_jaccard_pairs(g, &res, &pairs, mode, loops);
  for (i = 0, k = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--, k++) {
      if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
        fprintf(stderr, "Jaccard similarity calculation for vertex pair %ld-%ld "
            "does not match the value in the full matrix (%.6f vs %.6f)\n",
            i, j, VECTOR(res)[k], MATRIX(*m, i, j));
        return 1;
      }
    }
  }
  igraph_vector_destroy(&pairs);

  /* Third, query the similarities for all edges */
  igraph_similarity_jaccard_es(g, &res, igraph_ess_all(IGRAPH_EDGEORDER_FROM), mode, loops);
  igraph_eit_create(g, igraph_ess_all(IGRAPH_EDGEORDER_FROM), &eit);
  k = 0;
  while (!IGRAPH_EIT_END(eit)) {
    long int eid = IGRAPH_EIT_GET(eit);
    i = IGRAPH_FROM(g, eid); j = IGRAPH_TO(g, eid);
    if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
      fprintf(stderr, "Jaccard similarity calculation for edge %ld-%ld (ID=%ld) "
          "does not match the value in the full matrix (%.6f vs %.6f)\n",
          i, j, eid, VECTOR(res)[k], MATRIX(*m, i, j));
      return 1;
    }
    IGRAPH_EIT_NEXT(eit);
    k++;
  }

  igraph_eit_destroy(&eit);

  igraph_vector_destroy(&res);

  return 0;
}

int check_dice_all(const igraph_t* g, igraph_matrix_t* m,
		igraph_neimode_t mode, igraph_bool_t loops) {
  igraph_vector_t pairs, res;
  long int i, j, k, n;
  igraph_eit_t eit;

  igraph_vector_init(&res, 0);

  /* First, query the similarities for all the vertices to a matrix */
  igraph_similarity_dice(g, m, igraph_vss_all(), mode, loops);

  /* Second, query the similarities for all pairs using a pair vector */
  n = igraph_vcount(g);
  igraph_vector_init(&pairs, 0);
  for (i = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--) {
      igraph_vector_push_back(&pairs, i);
      igraph_vector_push_back(&pairs, j);
    }
  }
  igraph_similarity_dice_pairs(g, &res, &pairs, mode, loops);
  for (i = 0, k = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--, k++) {
      if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
        fprintf(stderr, "Dice similarity calculation for vertex pair %ld-%ld "
            "does not match the value in the full matrix (%.6f vs %.6f)\n",
            i, j, VECTOR(res)[k], MATRIX(*m, i, j));
        return 1;
      }
    }
  }
  igraph_vector_destroy(&pairs);

  /* Third, query the similarities for all edges */
  igraph_similarity_dice_es(g, &res, igraph_ess_all(IGRAPH_EDGEORDER_FROM), mode, loops);
  igraph_eit_create(g, igraph_ess_all(IGRAPH_EDGEORDER_FROM), &eit);
  k = 0;
  while (!IGRAPH_EIT_END(eit)) {
    long int eid = IGRAPH_EIT_GET(eit);
    i = IGRAPH_FROM(g, eid); j = IGRAPH_TO(g, eid);
    if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
      fprintf(stderr, "Dice similarity calculation for edge %ld-%ld (ID=%ld) "
          "does not match the value in the full matrix (%.6f vs %.6f)\n",
          i, j, eid, VECTOR(res)[k], MATRIX(*m, i, j));
      return 1;
    }
    IGRAPH_EIT_NEXT(eit);
    k++;
  }

  igraph_eit_destroy(&eit);

  igraph_vector_destroy(&res);

  return 0;
}

int main() {
  
  igraph_t g;
  igraph_matrix_t m;
  int ret;

  igraph_small(&g, 0, IGRAPH_DIRECTED, 
	       0,1, 2,1, 2,0, 3,0, 
	       -1);
  
  igraph_matrix_init(&m, 0, 0);

  ret = check_jaccard_all(&g, &m, IGRAPH_ALL, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 1;
  
  igraph_similarity_jaccard(&g, &m, igraph_vss_seq(1, 2), IGRAPH_ALL, 0);
  print_matrix(&m, stdout);
  
  ret = check_jaccard_all(&g, &m, IGRAPH_OUT, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 3;
  
  ret = check_jaccard_all(&g, &m, IGRAPH_IN, 0);
  print_matrix(&m, stdout);
  if (ret)
    return 4;
  
  ret = check_dice_all(&g, &m, IGRAPH_ALL, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 5;
  
  ret = check_dice_all(&g, &m, IGRAPH_OUT, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 6;

  ret = check_dice_all(&g, &m, IGRAPH_IN, 0);
  print_matrix(&m, stdout);
  if (ret)
    return 7;

  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_ALL);
  print_matrix(&m, stdout);
  
  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_OUT);
  print_matrix(&m, stdout);
  
  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_IN);
  print_matrix(&m, stdout);
  
  igraph_matrix_destroy(&m);
  igraph_destroy(&g);
  
  return 0;
}


9.7. igraph_similarity_dice_pairs — Dice similarity coefficient for given vertex pairs.

int igraph_similarity_dice_pairs(const igraph_t *graph, igraph_vector_t *res,
	const igraph_vector_t *pairs, igraph_neimode_t mode, igraph_bool_t loops);

The Dice similarity coefficient of two vertices is twice the number of common neighbors divided by the sum of the degrees of the vertices. This function calculates the pairwise Dice similarities for a list of vertex pairs.

Arguments: 

graph:

The graph object to analyze

res:

Pointer to a vector, the result of the calculation will be stored here. The number of elements is the same as the number of pairs in pairs.

pairs:

A vector that contains the pairs for which the similarity will be calculated. Each pair is defined by two consecutive elements, i.e. the first and second element of the vector specifies the first pair, the third and fourth element specifies the second pair and so on.

mode:

The type of neighbors to be used for the calculation in directed graphs. Possible values:

IGRAPH_OUT

the outgoing edges will be considered for each node.

IGRAPH_IN

the incoming edges will be considered for each node.

IGRAPH_ALL

the directed graph is considered as an undirected one for the computation.

loops:

Whether to include the vertices themselves as their own neighbors.

Returns: 

Error code:

IGRAPH_ENOMEM

not enough memory for temporary data.

IGRAPH_EINVVID

invalid vertex id passed.

IGRAPH_EINVMODE

invalid mode argument.

Time complexity: O(nd), n is the number of pairs in the given vector, d is the (maximum) degree of the vertices in the graph.

See also: 

igraph_similarity_dice() to calculate the Dice similarity between all pairs of a vertex set, or igraph_similarity_jaccard(), igraph_similarity_jaccard_pairs() and igraph_similarity_jaccard_es() for a measure very similar to the Dice coefficient

Example 13.23.  File examples/simple/igraph_similarity.c

/* -*- mode: C -*-  */
/* vim:set ts=2 sw=2 sts=2 et: */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

void print_matrix(igraph_matrix_t *m, FILE *f) {
  long int i, j;
  for (i=0; i<igraph_matrix_nrow(m); i++) {
    for (j=0; j<igraph_matrix_ncol(m); j++) {
      fprintf(f, " %.2f", MATRIX(*m, i, j));
    }
    fprintf(f, "\n");
  }
  fprintf(f, "==========\n");
}

int check_jaccard_all(const igraph_t* g, igraph_matrix_t* m,
		igraph_neimode_t mode, igraph_bool_t loops) {
  igraph_vector_t pairs, res;
  long int i, j, k, n;
  igraph_eit_t eit;

  igraph_vector_init(&res, 0);

  /* First, query the similarities for all the vertices to a matrix */
  igraph_similarity_jaccard(g, m, igraph_vss_all(), mode, loops);

  /* Second, query the similarities for all pairs using a pair vector */
  n = igraph_vcount(g);
  igraph_vector_init(&pairs, 0);
  for (i = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--) {
      igraph_vector_push_back(&pairs, i);
      igraph_vector_push_back(&pairs, j);
    }
  }
  igraph_similarity_jaccard_pairs(g, &res, &pairs, mode, loops);
  for (i = 0, k = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--, k++) {
      if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
        fprintf(stderr, "Jaccard similarity calculation for vertex pair %ld-%ld "
            "does not match the value in the full matrix (%.6f vs %.6f)\n",
            i, j, VECTOR(res)[k], MATRIX(*m, i, j));
        return 1;
      }
    }
  }
  igraph_vector_destroy(&pairs);

  /* Third, query the similarities for all edges */
  igraph_similarity_jaccard_es(g, &res, igraph_ess_all(IGRAPH_EDGEORDER_FROM), mode, loops);
  igraph_eit_create(g, igraph_ess_all(IGRAPH_EDGEORDER_FROM), &eit);
  k = 0;
  while (!IGRAPH_EIT_END(eit)) {
    long int eid = IGRAPH_EIT_GET(eit);
    i = IGRAPH_FROM(g, eid); j = IGRAPH_TO(g, eid);
    if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
      fprintf(stderr, "Jaccard similarity calculation for edge %ld-%ld (ID=%ld) "
          "does not match the value in the full matrix (%.6f vs %.6f)\n",
          i, j, eid, VECTOR(res)[k], MATRIX(*m, i, j));
      return 1;
    }
    IGRAPH_EIT_NEXT(eit);
    k++;
  }

  igraph_eit_destroy(&eit);

  igraph_vector_destroy(&res);

  return 0;
}

int check_dice_all(const igraph_t* g, igraph_matrix_t* m,
		igraph_neimode_t mode, igraph_bool_t loops) {
  igraph_vector_t pairs, res;
  long int i, j, k, n;
  igraph_eit_t eit;

  igraph_vector_init(&res, 0);

  /* First, query the similarities for all the vertices to a matrix */
  igraph_similarity_dice(g, m, igraph_vss_all(), mode, loops);

  /* Second, query the similarities for all pairs using a pair vector */
  n = igraph_vcount(g);
  igraph_vector_init(&pairs, 0);
  for (i = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--) {
      igraph_vector_push_back(&pairs, i);
      igraph_vector_push_back(&pairs, j);
    }
  }
  igraph_similarity_dice_pairs(g, &res, &pairs, mode, loops);
  for (i = 0, k = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--, k++) {
      if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
        fprintf(stderr, "Dice similarity calculation for vertex pair %ld-%ld "
            "does not match the value in the full matrix (%.6f vs %.6f)\n",
            i, j, VECTOR(res)[k], MATRIX(*m, i, j));
        return 1;
      }
    }
  }
  igraph_vector_destroy(&pairs);

  /* Third, query the similarities for all edges */
  igraph_similarity_dice_es(g, &res, igraph_ess_all(IGRAPH_EDGEORDER_FROM), mode, loops);
  igraph_eit_create(g, igraph_ess_all(IGRAPH_EDGEORDER_FROM), &eit);
  k = 0;
  while (!IGRAPH_EIT_END(eit)) {
    long int eid = IGRAPH_EIT_GET(eit);
    i = IGRAPH_FROM(g, eid); j = IGRAPH_TO(g, eid);
    if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
      fprintf(stderr, "Dice similarity calculation for edge %ld-%ld (ID=%ld) "
          "does not match the value in the full matrix (%.6f vs %.6f)\n",
          i, j, eid, VECTOR(res)[k], MATRIX(*m, i, j));
      return 1;
    }
    IGRAPH_EIT_NEXT(eit);
    k++;
  }

  igraph_eit_destroy(&eit);

  igraph_vector_destroy(&res);

  return 0;
}

int main() {
  
  igraph_t g;
  igraph_matrix_t m;
  int ret;

  igraph_small(&g, 0, IGRAPH_DIRECTED, 
	       0,1, 2,1, 2,0, 3,0, 
	       -1);
  
  igraph_matrix_init(&m, 0, 0);

  ret = check_jaccard_all(&g, &m, IGRAPH_ALL, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 1;
  
  igraph_similarity_jaccard(&g, &m, igraph_vss_seq(1, 2), IGRAPH_ALL, 0);
  print_matrix(&m, stdout);
  
  ret = check_jaccard_all(&g, &m, IGRAPH_OUT, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 3;
  
  ret = check_jaccard_all(&g, &m, IGRAPH_IN, 0);
  print_matrix(&m, stdout);
  if (ret)
    return 4;
  
  ret = check_dice_all(&g, &m, IGRAPH_ALL, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 5;
  
  ret = check_dice_all(&g, &m, IGRAPH_OUT, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 6;

  ret = check_dice_all(&g, &m, IGRAPH_IN, 0);
  print_matrix(&m, stdout);
  if (ret)
    return 7;

  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_ALL);
  print_matrix(&m, stdout);
  
  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_OUT);
  print_matrix(&m, stdout);
  
  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_IN);
  print_matrix(&m, stdout);
  
  igraph_matrix_destroy(&m);
  igraph_destroy(&g);
  
  return 0;
}


9.8. igraph_similarity_dice_es — Dice similarity coefficient for a given edge selector.

int igraph_similarity_dice_es(const igraph_t *graph, igraph_vector_t *res,
	const igraph_es_t es, igraph_neimode_t mode, igraph_bool_t loops);

The Dice similarity coefficient of two vertices is twice the number of common neighbors divided by the sum of the degrees of the vertices. This function calculates the pairwise Dice similarities for the endpoints of edges in a given edge selector.

Arguments: 

graph:

The graph object to analyze

res:

Pointer to a vector, the result of the calculation will be stored here. The number of elements is the same as the number of edges in es.

es:

An edge selector that specifies the edges to be included in the result.

mode:

The type of neighbors to be used for the calculation in directed graphs. Possible values:

IGRAPH_OUT

the outgoing edges will be considered for each node.

IGRAPH_IN

the incoming edges will be considered for each node.

IGRAPH_ALL

the directed graph is considered as an undirected one for the computation.

loops:

Whether to include the vertices themselves as their own neighbors.

Returns: 

Error code:

IGRAPH_ENOMEM

not enough memory for temporary data.

IGRAPH_EINVVID

invalid vertex id passed.

IGRAPH_EINVMODE

invalid mode argument.

Time complexity: O(nd), n is the number of pairs in the given vector, d is the (maximum) degree of the vertices in the graph.

See also: 

igraph_similarity_dice() and igraph_similarity_dice_pairs() to calculate the Dice similarity between all pairs of a vertex set or some selected vertex pairs, or igraph_similarity_jaccard(), igraph_similarity_jaccard_pairs() and igraph_similarity_jaccard_es() for a measure very similar to the Dice coefficient

Example 13.24.  File examples/simple/igraph_similarity.c

/* -*- mode: C -*-  */
/* vim:set ts=2 sw=2 sts=2 et: */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

void print_matrix(igraph_matrix_t *m, FILE *f) {
  long int i, j;
  for (i=0; i<igraph_matrix_nrow(m); i++) {
    for (j=0; j<igraph_matrix_ncol(m); j++) {
      fprintf(f, " %.2f", MATRIX(*m, i, j));
    }
    fprintf(f, "\n");
  }
  fprintf(f, "==========\n");
}

int check_jaccard_all(const igraph_t* g, igraph_matrix_t* m,
		igraph_neimode_t mode, igraph_bool_t loops) {
  igraph_vector_t pairs, res;
  long int i, j, k, n;
  igraph_eit_t eit;

  igraph_vector_init(&res, 0);

  /* First, query the similarities for all the vertices to a matrix */
  igraph_similarity_jaccard(g, m, igraph_vss_all(), mode, loops);

  /* Second, query the similarities for all pairs using a pair vector */
  n = igraph_vcount(g);
  igraph_vector_init(&pairs, 0);
  for (i = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--) {
      igraph_vector_push_back(&pairs, i);
      igraph_vector_push_back(&pairs, j);
    }
  }
  igraph_similarity_jaccard_pairs(g, &res, &pairs, mode, loops);
  for (i = 0, k = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--, k++) {
      if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
        fprintf(stderr, "Jaccard similarity calculation for vertex pair %ld-%ld "
            "does not match the value in the full matrix (%.6f vs %.6f)\n",
            i, j, VECTOR(res)[k], MATRIX(*m, i, j));
        return 1;
      }
    }
  }
  igraph_vector_destroy(&pairs);

  /* Third, query the similarities for all edges */
  igraph_similarity_jaccard_es(g, &res, igraph_ess_all(IGRAPH_EDGEORDER_FROM), mode, loops);
  igraph_eit_create(g, igraph_ess_all(IGRAPH_EDGEORDER_FROM), &eit);
  k = 0;
  while (!IGRAPH_EIT_END(eit)) {
    long int eid = IGRAPH_EIT_GET(eit);
    i = IGRAPH_FROM(g, eid); j = IGRAPH_TO(g, eid);
    if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
      fprintf(stderr, "Jaccard similarity calculation for edge %ld-%ld (ID=%ld) "
          "does not match the value in the full matrix (%.6f vs %.6f)\n",
          i, j, eid, VECTOR(res)[k], MATRIX(*m, i, j));
      return 1;
    }
    IGRAPH_EIT_NEXT(eit);
    k++;
  }

  igraph_eit_destroy(&eit);

  igraph_vector_destroy(&res);

  return 0;
}

int check_dice_all(const igraph_t* g, igraph_matrix_t* m,
		igraph_neimode_t mode, igraph_bool_t loops) {
  igraph_vector_t pairs, res;
  long int i, j, k, n;
  igraph_eit_t eit;

  igraph_vector_init(&res, 0);

  /* First, query the similarities for all the vertices to a matrix */
  igraph_similarity_dice(g, m, igraph_vss_all(), mode, loops);

  /* Second, query the similarities for all pairs using a pair vector */
  n = igraph_vcount(g);
  igraph_vector_init(&pairs, 0);
  for (i = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--) {
      igraph_vector_push_back(&pairs, i);
      igraph_vector_push_back(&pairs, j);
    }
  }
  igraph_similarity_dice_pairs(g, &res, &pairs, mode, loops);
  for (i = 0, k = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--, k++) {
      if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
        fprintf(stderr, "Dice similarity calculation for vertex pair %ld-%ld "
            "does not match the value in the full matrix (%.6f vs %.6f)\n",
            i, j, VECTOR(res)[k], MATRIX(*m, i, j));
        return 1;
      }
    }
  }
  igraph_vector_destroy(&pairs);

  /* Third, query the similarities for all edges */
  igraph_similarity_dice_es(g, &res, igraph_ess_all(IGRAPH_EDGEORDER_FROM), mode, loops);
  igraph_eit_create(g, igraph_ess_all(IGRAPH_EDGEORDER_FROM), &eit);
  k = 0;
  while (!IGRAPH_EIT_END(eit)) {
    long int eid = IGRAPH_EIT_GET(eit);
    i = IGRAPH_FROM(g, eid); j = IGRAPH_TO(g, eid);
    if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
      fprintf(stderr, "Dice similarity calculation for edge %ld-%ld (ID=%ld) "
          "does not match the value in the full matrix (%.6f vs %.6f)\n",
          i, j, eid, VECTOR(res)[k], MATRIX(*m, i, j));
      return 1;
    }
    IGRAPH_EIT_NEXT(eit);
    k++;
  }

  igraph_eit_destroy(&eit);

  igraph_vector_destroy(&res);

  return 0;
}

int main() {
  
  igraph_t g;
  igraph_matrix_t m;
  int ret;

  igraph_small(&g, 0, IGRAPH_DIRECTED, 
	       0,1, 2,1, 2,0, 3,0, 
	       -1);
  
  igraph_matrix_init(&m, 0, 0);

  ret = check_jaccard_all(&g, &m, IGRAPH_ALL, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 1;
  
  igraph_similarity_jaccard(&g, &m, igraph_vss_seq(1, 2), IGRAPH_ALL, 0);
  print_matrix(&m, stdout);
  
  ret = check_jaccard_all(&g, &m, IGRAPH_OUT, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 3;
  
  ret = check_jaccard_all(&g, &m, IGRAPH_IN, 0);
  print_matrix(&m, stdout);
  if (ret)
    return 4;
  
  ret = check_dice_all(&g, &m, IGRAPH_ALL, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 5;
  
  ret = check_dice_all(&g, &m, IGRAPH_OUT, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 6;

  ret = check_dice_all(&g, &m, IGRAPH_IN, 0);
  print_matrix(&m, stdout);
  if (ret)
    return 7;

  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_ALL);
  print_matrix(&m, stdout);
  
  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_OUT);
  print_matrix(&m, stdout);
  
  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_IN);
  print_matrix(&m, stdout);
  
  igraph_matrix_destroy(&m);
  igraph_destroy(&g);
  
  return 0;
}


9.9. igraph_similarity_inverse_log_weighted — Vertex similarity based on the inverse logarithm of vertex degrees.

int igraph_similarity_inverse_log_weighted(const igraph_t *graph,
  igraph_matrix_t *res, const igraph_vs_t vids, igraph_neimode_t mode);

The inverse log-weighted similarity of two vertices is the number of their common neighbors, weighted by the inverse logarithm of their degrees. It is based on the assumption that two vertices should be considered more similar if they share a low-degree common neighbor, since high-degree common neighbors are more likely to appear even by pure chance.

Isolated vertices will have zero similarity to any other vertex. Self-similarities are not calculated.

See the following paper for more details: Lada A. Adamic and Eytan Adar: Friends and neighbors on the Web. Social Networks, 25(3):211-230, 2003.

Arguments: 

graph:

The graph object to analyze.

res:

Pointer to a matrix, the result of the calculation will be stored here. The number of its rows is the same as the number of vertex ids in vids, the number of columns is the number of vertices in the graph.

vids:

The vertex ids of the vertices for which the calculation will be done.

mode:

The type of neighbors to be used for the calculation in directed graphs. Possible values:

IGRAPH_OUT

the outgoing edges will be considered for each node. Nodes will be weighted according to their in-degree.

IGRAPH_IN

the incoming edges will be considered for each node. Nodes will be weighted according to their out-degree.

IGRAPH_ALL

the directed graph is considered as an undirected one for the computation. Every node is weighted according to its undirected degree.

Returns: 

Error code: IGRAPH_EINVVID: invalid vertex id.

Time complexity: O(|V|d^2), |V| is the number of vertices in the graph, d is the (maximum) degree of the vertices in the graph.

Example 13.25.  File examples/simple/igraph_similarity.c

/* -*- mode: C -*-  */
/* vim:set ts=2 sw=2 sts=2 et: */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

void print_matrix(igraph_matrix_t *m, FILE *f) {
  long int i, j;
  for (i=0; i<igraph_matrix_nrow(m); i++) {
    for (j=0; j<igraph_matrix_ncol(m); j++) {
      fprintf(f, " %.2f", MATRIX(*m, i, j));
    }
    fprintf(f, "\n");
  }
  fprintf(f, "==========\n");
}

int check_jaccard_all(const igraph_t* g, igraph_matrix_t* m,
		igraph_neimode_t mode, igraph_bool_t loops) {
  igraph_vector_t pairs, res;
  long int i, j, k, n;
  igraph_eit_t eit;

  igraph_vector_init(&res, 0);

  /* First, query the similarities for all the vertices to a matrix */
  igraph_similarity_jaccard(g, m, igraph_vss_all(), mode, loops);

  /* Second, query the similarities for all pairs using a pair vector */
  n = igraph_vcount(g);
  igraph_vector_init(&pairs, 0);
  for (i = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--) {
      igraph_vector_push_back(&pairs, i);
      igraph_vector_push_back(&pairs, j);
    }
  }
  igraph_similarity_jaccard_pairs(g, &res, &pairs, mode, loops);
  for (i = 0, k = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--, k++) {
      if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
        fprintf(stderr, "Jaccard similarity calculation for vertex pair %ld-%ld "
            "does not match the value in the full matrix (%.6f vs %.6f)\n",
            i, j, VECTOR(res)[k], MATRIX(*m, i, j));
        return 1;
      }
    }
  }
  igraph_vector_destroy(&pairs);

  /* Third, query the similarities for all edges */
  igraph_similarity_jaccard_es(g, &res, igraph_ess_all(IGRAPH_EDGEORDER_FROM), mode, loops);
  igraph_eit_create(g, igraph_ess_all(IGRAPH_EDGEORDER_FROM), &eit);
  k = 0;
  while (!IGRAPH_EIT_END(eit)) {
    long int eid = IGRAPH_EIT_GET(eit);
    i = IGRAPH_FROM(g, eid); j = IGRAPH_TO(g, eid);
    if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
      fprintf(stderr, "Jaccard similarity calculation for edge %ld-%ld (ID=%ld) "
          "does not match the value in the full matrix (%.6f vs %.6f)\n",
          i, j, eid, VECTOR(res)[k], MATRIX(*m, i, j));
      return 1;
    }
    IGRAPH_EIT_NEXT(eit);
    k++;
  }

  igraph_eit_destroy(&eit);

  igraph_vector_destroy(&res);

  return 0;
}

int check_dice_all(const igraph_t* g, igraph_matrix_t* m,
		igraph_neimode_t mode, igraph_bool_t loops) {
  igraph_vector_t pairs, res;
  long int i, j, k, n;
  igraph_eit_t eit;

  igraph_vector_init(&res, 0);

  /* First, query the similarities for all the vertices to a matrix */
  igraph_similarity_dice(g, m, igraph_vss_all(), mode, loops);

  /* Second, query the similarities for all pairs using a pair vector */
  n = igraph_vcount(g);
  igraph_vector_init(&pairs, 0);
  for (i = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--) {
      igraph_vector_push_back(&pairs, i);
      igraph_vector_push_back(&pairs, j);
    }
  }
  igraph_similarity_dice_pairs(g, &res, &pairs, mode, loops);
  for (i = 0, k = 0; i < n; i++) {
    for (j = n-1; j >= 0; j--, k++) {
      if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
        fprintf(stderr, "Dice similarity calculation for vertex pair %ld-%ld "
            "does not match the value in the full matrix (%.6f vs %.6f)\n",
            i, j, VECTOR(res)[k], MATRIX(*m, i, j));
        return 1;
      }
    }
  }
  igraph_vector_destroy(&pairs);

  /* Third, query the similarities for all edges */
  igraph_similarity_dice_es(g, &res, igraph_ess_all(IGRAPH_EDGEORDER_FROM), mode, loops);
  igraph_eit_create(g, igraph_ess_all(IGRAPH_EDGEORDER_FROM), &eit);
  k = 0;
  while (!IGRAPH_EIT_END(eit)) {
    long int eid = IGRAPH_EIT_GET(eit);
    i = IGRAPH_FROM(g, eid); j = IGRAPH_TO(g, eid);
    if (fabs(VECTOR(res)[k] - MATRIX(*m, i, j)) > 1e-6) {
      fprintf(stderr, "Dice similarity calculation for edge %ld-%ld (ID=%ld) "
          "does not match the value in the full matrix (%.6f vs %.6f)\n",
          i, j, eid, VECTOR(res)[k], MATRIX(*m, i, j));
      return 1;
    }
    IGRAPH_EIT_NEXT(eit);
    k++;
  }

  igraph_eit_destroy(&eit);

  igraph_vector_destroy(&res);

  return 0;
}

int main() {
  
  igraph_t g;
  igraph_matrix_t m;
  int ret;

  igraph_small(&g, 0, IGRAPH_DIRECTED, 
	       0,1, 2,1, 2,0, 3,0, 
	       -1);
  
  igraph_matrix_init(&m, 0, 0);

  ret = check_jaccard_all(&g, &m, IGRAPH_ALL, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 1;
  
  igraph_similarity_jaccard(&g, &m, igraph_vss_seq(1, 2), IGRAPH_ALL, 0);
  print_matrix(&m, stdout);
  
  ret = check_jaccard_all(&g, &m, IGRAPH_OUT, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 3;
  
  ret = check_jaccard_all(&g, &m, IGRAPH_IN, 0);
  print_matrix(&m, stdout);
  if (ret)
    return 4;
  
  ret = check_dice_all(&g, &m, IGRAPH_ALL, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 5;
  
  ret = check_dice_all(&g, &m, IGRAPH_OUT, 1);
  print_matrix(&m, stdout);
  if (ret)
    return 6;

  ret = check_dice_all(&g, &m, IGRAPH_IN, 0);
  print_matrix(&m, stdout);
  if (ret)
    return 7;

  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_ALL);
  print_matrix(&m, stdout);
  
  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_OUT);
  print_matrix(&m, stdout);
  
  igraph_similarity_inverse_log_weighted(&g, &m, igraph_vss_all(), IGRAPH_IN);
  print_matrix(&m, stdout);
  
  igraph_matrix_destroy(&m);
  igraph_destroy(&g);
  
  return 0;
}


10. Spanning Trees

10.1. igraph_minimum_spanning_tree — Calculates one minimum spanning tree of a graph.

int igraph_minimum_spanning_tree(const igraph_t* graph,
    igraph_vector_t* res, const igraph_vector_t* weights);

If the graph has more minimum spanning trees (this is always the case, except if it is a forest) this implementation returns only the same one.

Directed graphs are considered as undirected for this computation.

If the graph is not connected then its minimum spanning forest is returned. This is the set of the minimum spanning trees of each component.

Arguments: 

graph:

The graph object.

res:

An initialized vector, the IDs of the edges that constitute a spanning tree will be returned here. Use igraph_subgraph_edges() to extract the spanning tree as a separate graph object.

weights:

A vector containing the weights of the edges in the same order as the simple edge iterator visits them (i.e. in increasing order of edge IDs).

Returns: 

Error code: IGRAPH_ENOMEM, not enough memory for temporary data.

Time complexity: O(|V|+|E|) for the unweighted case, O(|E| log |V|) for the weighted case. |V| is the number of vertices, |E| the number of edges in the graph.

See also: 

igraph_minimum_spanning_tree_unweighted() and igraph_minimum_spanning_tree_prim() if you only need the tree as a separate graph object.

Example 13.26.  File examples/simple/igraph_minimum_spanning_tree.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

int main() {
  
  igraph_t g, tree;
  igraph_vector_t eb, edges;
  long int i;
  
  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 
	       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,  8,  2,  9,  2, 13,  2, 27,
	       2, 28,  2, 32,  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, 29,
	       23, 32, 23, 33, 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,
	       -1);
  
  igraph_vector_init(&eb, igraph_ecount(&g));
  igraph_edge_betweenness(&g, &eb, IGRAPH_UNDIRECTED, /*weights=*/ 0);
  for (i=0; i<igraph_vector_size(&eb); i++) {
    VECTOR(eb)[i] = -VECTOR(eb)[i];
  }

  igraph_minimum_spanning_tree_prim(&g, &tree, &eb);
  igraph_write_graph_edgelist(&tree, stdout);

  igraph_vector_init(&edges, 0);
  igraph_minimum_spanning_tree(&g, &edges, &eb);
  igraph_vector_print(&edges);
  igraph_vector_destroy(&edges);

  igraph_destroy(&tree);
  igraph_destroy(&g);
  igraph_vector_destroy(&eb);
  
  return 0;
}


10.2. igraph_minimum_spanning_tree_unweighted — Calculates one minimum spanning tree of an unweighted graph.

int igraph_minimum_spanning_tree_unweighted(const igraph_t *graph, 
					    igraph_t *mst);

If the graph has more minimum spanning trees (this is always the case, except if it is a forest) this implementation returns only the same one.

Directed graphs are considered as undirected for this computation.

If the graph is not connected then its minimum spanning forest is returned. This is the set of the minimum spanning trees of each component.

Arguments: 

graph:

The graph object.

mst:

The minimum spanning tree, another graph object. Do not initialize this object before passing it to this function, but be sure to call igraph_destroy() on it if you don't need it any more.

Returns: 

Error code: IGRAPH_ENOMEM, not enough memory for temporary data.

Time complexity: O(|V|+|E|), |V| is the number of vertices, |E| the number of edges in the graph.

See also: 

igraph_minimum_spanning_tree_prim() for weighted graphs, igraph_minimum_spanning_tree() if you need the IDs of the edges that constitute the spanning tree.

10.3. igraph_minimum_spanning_tree_prim — Calculates one minimum spanning tree of a weighted graph.

int igraph_minimum_spanning_tree_prim(const igraph_t *graph, igraph_t *mst,
				      const igraph_vector_t *weights);

This function uses Prim's method for carrying out the computation, see Prim, R.C.: Shortest connection networks and some generalizations, Bell System Technical Journal, Vol. 36, 1957, 1389--1401.

If the graph has more than one minimum spanning tree, the current implementation returns always the same one.

Directed graphs are considered as undirected for this computation.

If the graph is not connected then its minimum spanning forest is returned. This is the set of the minimum spanning trees of each component.

Arguments: 

graph:

The graph object.

mst:

The result of the computation, a graph object containing the minimum spanning tree of the graph. Do not initialize this object before passing it to this function, but be sure to call igraph_destroy() on it if you don't need it any more.

weights:

A vector containing the weights of the edges in the same order as the simple edge iterator visits them (i.e. in increasing order of edge IDs).

Returns: 

Error code: IGRAPH_ENOMEM, not enough memory. IGRAPH_EINVAL, length of weight vector does not match number of edges.

Time complexity: O(|E| log |V|), |V| is the number of vertices, |E| the number of edges in the graph.

See also: 

igraph_minimum_spanning_tree_unweighted() for unweighted graphs, igraph_minimum_spanning_tree() if you need the IDs of the edges that constitute the spanning tree.

Example 13.27.  File examples/simple/igraph_minimum_spanning_tree.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

int main() {
  
  igraph_t g, tree;
  igraph_vector_t eb, edges;
  long int i;
  
  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 
	       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,  8,  2,  9,  2, 13,  2, 27,
	       2, 28,  2, 32,  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, 29,
	       23, 32, 23, 33, 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,
	       -1);
  
  igraph_vector_init(&eb, igraph_ecount(&g));
  igraph_edge_betweenness(&g, &eb, IGRAPH_UNDIRECTED, /*weights=*/ 0);
  for (i=0; i<igraph_vector_size(&eb); i++) {
    VECTOR(eb)[i] = -VECTOR(eb)[i];
  }

  igraph_minimum_spanning_tree_prim(&g, &tree, &eb);
  igraph_write_graph_edgelist(&tree, stdout);

  igraph_vector_init(&edges, 0);
  igraph_minimum_spanning_tree(&g, &edges, &eb);
  igraph_vector_print(&edges);
  igraph_vector_destroy(&edges);

  igraph_destroy(&tree);
  igraph_destroy(&g);
  igraph_vector_destroy(&eb);
  
  return 0;
}


11. Transitivity or Clustering Coefficient

11.1. igraph_transitivity_undirected — Calculates the transitivity (clustering coefficient) of a graph.

int igraph_transitivity_undirected(const igraph_t *graph,
				   igraph_real_t *res,
				   igraph_transitivity_mode_t mode);

The transitivity measures the probability that two neighbors of a vertex are connected. More precisely, this is the ratio of the triangles and connected triples in the graph, the result is a single real number. Directed graphs are considered as undirected ones.

Note that this measure is different from the local transitivity measure (see igraph_transitivity_local_undirected() ) as it calculates a single value for the whole graph. See the following reference for more details:

S. Wasserman and K. Faust: Social Network Analysis: Methods and Applications. Cambridge: Cambridge University Press, 1994.

Clustering coefficient is an alternative name for transitivity.

Arguments: 

graph:

The graph object.

res:

Pointer to a real variable, the result will be stored here.

mode:

Defines how to treat graphs with no connected triples. IGRAPH_TRANSITIVITY_NAN returns NaN in this case, IGRAPH_TRANSITIVITY_ZERO returns zero.

Returns: 

Error code: IGRAPH_ENOMEM: not enough memory for temporary data.

See also: 

Time complexity: O(|V|*d^2), |V| is the number of vertices in the graph, d is the average node degree.

Example 13.28.  File examples/simple/igraph_transitivity.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

int main() {
  
  igraph_t g;
  igraph_real_t res;

  /* Trivial cases */

  igraph_ring(&g, 100, IGRAPH_UNDIRECTED, 0, 0);
  igraph_transitivity_undirected(&g, &res, IGRAPH_TRANSITIVITY_NAN);
  igraph_destroy(&g);

  if (res != 0) {
    return 1;
  }

  igraph_full(&g, 20, IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS);
  igraph_transitivity_undirected(&g, &res, IGRAPH_TRANSITIVITY_NAN);
  igraph_destroy(&g);
  
  if (res != 1) {
    return 2;
  }

  /* Degenerate cases */
  igraph_small(&g, 0, IGRAPH_UNDIRECTED,
		  0,  1,  2,  3,  4,  5, -1);
  igraph_transitivity_undirected(&g, &res, IGRAPH_TRANSITIVITY_NAN);
  /* res should be NaN here, any comparison must return false */
  if (res == 0 || res > 0 || res < 0) {
	return 4;
  }
  igraph_transitivity_undirected(&g, &res, IGRAPH_TRANSITIVITY_ZERO);
  /* res should be zero here */
  if (res) {
	return 5;
  }
  igraph_destroy(&g);

  /* Zachary Karate club */

  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 
	       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,  8,  2,  9,  2, 13,  2, 27,
	       2, 28,  2, 32,  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, 29,
	       23, 32, 23, 33, 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,
	       -1);  
  
  igraph_transitivity_undirected(&g, &res, IGRAPH_TRANSITIVITY_NAN);
  igraph_destroy(&g);
  
  if (res != 0.2556818181818181767717) {
    fprintf(stderr, "%f != %f\n", res, 0.2556818181818181767717);
    return 3;
  }

  return 0;
}


11.2. igraph_transitivity_local_undirected — Calculates the local transitivity (clustering coefficient) of a graph.

int igraph_transitivity_local_undirected(const igraph_t *graph,
					 igraph_vector_t *res,
					 const igraph_vs_t vids,
					 igraph_transitivity_mode_t mode);

The transitivity measures the probability that two neighbors of a vertex are connected. In case of the local transitivity, this probability is calculated separately for each vertex.

Note that this measure is different from the global transitivity measure (see igraph_transitivity_undirected() ) as it calculates a transitivity value for each vertex individually. See the following reference for more details:

D. J. Watts and S. Strogatz: Collective dynamics of small-world networks. Nature 393(6684):440-442 (1998).

Clustering coefficient is an alternative name for transitivity.

Arguments: 

graph:

The input graph, it can be directed but direction of the edges will be ignored.

res:

Pointer to an initialized vector, the result will be stored here. It will be resized as needed.

vids:

Vertex set, the vertices for which the local transitivity will be calculated.

mode:

Defines how to treat vertices with degree less than two. IGRAPH_TRANSITIVITY_NAN returns NaN for these vertices, IGRAPH_TRANSITIVITY_ZERO returns zero.

Returns: 

Error code.

See also: 

Time complexity: O(n*d^2), n is the number of vertices for which the transitivity is calculated, d is the average vertex degree.

11.3. igraph_transitivity_avglocal_undirected — Average local transitivity (clustering coefficient).

int igraph_transitivity_avglocal_undirected(const igraph_t *graph,
					    igraph_real_t *res,
					    igraph_transitivity_mode_t mode);

The transitivity measures the probability that two neighbors of a vertex are connected. In case of the average local transitivity, this probability is calculated for each vertex and then the average is taken. Vertices with less than two neighbors require special treatment, they will either be left out from the calculation or they will be considered as having zero transitivity, depending on the mode argument.

Note that this measure is different from the global transitivity measure (see igraph_transitivity_undirected() ) as it simply takes the average local transitivity across the whole network. See the following reference for more details:

D. J. Watts and S. Strogatz: Collective dynamics of small-world networks. Nature 393(6684):440-442 (1998).

Clustering coefficient is an alternative name for transitivity.

Arguments: 

graph:

The input graph, directed graphs are considered as undirected ones.

res:

Pointer to a real variable, the result will be stored here.

mode:

Defines how to treat vertices with degree less than two. IGRAPH_TRANSITIVITY_NAN leaves them out from averaging, IGRAPH_TRANSITIVITY_ZERO includes them with zero transitivity. The result will be NaN if the mode is IGRAPH_TRANSITIVITY_NAN and there are no vertices with more than one neighbor.

Returns: 

Error code.

See also: 

Time complexity: O(|V|*d^2), |V| is the number of vertices in the graph and d is the average degree.

11.4. igraph_transitivity_barrat — Weighted transitivity, as defined by A. Barrat.

int igraph_transitivity_barrat(const igraph_t *graph,
			       igraph_vector_t *res,
			       const igraph_vs_t vids,
			       const igraph_vector_t *weights,
				   igraph_transitivity_mode_t mode);

This is a local transitivity, i.e. a vertex-level index. For a given vertex i, from all triangles in which it participates we consider the weight of the edges incident on i. The transitivity is the sum of these weights divided by twice the strength of the vertex (see igraph_strength()) and the degree of the vertex minus one. See Alain Barrat, Marc Barthelemy, Romualdo Pastor-Satorras, Alessandro Vespignani: The architecture of complex weighted networks, Proc. Natl. Acad. Sci. USA 101, 3747 (2004) at http://arxiv.org/abs/cond-mat/0311416 for the exact formula.

Arguments: 

graph:

The input graph, edge directions are ignored for directed graphs. Note that the function does NOT work for non-simple graphs.

res:

Pointer to an initialized vector, the result will be stored here. It will be resized as needed.

vids:

The vertices for which the calculation is performed.

weights:

Edge weights. If this is a null pointer, then a warning is given and igraph_transitivity_local_undirected() is called.

mode:

Defines how to treat vertices with zero strength. IGRAPH_TRANSITIVITY_NAN says that the transitivity of these vertices is NaN, IGRAPH_TRANSITIVITY_ZERO says it is zero.

Returns: 

Error code.

Time complexity: O(|V|*d^2), |V| is the number of vertices in the graph, d is the average node degree.

See also: 

12. Directedness conversion

12.1. igraph_to_directed — Convert an undirected graph to a directed one

int igraph_to_directed(igraph_t *graph,
		       igraph_to_directed_t mode);

If the supplied graph is directed, this function does nothing.

Arguments: 

graph:

The graph object to convert.

mode:

Constant, specifies the details of how exactly the conversion is done. Possible values: IGRAPH_TO_DIRECTED_ARBITRARY: the number of edges in the graph stays the same, an arbitrarily directed edge is created for each undirected edge; IGRAPH_TO_DIRECTED_MUTUAL: two directed edges are created for each undirected edge, one in each direction.

Returns: 

Error code.

Time complexity: O(|V|+|E|), the number of vertices plus the number of edges.

12.2. igraph_to_undirected — Convert a directed graph to an undirected one.

int igraph_to_undirected(igraph_t *graph,
			 igraph_to_undirected_t mode,
			 const igraph_attribute_combination_t *edge_comb);

If the supplied graph is undirected, this function does nothing.

Arguments: 

graph:

The graph object to convert.

mode:

Constant, specifies the details of how exactly the conversion is done. Possible values: IGRAPH_TO_UNDIRECTED_EACH: the number of edges remains constant, an undirected edge is created for each directed one, this version might create graphs with multiple edges; IGRAPH_TO_UNDIRECTED_COLLAPSE: one undirected edge will be created for each pair of vertices which are connected with at least one directed edge, no multiple edges will be created. IGRAPH_TO_UNDIRECTED_MUTUAL creates an undirected edge for each pair of mutual edges in the directed graph. Non-mutual edges are lost. This mode might create multiple edges.

edge_comb:

What to do with the edge attributes. See the igraph manual section about attributes for details.

Returns: 

Error code.

Time complexity: O(|V|+|E|), the number of vertices plus the number of edges.

Example 13.29.  File examples/simple/igraph_to_undirected.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

int main() {
  
  igraph_vector_t v;
  igraph_t g;
  
  igraph_vector_init_int(&v, 2, 5, 5);
  igraph_lattice(&g, &v, 1, IGRAPH_DIRECTED, 1 /*mutual*/, 0 /*circular*/);
  igraph_to_undirected(&g, IGRAPH_TO_UNDIRECTED_COLLAPSE, 
		       /*edge_comb=*/ 0);
  igraph_write_graph_edgelist(&g, stdout);

  igraph_destroy(&g);
  igraph_vector_destroy(&v);

  printf("---\n");

  igraph_small(&g, 10, IGRAPH_DIRECTED, 
	       0,1, 2,1, 2,3, 2,3, 4,3, 4,3,
	       5,6, 6,5, 6,7, 6,7, 7,6, 7,8, 7,8, 8,7, 8,7, 8,8, 9,9, 9,9,
	       -1);
  igraph_to_undirected(&g, IGRAPH_TO_UNDIRECTED_MUTUAL,
		       /*edge_comb=*/ 0);
  igraph_write_graph_edgelist(&g, stdout);
  igraph_destroy(&g);
  
  return 0;
}


13. Spectral properties

13.1. igraph_laplacian — Returns the Laplacian matrix of a graph

int igraph_laplacian(const igraph_t *graph, igraph_matrix_t *res,
		     igraph_sparsemat_t *sparseres,
                     igraph_bool_t normalized, 
                     const igraph_vector_t *weights);

The graph Laplacian matrix is similar to an adjacency matrix but contains -1's instead of 1's and the vertex degrees are included in the diagonal. So the result for edge i--j is -1 if i!=j and is equal to the degree of vertex i if i==j. igraph_laplacian will work on a directed graph; in this case, the diagonal will contain the out-degrees. Loop edges will be ignored.

The normalized version of the Laplacian matrix has 1 in the diagonal and -1/sqrt(d[i]d[j]) if there is an edge from i to j.

The first version of this function was written by Vincent Matossian.

Arguments: 

graph:

Pointer to the graph to convert.

res:

Pointer to an initialized matrix object, the result is stored here. It will be resized if needed. If it is a null pointer, then it is ignored. At least one of res and sparseres must be a non-null pointer.

sparseres:

Pointer to an initialized sparse matrix object, the result is stored here, if it is not a null pointer. At least one of res and sparseres must be a non-null pointer.

normalized:

Whether to create a normalized Laplacian matrix.

weights:

An optional vector containing edge weights, to calculate the weighted Laplacian matrix. Set it to a null pointer to calculate the unweighted Laplacian.

Returns: 

Error code.

Time complexity: O(|V||V|), |V| is the number of vertices in the graph.

Example 13.30.  File examples/simple/igraph_laplacian.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

igraph_bool_t check_laplacian(igraph_t* graph, igraph_matrix_t* matrix, igraph_vector_t* w) {
  igraph_vector_t vec, res;
  long int i, j;

  igraph_vector_init(&vec, 0);
  igraph_vector_init(&res, igraph_vcount(graph));

  if (w)
    igraph_strength(graph, &vec, igraph_vss_all(), IGRAPH_OUT, IGRAPH_NO_LOOPS, w);
  else
    igraph_degree(graph, &vec, igraph_vss_all(), IGRAPH_OUT, IGRAPH_NO_LOOPS);

  for (i = 0; i < igraph_vcount(graph); i++) {
    VECTOR(vec)[i] = sqrt(VECTOR(vec)[i]);
  }

  for (i = 0; i < igraph_vcount(graph); i++) {
    for (j = 0; j < igraph_vcount(graph); j++) {
      VECTOR(res)[i] += MATRIX(*matrix, i, j) * VECTOR(vec)[j];
    }
  }

  if (igraph_vector_min(&res) > 1e-7) {
    printf("Invalid Laplacian matrix:\n");
    igraph_matrix_print(matrix);
    return 0;
  }

  igraph_vector_destroy(&vec);
  igraph_vector_destroy(&res);

  return 1;
}

int test_unnormalized_laplacian(igraph_vector_t* w, igraph_bool_t dir) {
  igraph_t g;
  igraph_matrix_t m, m2;
  igraph_sparsemat_t sm;
  igraph_vector_t vec, *weights = 0;
  igraph_matrix_init(&m, 1, 1);
  igraph_sparsemat_init(&sm, 0, 0, 0);

  if (w) {
    weights = (igraph_vector_t*)calloc(1, sizeof(igraph_vector_t));
    igraph_vector_copy(weights, w);
  }

  /* No loop or multiple edges */
  igraph_ring(&g, 5, dir, 0, 1);
  igraph_laplacian(&g, &m, &sm, 0, weights);
  igraph_matrix_init(&m2, 0, 0);
  igraph_sparsemat_as_matrix(&m2, &sm);
  if (!igraph_matrix_all_e_tol(&m, &m2, 0)) { 
    return 41;
  }
  igraph_matrix_destroy(&m2);
  igraph_matrix_print(&m);
  printf("===\n");

  /* Add some loop edges */
  igraph_vector_init_real(&vec, 4, 1.0, 1.0, 2.0, 2.0);
  igraph_add_edges(&g, &vec, 0);
  igraph_vector_destroy(&vec);
  if (weights) {
    igraph_vector_push_back(weights, 2);
    igraph_vector_push_back(weights, 2);
  }

  igraph_laplacian(&g, &m, &sm, 0, weights);
  igraph_matrix_init(&m2, 0, 0);
  igraph_sparsemat_as_matrix(&m2, &sm);
  if (!igraph_matrix_all_e_tol(&m, &m2, 0)) { 
    return 42;
  }
  igraph_matrix_destroy(&m2);
  igraph_matrix_print(&m);
  printf("===\n");

  /* Duplicate some edges */
  igraph_vector_init_real(&vec, 4, 1.0, 2.0, 3.0, 4.0);
  igraph_add_edges(&g, &vec, 0);
  igraph_vector_destroy(&vec);
  if (weights) {
    igraph_vector_push_back(weights, 3);
    igraph_vector_push_back(weights, 3);
  }

  igraph_laplacian(&g, &m, &sm, 0, weights);
  igraph_matrix_init(&m2, 0, 0);
  igraph_sparsemat_as_matrix(&m2, &sm);
  if (!igraph_matrix_all_e_tol(&m, &m2, 0)) { 
    return 43;
  }
  igraph_matrix_destroy(&m2);
  igraph_matrix_print(&m);

  igraph_destroy(&g);

  igraph_matrix_destroy(&m);
  if (weights) {
    igraph_vector_destroy(weights); free(weights);
  }

  return 0;
}

int test_normalized_laplacian(igraph_vector_t *w, igraph_bool_t dir) {
  igraph_t g;
  igraph_matrix_t m, m2;
  igraph_sparsemat_t sm;
  igraph_vector_t vec, *weights = 0;
  igraph_bool_t ok = 1;
  igraph_matrix_init(&m, 1, 1);
  igraph_sparsemat_init(&sm, 0, 0, 0);

  if (w) {
    weights = (igraph_vector_t*)calloc(1, sizeof(igraph_vector_t));
    igraph_vector_copy(weights, w);
  }

  /* Undirected graph, no loop or multiple edges */
  igraph_ring(&g, 5, dir, 0, 1);
  igraph_laplacian(&g, &m, &sm, 1, weights);
  igraph_matrix_init(&m2, 0, 0);
  igraph_sparsemat_as_matrix(&m2, &sm);
  if (!igraph_matrix_all_e_tol(&m, &m2, 0)) { 
    return 44;
  }
  igraph_matrix_destroy(&m2);
  ok = ok && check_laplacian(&g, &m, weights);

  /* Add some loop edges */
  igraph_vector_init_real(&vec, 4, 1.0, 1.0, 2.0, 2.0);
  igraph_add_edges(&g, &vec, 0);
  igraph_vector_destroy(&vec);
  if (weights) {
    igraph_vector_push_back(weights, 2);
    igraph_vector_push_back(weights, 2);
  }

  igraph_laplacian(&g, &m, &sm, 1, weights);
  igraph_matrix_init(&m2, 0, 0);
  igraph_sparsemat_as_matrix(&m2, &sm);
  if (!igraph_matrix_all_e_tol(&m, &m2, 0)) { 
    return 45;
  }
  igraph_matrix_destroy(&m2);
  ok = ok && check_laplacian(&g, &m, weights);

  /* Duplicate some edges */
  igraph_vector_init_real(&vec, 4, 1.0, 2.0, 3.0, 4.0);
  igraph_add_edges(&g, &vec, 0);
  igraph_vector_destroy(&vec);
  if (weights) {
    igraph_vector_push_back(weights, 3);
    igraph_vector_push_back(weights, 3);
  }

  igraph_laplacian(&g, &m, &sm, 1, weights);
  igraph_matrix_init(&m2, 0, 0);
  igraph_sparsemat_as_matrix(&m2, &sm);
  if (!igraph_matrix_all_e_tol(&m, &m2, 0)) { 
    return 46;
  }
  igraph_matrix_destroy(&m2);
  ok = ok && check_laplacian(&g, &m, weights);

  igraph_destroy(&g);

  igraph_matrix_destroy(&m);
  if (weights) {
    igraph_vector_destroy(weights); free(weights);
  }

  if (ok)
    printf("OK\n");

  return !ok;
}

int main() {
  int res;
  int i;
  igraph_vector_t weights;

  igraph_vector_init_real(&weights, 5, 1.0, 2.0, 3.0, 4.0, 5.0);

  for (i = 0; i < 8; i++) {
    igraph_bool_t is_normalized = i / 4;
    igraph_vector_t* v = ((i & 2) / 2 ? &weights : 0);
    igraph_bool_t dir = (i % 2 ? IGRAPH_DIRECTED : IGRAPH_UNDIRECTED);

    printf("=== %sormalized, %sweighted, %sdirected\n",
      (is_normalized ? "N" : "Unn"),
      (v != 0 ? "" : "un"),
      (dir == IGRAPH_DIRECTED ? "" : "un")
    );

    if (is_normalized)
      res = test_normalized_laplacian(v, dir);
    else
      res = test_unnormalized_laplacian(v, dir);

    if (res)
      return i+1;
  }

  igraph_vector_destroy(&weights);

  return 0;
}


14. Non-simple graphs: multiple and loop edges

14.1. igraph_is_simple — Decides whether the input graph is a simple graph.

int igraph_is_simple(const igraph_t *graph, igraph_bool_t *res);

A graph is a simple graph if it does not contain loop edges and multiple edges.

Arguments: 

graph:

The input graph.

res:

Pointer to a boolean constant, the result is stored here.

Returns: 

Error code.

See also: 

igraph_is_loop() and igraph_is_multiple() to find the loops and multiple edges, igraph_simplify() to get rid of them, or igraph_has_multiple() to decide whether there is at least one multiple edge.

Time complexity: O(|V|+|E|).

14.2. igraph_is_loop — Find the loop edges in a graph.

int igraph_is_loop(const igraph_t *graph, igraph_vector_bool_t *res, 
		   igraph_es_t es);

A loop edge is an edge from a vertex to itself.

Arguments: 

graph:

The input graph.

res:

Pointer to an initialized boolean vector for storing the result, it will be resized as needed.

es:

The edges to check, for all edges supply igraph_ess_all() here.

Returns: 

Error code.

See also: 

igraph_simplify() to get rid of loop edges.

Time complexity: O(e), the number of edges to check.

Example 13.31.  File examples/simple/igraph_is_loop.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

void print_vector(igraph_vector_bool_t *v, FILE *f) {
  long int i;
  for (i=0; i<igraph_vector_bool_size(v); i++) {
    fprintf(f, " %i", (int) VECTOR(*v)[i]);
  }
  fprintf(f, "\n");
}

int main() {
  
  igraph_t graph;
  igraph_vector_bool_t v;
  
  igraph_vector_bool_init(&v, 0);

  igraph_small(&graph, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,1, 0,1, 1,0, 3,4, 11,10, -1);
  igraph_is_loop(&graph, &v, igraph_ess_all(IGRAPH_EDGEORDER_ID));
  print_vector(&v, stdout);
  igraph_destroy(&graph);
  
  igraph_small(&graph, 0, IGRAPH_UNDIRECTED,
	       0,0, 1,1, 2,2, 2,3, 2,4, 2,5, 2,6, 2,2, 0,0, -1);
  igraph_is_loop(&graph, &v, igraph_ess_all(IGRAPH_EDGEORDER_ID));
  print_vector(&v, stdout);
  igraph_destroy(&graph);

  igraph_vector_bool_destroy(&v);
  
  return 0;
}


14.3. igraph_is_multiple — Find the multiple edges in a graph.

int igraph_is_multiple(const igraph_t *graph, igraph_vector_bool_t *res, 
		       igraph_es_t es);

An edge is a multiple edge if there is another edge with the same head and tail vertices in the graph.

Note that this function returns true only for the second or more appearances of the multiple edges.

Arguments: 

graph:

The input graph.

res:

Pointer to a boolean vector, the result will be stored here. It will be resized as needed.

es:

The edges to check. Supply igraph_ess_all() if you want to check all edges.

Returns: 

Error code.

See also: 

Time complexity: O(e*d), e is the number of edges to check and d is the average degree (out-degree in directed graphs) of the vertices at the tail of the edges.

Example 13.32.  File examples/simple/igraph_is_multiple.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

void print_vector(igraph_vector_bool_t *v, FILE *f) {
  long int i;
  for (i=0; i<igraph_vector_bool_size(v); i++) {
    fprintf(f, " %i", (int) VECTOR(*v)[i]);
  }
  fprintf(f, "\n");
}

int main() {
  
  igraph_t graph;
  igraph_vector_bool_t v;
  
  igraph_vector_bool_init(&v, 0);

  igraph_small(&graph, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,1, 0,1, 1,0, 3,4, 11,10, -1);
  igraph_is_multiple(&graph, &v, igraph_ess_all(IGRAPH_EDGEORDER_ID));
  print_vector(&v, stdout);
  igraph_destroy(&graph);
  
  igraph_small(&graph, 0, IGRAPH_UNDIRECTED,
	       0,0, 1,2, 1,1, 2,2, 2,1, 2,3, 2,4, 
	       2,5, 2,6, 2,2, 3,2, 0,0, 6,2, 2,2, 0,0, -1);
  igraph_is_multiple(&graph, &v, igraph_ess_all(IGRAPH_EDGEORDER_ID));
  print_vector(&v, stdout);
  igraph_destroy(&graph);

  igraph_vector_bool_destroy(&v);
  
  return 0;
}


14.4. igraph_has_multiple — Check whether the graph has at least one multiple edge.

int igraph_has_multiple(const igraph_t *graph, igraph_bool_t *res);

An edge is a multiple edge if there is another edge with the same head and tail vertices in the graph.

Arguments: 

graph:

The input graph.

res:

Pointer to a boolean variable, the result will be stored here.

Returns: 

Error code.

See also: 

Time complexity: O(e*d), e is the number of edges to check and d is the average degree (out-degree in directed graphs) of the vertices at the tail of the edges.

Example 13.33.  File examples/simple/igraph_has_multiple.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

void print_vector(igraph_vector_bool_t *v, FILE *f) {
  long int i;
  for (i=0; i<igraph_vector_bool_size(v); i++) {
    fprintf(f, " %i", (int) VECTOR(*v)[i]);
  }
  fprintf(f, "\n");
}

int main() {
  
  igraph_t graph;
  igraph_bool_t res;
  
  igraph_small(&graph, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,1, 0,1, 1,0, 3,4, 11,10, -1);
  igraph_has_multiple(&graph, &res);
  if (!res)
    return 1;
  igraph_destroy(&graph);
  
  igraph_small(&graph, 0, IGRAPH_UNDIRECTED,
	       0,0, 1,2, 1,1, 2,2, 2,1, 2,3, 2,4, 
	       2,5, 2,6, 2,2, 3,2, 0,0, 6,2, 2,2, 0,0, -1);
  igraph_has_multiple(&graph, &res);
  if (!res)
    return 2;
  igraph_destroy(&graph);

  igraph_small(&graph, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,1, 1,0, 3,4, 11,10, -1);
  igraph_has_multiple(&graph, &res);
  if (res)
    return 3;
  igraph_destroy(&graph);
  
  igraph_small(&graph, 0, IGRAPH_UNDIRECTED,
	       0,0, 1,2, 1,1, 2,2, 2,3, 2,4, 2,5, 2,6, 2,2, -1);
  igraph_has_multiple(&graph, &res);
  if (!res)
    return 4;
  igraph_destroy(&graph);

  igraph_small(&graph, 0, IGRAPH_UNDIRECTED,
	       0,0, 1,2, 1,1, 2,2, 2,3, 2,4, 2,5, 2,6, -1);
  igraph_has_multiple(&graph, &res);
  if (res)
    return 5;
  igraph_destroy(&graph);

  igraph_small(&graph, 0, IGRAPH_UNDIRECTED, 0,1, 0,1, 1,2, -1);
  igraph_has_multiple(&graph, &res);
  if (!res)
    return 6;
  igraph_destroy(&graph);

  igraph_small(&graph, 0, IGRAPH_UNDIRECTED, 0,0, 0,0, -1);
  igraph_has_multiple(&graph, &res);
  if (!res)
    return 7;
  igraph_destroy(&graph);

  return 0;
}


14.5. igraph_count_multiple — Count the number of appearances of the edges in a graph.

int igraph_count_multiple(const igraph_t *graph, igraph_vector_t *res, igraph_es_t es);

If the graph has no multiple edges then the result vector will be filled with ones. (An edge is a multiple edge if there is another edge with the same head and tail vertices in the graph.)

Arguments: 

graph:

The input graph.

res:

Pointer to a vector, the result will be stored here. It will be resized as needed.

es:

The edges to check. Supply igraph_ess_all() if you want to check all edges.

Returns: 

Error code.

See also: 

Time complexity: O(e*d), e is the number of edges to check and d is the average degree (out-degree in directed graphs) of the vertices at the tail of the edges.

14.6. igraph_simplify — Removes loop and/or multiple edges from the graph.

int igraph_simplify(igraph_t *graph, igraph_bool_t multiple, 
		    igraph_bool_t loops, 
		    const igraph_attribute_combination_t *edge_comb);

Arguments: 

graph:

The graph object.

multiple:

Logical, if true, multiple edges will be removed.

loops:

Logical, if true, loops (self edges) will be removed.

edge_comb:

What to do with the edge attributes. See the igraph manual section about attributes for details.

Returns: 

Error code: IGRAPH_ENOMEM if we are out of memory.

Time complexity: O(|V|+|E|).

Example 13.34.  File examples/simple/igraph_simplify.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

int main() {

  igraph_t g;

  /* Multiple edges */

  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,1, 0,1, 0,1, 0,1, 0,1, -1);
  igraph_simplify(&g, 1, 1, /*edge_comb=*/ 0);
  igraph_write_graph_edgelist(&g, stdout);
  igraph_destroy(&g);
  
  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 1,0, 0,1, 1,0, 0,1, 0,1, -1);
  igraph_simplify(&g, 1, 1, /*edge_comb=*/ 0);
  if (igraph_ecount(&g) != 1) {
    return 1;
  }
  igraph_destroy(&g);
  
  /* Loop edges*/
  
  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,0,1,1,2,2, 1,2, -1);
  igraph_simplify(&g, 1, 1, /*edge_comb=*/ 0);
  igraph_write_graph_edgelist(&g, stdout);
  igraph_destroy(&g);

  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 0,0,1,1,2,2, 1,2, -1); 
  igraph_simplify(&g, 1, 1, /*edge_comb=*/ 0);
  igraph_write_graph_edgelist(&g, stdout);
  igraph_destroy(&g);

  /* Loop & multiple edges */
  
  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,0,0,0,0,0,0,0, 1,2, -1);
  igraph_simplify(&g, 1 /* multiple */, 0 /* loop */, /*edge_comb=*/ 0);
  igraph_write_graph_edgelist(&g, stdout);
  igraph_destroy(&g);

  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 1,1,1,1,1,1,1,1, 2,3, -1); 
  igraph_simplify(&g, 1 /* multiple */, 0 /* loop */, /*edge_comb=*/ 0);
  igraph_write_graph_edgelist(&g, stdout);
  igraph_destroy(&g);

  igraph_small(&g, 0, IGRAPH_DIRECTED, 2,2,2,2,2,2, 3,2, -1);
  igraph_simplify(&g, 0 /* multiple */, 1 /* loop */, /*edge_comb=*/ 0);
  igraph_write_graph_edgelist(&g, stdout);
  igraph_destroy(&g);

  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 3,3,3,3, 3,4, -1);
  igraph_simplify(&g, 0 /* multiple */, 1 /* loop */, /*edge_comb=*/ 0);
  igraph_write_graph_edgelist(&g, stdout);
  igraph_destroy(&g);  

  igraph_small(&g, 0, IGRAPH_DIRECTED, 2,2,2,2,2,2,2,2, 3,2,3,2,3,2,3,2,3,2,-1);
  igraph_simplify(&g, 1, 1, /*edge_comb=*/ 0);
  igraph_write_graph_edgelist(&g, stdout);
  igraph_destroy(&g);

  igraph_small(&g, 0, IGRAPH_UNDIRECTED, 
	       2,2,2,2,2,2,2,2, 3,2,2,3,3,2,3,2,3,2,-1);
  igraph_simplify(&g, 1, 1, /*edge_comb=*/ 0);
  if (igraph_ecount(&g) != 1) { 
    return 2;
  }
  igraph_destroy(&g);

  return 0;
}


15. Mixing patterns

15.1. igraph_assortativity_nominal — Assortativity of a graph based on vertex categories

int igraph_assortativity_nominal(const igraph_t *graph, 
				 const igraph_vector_t *types,
				 igraph_real_t *res,
				 igraph_bool_t directed);

Assuming the vertices of the input graph belong to different categories, this function calculates the assortativity coefficient of the graph. The assortativity coefficient is between minus one and one and it is one if all connections stay within categories, it is minus one, if the network is perfectly disassortative. For a randomly connected network it is (asymptotically) zero.

See equation (2) in M. E. J. Newman: Mixing patterns in networks, Phys. Rev. E 67, 026126 (2003) (http://arxiv.org/abs/cond-mat/0209450) for the proper definition.

Arguments: 

graph:

The input graph, it can be directed or undirected.

types:

Vector giving the vertex types. They are assumed to be integer numbers, starting with zero.

res:

Pointer to a real variable, the result is stored here.

directed:

Boolean, it gives whether to consider edge directions in a directed graph. It is ignored for undirected graphs.

Returns: 

Error code.

Time complexity: O(|E|+t), |E| is the number of edges, t is the number of vertex types.

See also: 

igraph_assortativity if the vertex types are defines by numeric values (e.g. vertex degree), instead of categories.

Example 13.35.  File examples/simple/assortativity.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2009-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.h>
#include <stdio.h>

int main() {

  igraph_t g;
  FILE *karate, *neural;
  igraph_real_t res;
  igraph_vector_t types;
  igraph_vector_t degree, outdegree, indegree;

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

  karate=fopen("karate.gml", "r");
  igraph_read_graph_gml(&g, karate);
  fclose(karate);
  
  igraph_vector_init(&types, 0);
  igraph_degree(&g, &types, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);

  igraph_assortativity_nominal(&g, &types, &res, /*directed=*/ 0);
  printf("%.5f\n", res);
  
  igraph_destroy(&g);

  /*---------------------*/

  neural=fopen("celegansneural.gml", "r");
  igraph_read_graph_gml(&g, neural);
  fclose(neural);
  
  igraph_degree(&g, &types, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);

  igraph_assortativity_nominal(&g, &types, &res, /*directed=*/ 1);
  printf("%.5f\n", res);  
  igraph_assortativity_nominal(&g, &types, &res, /*directed=*/ 0);
  printf("%.5f\n", res);  

  igraph_destroy(&g);
  igraph_vector_destroy(&types);

  /*---------------------*/
  
  karate=fopen("karate.gml", "r");
  igraph_read_graph_gml(&g, karate);
  fclose(karate);
  
  igraph_vector_init(&degree, 0);
  igraph_degree(&g, &degree, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);
  igraph_vector_add_constant(&degree, -1);

  igraph_assortativity(&g, &degree, 0, &res, /*directed=*/ 0);
  printf("%.5f\n", res);
  
  igraph_destroy(&g);

  /*---------------------*/

  neural=fopen("celegansneural.gml", "r");
  igraph_read_graph_gml(&g, neural);
  fclose(neural);
  
  igraph_degree(&g, &degree, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);
  igraph_vector_add_constant(&degree, -1);

  igraph_assortativity(&g, &degree, 0, &res, /*directed=*/ 1);
  printf("%.5f\n", res);  
  igraph_assortativity(&g, &degree, 0, &res, /*directed=*/ 0);
  printf("%.5f\n", res);  

  igraph_vector_destroy(&degree);

  /*---------------------*/
  
  igraph_vector_init(&indegree, 0);
  igraph_vector_init(&outdegree, 0);
  igraph_degree(&g, &indegree, igraph_vss_all(), IGRAPH_IN, /*loops=*/ 1);
  igraph_degree(&g, &outdegree, igraph_vss_all(), IGRAPH_OUT, /*loops=*/ 1);
  igraph_vector_add_constant(&indegree, -1);
  igraph_vector_add_constant(&outdegree, -1);
  
  igraph_assortativity(&g, &outdegree, &indegree, &res, /*directed=*/ 1);
  printf("%.5f\n", res);

  igraph_vector_destroy(&indegree);
  igraph_vector_destroy(&outdegree);

  /*---------------------*/
  
  igraph_assortativity_degree(&g, &res, /*directed=*/ 1);
  printf("%.5f\n", res);

  igraph_destroy(&g);  

  /*---------------------*/

  karate=fopen("karate.gml", "r");
  igraph_read_graph_gml(&g, karate);
  fclose(karate);
  
  igraph_assortativity_degree(&g, &res, /*directed=*/ 1);
  printf("%.5f\n", res);
  
  igraph_destroy(&g);

  /*---------------------*/
  
  igraph_small(&g, sizeof(football_types)/sizeof(igraph_real_t), 
	       IGRAPH_UNDIRECTED,
	       0,1,2,3,0,4,4,5,3,5,2,6,6,7,7,8,8,9,0,9,4,9,5,10,10,11,5,11,
	       3,11,12,13,2,13,2,14,12,14,14,15,13,15,2,15,4,16,9,16,0,16,
	       16,17,12,17,12,18,18,19,17,20,20,21,8,21,7,21,9,22,7,22,21,
	       22,8,22,22,23,9,23,4,23,16,23,0,23,11,24,24,25,1,25,3,26,12,
	       26,14,26,26,27,17,27,1,27,17,27,4,28,11,28,24,28,19,29,29,
	       30,19,30,18,31,31,32,21,32,15,32,13,32,6,32,0,33,1,33,25,33,
	       19,33,31,34,26,34,12,34,18,34,34,35,0,35,29,35,19,35,30,35,
	       18,36,12,36,20,36,19,36,36,37,1,37,25,37,33,37,18,38,16,38,
	       28,38,26,38,14,38,12,38,38,39,6,39,32,39,13,39,15,39,7,40,3,
	       40,40,41,8,41,4,41,23,41,9,41,0,41,16,41,34,42,29,42,18,42,
	       26,42,42,43,36,43,26,43,31,43,38,43,12,43,14,43,19,44,35,44,
	       30,44,44,45,13,45,33,45,1,45,37,45,25,45,21,46,46,47,22,47,
	       6,47,15,47,2,47,39,47,32,47,44,48,48,49,32,49,46,49,30,50,
	       24,50,11,50,28,50,50,51,40,51,8,51,22,51,21,51,3,52,40,52,5,
	       52,52,53,25,53,48,53,49,53,46,53,39,54,31,54,38,54,14,54,34,
	       54,18,54,54,55,31,55,6,55,35,55,29,55,19,55,30,55,27,56,56,
	       57,1,57,42,57,44,57,48,57,3,58,6,58,17,58,36,58,36,59,58,59,
	       59,60,10,60,39,60,6,60,47,60,13,60,15,60,2,60,43,61,47,61,
	       54,61,18,61,26,61,31,61,34,61,61,62,20,62,45,62,17,62,27,62,
	       56,62,27,63,58,63,59,63,42,63,63,64,9,64,32,64,60,64,2,64,6,
	       64,47,64,13,64,0,65,27,65,17,65,63,65,56,65,20,65,65,66,59,
	       66,24,66,44,66,48,66,16,67,41,67,46,67,53,67,49,67,67,68,15,
	       68,50,68,21,68,51,68,7,68,22,68,8,68,4,69,24,69,28,69,50,69,
	       11,69,69,70,43,70,65,70,20,70,56,70,62,70,27,70,60,71,18,71,
	       14,71,34,71,54,71,38,71,61,71,31,71,71,72,2,72,10,72,3,72,
	       40,72,52,72,7,73,49,73,53,73,67,73,46,73,73,74,2,74,72,74,5,
	       74,10,74,52,74,3,74,40,74,20,75,66,75,48,75,57,75,44,75,75,
	       76,27,76,59,76,20,76,70,76,66,76,56,76,62,76,73,77,22,77,7,
	       77,51,77,21,77,8,77,77,78,23,78,50,78,28,78,22,78,8,78,68,
	       78,7,78,51,78,31,79,43,79,30,79,19,79,29,79,35,79,55,79,79,
	       80,37,80,29,80,16,81,5,81,40,81,10,81,72,81,3,81,81,82,74,
	       82,39,82,77,82,80,82,30,82,29,82,7,82,53,83,81,83,69,83,73,
	       83,46,83,67,83,49,83,83,84,24,84,49,84,52,84,3,84,74,84,10,
	       84,81,84,5,84,3,84,6,85,14,85,38,85,43,85,80,85,12,85,26,85,
	       31,85,44,86,53,86,75,86,57,86,48,86,80,86,66,86,86,87,17,87,
	       62,87,56,87,24,87,20,87,65,87,49,88,58,88,83,88,69,88,46,88,
	       53,88,73,88,67,88,88,89,1,89,37,89,25,89,33,89,55,89,45,89,
	       5,90,8,90,23,90,0,90,11,90,50,90,24,90,69,90,28,90,29,91,48,
	       91,66,91,69,91,44,91,86,91,57,91,80,91,91,92,35,92,15,92,86,
	       92,48,92,57,92,61,92,66,92,75,92,0,93,23,93,80,93,16,93,4,
	       93,82,93,91,93,41,93,9,93,34,94,19,94,55,94,79,94,80,94,29,
	       94,30,94,82,94,35,94,70,95,69,95,76,95,62,95,56,95,27,95,17,
	       95,87,95,37,95,48,96,17,96,76,96,27,96,56,96,65,96,20,96,87,
	       96,5,97,86,97,58,97,11,97,59,97,63,97,97,98,77,98,48,98,84,
	       98,40,98,10,98,5,98,52,98,81,98,89,99,34,99,14,99,85,99,54,
	       99,18,99,31,99,61,99,71,99,14,99,99,100,82,100,13,100,2,100,
	       15,100,32,100,64,100,47,100,39,100,6,100,51,101,30,101,94,
	       101,1,101,79,101,58,101,19,101,55,101,35,101,29,101,100,102,
	       74,102,52,102,98,102,72,102,40,102,10,102,3,102,102,103,33,
	       103,45,103,25,103,89,103,37,103,1,103,70,103,72,104,11,104,
	       0,104,93,104,67,104,41,104,16,104,87,104,23,104,4,104,9,104,
	       89,105,103,105,33,105,62,105,37,105,45,105,1,105,80,105,25,
	       105,25,106,56,106,92,106,2,106,13,106,32,106,60,106,6,106,
	       64,106,15,106,39,106,88,107,75,107,98,107,102,107,72,107,40,
	       107,81,107,5,107,10,107,84,107,4,108,9,108,7,108,51,108,77,
	       108,21,108,78,108,22,108,68,108,79,109,30,109,63,109,1,109,
	       33,109,103,109,105,109,45,109,25,109,89,109,37,109,67,110,
	       13,110,24,110,80,110,88,110,49,110,73,110,46,110,83,110,53,
	       110,23,111,64,111,46,111,78,111,8,111,21,111,51,111,7,111,
	       108,111,68,111,77,111,52,112,96,112,97,112,57,112,66,112,63,
	       112,44,112,92,112,75,112,91,112,28,113,20,113,95,113,59,113,
	       70,113,17,113,87,113,76,113,65,113,96,113,83,114,88,114,110,
	       114,53,114,49,114,73,114,46,114,67,114,58,114,15,114,104,114,
	       -1);
  igraph_simplify(&g, /*multiple=*/ 1, /*loops=*/ 1, /*edge_comb=*/ 0);
  igraph_vector_view(&types, football_types, 
		     sizeof(football_types) / sizeof(igraph_real_t));
  igraph_assortativity_nominal(&g, &types, &res, /*directed=*/ 0);
  printf("%.5f\n", res);
  
  igraph_destroy(&g);
  
  return 0;
}


15.2. igraph_assortativity — Assortativity based on numeric properties of vertices

int igraph_assortativity(const igraph_t *graph,
			 const igraph_vector_t *types1,
			 const igraph_vector_t *types2,
			 igraph_real_t *res,
			 igraph_bool_t directed);

This function calculates the assortativity coefficient of the input graph. This coefficient is basically the correlation between the actual connectivity patterns of the vertices and the pattern expected from the distribution of the vertex types.

See equation (21) in M. E. J. Newman: Mixing patterns in networks, Phys. Rev. E 67, 026126 (2003) (http://arxiv.org/abs/cond-mat/0209450) for the proper definition. The actual calculation is performed using equation (26) in the same paper for directed graphs, and equation (4) in M. E. J. Newman: Assortative mixing in networks, Phys. Rev. Lett. 89, 208701 (2002) (http://arxiv.org/abs/cond-mat/0205405/) for undirected graphs.

Arguments: 

graph:

The input graph, it can be directed or undirected.

types1:

The vertex values, these can be arbitrary numeric values.

types2:

A second value vector to be using for the incoming edges when calculating assortativity for a directed graph. Supply a null pointer here if you want to use the same values for outgoing and incoming edges. This argument is ignored (with a warning) if it is not a null pointer and undirected assortativity coefficient is being calculated.

res:

Pointer to a real variable, the result is stored here.

directed:

Boolean, whether to consider edge directions for directed graphs. It is ignored for undirected graphs.

Returns: 

Error code.

Time complexity: O(|E|), linear in the number of edges of the graph.

See also: 

igraph_assortativity_nominal() if you have discrete vertex categories instead of numeric labels, and igraph_assortativity_degree() for the special case of assortativity based on vertex degree.

Example 13.36.  File examples/simple/assortativity.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2009-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.h>
#include <stdio.h>

int main() {

  igraph_t g;
  FILE *karate, *neural;
  igraph_real_t res;
  igraph_vector_t types;
  igraph_vector_t degree, outdegree, indegree;

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

  karate=fopen("karate.gml", "r");
  igraph_read_graph_gml(&g, karate);
  fclose(karate);
  
  igraph_vector_init(&types, 0);
  igraph_degree(&g, &types, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);

  igraph_assortativity_nominal(&g, &types, &res, /*directed=*/ 0);
  printf("%.5f\n", res);
  
  igraph_destroy(&g);

  /*---------------------*/

  neural=fopen("celegansneural.gml", "r");
  igraph_read_graph_gml(&g, neural);
  fclose(neural);
  
  igraph_degree(&g, &types, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);

  igraph_assortativity_nominal(&g, &types, &res, /*directed=*/ 1);
  printf("%.5f\n", res);  
  igraph_assortativity_nominal(&g, &types, &res, /*directed=*/ 0);
  printf("%.5f\n", res);  

  igraph_destroy(&g);
  igraph_vector_destroy(&types);

  /*---------------------*/
  
  karate=fopen("karate.gml", "r");
  igraph_read_graph_gml(&g, karate);
  fclose(karate);
  
  igraph_vector_init(&degree, 0);
  igraph_degree(&g, &degree, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);
  igraph_vector_add_constant(&degree, -1);

  igraph_assortativity(&g, &degree, 0, &res, /*directed=*/ 0);
  printf("%.5f\n", res);
  
  igraph_destroy(&g);

  /*---------------------*/

  neural=fopen("celegansneural.gml", "r");
  igraph_read_graph_gml(&g, neural);
  fclose(neural);
  
  igraph_degree(&g, &degree, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);
  igraph_vector_add_constant(&degree, -1);

  igraph_assortativity(&g, &degree, 0, &res, /*directed=*/ 1);
  printf("%.5f\n", res);  
  igraph_assortativity(&g, &degree, 0, &res, /*directed=*/ 0);
  printf("%.5f\n", res);  

  igraph_vector_destroy(&degree);

  /*---------------------*/
  
  igraph_vector_init(&indegree, 0);
  igraph_vector_init(&outdegree, 0);
  igraph_degree(&g, &indegree, igraph_vss_all(), IGRAPH_IN, /*loops=*/ 1);
  igraph_degree(&g, &outdegree, igraph_vss_all(), IGRAPH_OUT, /*loops=*/ 1);
  igraph_vector_add_constant(&indegree, -1);
  igraph_vector_add_constant(&outdegree, -1);
  
  igraph_assortativity(&g, &outdegree, &indegree, &res, /*directed=*/ 1);
  printf("%.5f\n", res);

  igraph_vector_destroy(&indegree);
  igraph_vector_destroy(&outdegree);

  /*---------------------*/
  
  igraph_assortativity_degree(&g, &res, /*directed=*/ 1);
  printf("%.5f\n", res);

  igraph_destroy(&g);  

  /*---------------------*/

  karate=fopen("karate.gml", "r");
  igraph_read_graph_gml(&g, karate);
  fclose(karate);
  
  igraph_assortativity_degree(&g, &res, /*directed=*/ 1);
  printf("%.5f\n", res);
  
  igraph_destroy(&g);

  /*---------------------*/
  
  igraph_small(&g, sizeof(football_types)/sizeof(igraph_real_t), 
	       IGRAPH_UNDIRECTED,
	       0,1,2,3,0,4,4,5,3,5,2,6,6,7,7,8,8,9,0,9,4,9,5,10,10,11,5,11,
	       3,11,12,13,2,13,2,14,12,14,14,15,13,15,2,15,4,16,9,16,0,16,
	       16,17,12,17,12,18,18,19,17,20,20,21,8,21,7,21,9,22,7,22,21,
	       22,8,22,22,23,9,23,4,23,16,23,0,23,11,24,24,25,1,25,3,26,12,
	       26,14,26,26,27,17,27,1,27,17,27,4,28,11,28,24,28,19,29,29,
	       30,19,30,18,31,31,32,21,32,15,32,13,32,6,32,0,33,1,33,25,33,
	       19,33,31,34,26,34,12,34,18,34,34,35,0,35,29,35,19,35,30,35,
	       18,36,12,36,20,36,19,36,36,37,1,37,25,37,33,37,18,38,16,38,
	       28,38,26,38,14,38,12,38,38,39,6,39,32,39,13,39,15,39,7,40,3,
	       40,40,41,8,41,4,41,23,41,9,41,0,41,16,41,34,42,29,42,18,42,
	       26,42,42,43,36,43,26,43,31,43,38,43,12,43,14,43,19,44,35,44,
	       30,44,44,45,13,45,33,45,1,45,37,45,25,45,21,46,46,47,22,47,
	       6,47,15,47,2,47,39,47,32,47,44,48,48,49,32,49,46,49,30,50,
	       24,50,11,50,28,50,50,51,40,51,8,51,22,51,21,51,3,52,40,52,5,
	       52,52,53,25,53,48,53,49,53,46,53,39,54,31,54,38,54,14,54,34,
	       54,18,54,54,55,31,55,6,55,35,55,29,55,19,55,30,55,27,56,56,
	       57,1,57,42,57,44,57,48,57,3,58,6,58,17,58,36,58,36,59,58,59,
	       59,60,10,60,39,60,6,60,47,60,13,60,15,60,2,60,43,61,47,61,
	       54,61,18,61,26,61,31,61,34,61,61,62,20,62,45,62,17,62,27,62,
	       56,62,27,63,58,63,59,63,42,63,63,64,9,64,32,64,60,64,2,64,6,
	       64,47,64,13,64,0,65,27,65,17,65,63,65,56,65,20,65,65,66,59,
	       66,24,66,44,66,48,66,16,67,41,67,46,67,53,67,49,67,67,68,15,
	       68,50,68,21,68,51,68,7,68,22,68,8,68,4,69,24,69,28,69,50,69,
	       11,69,69,70,43,70,65,70,20,70,56,70,62,70,27,70,60,71,18,71,
	       14,71,34,71,54,71,38,71,61,71,31,71,71,72,2,72,10,72,3,72,
	       40,72,52,72,7,73,49,73,53,73,67,73,46,73,73,74,2,74,72,74,5,
	       74,10,74,52,74,3,74,40,74,20,75,66,75,48,75,57,75,44,75,75,
	       76,27,76,59,76,20,76,70,76,66,76,56,76,62,76,73,77,22,77,7,
	       77,51,77,21,77,8,77,77,78,23,78,50,78,28,78,22,78,8,78,68,
	       78,7,78,51,78,31,79,43,79,30,79,19,79,29,79,35,79,55,79,79,
	       80,37,80,29,80,16,81,5,81,40,81,10,81,72,81,3,81,81,82,74,
	       82,39,82,77,82,80,82,30,82,29,82,7,82,53,83,81,83,69,83,73,
	       83,46,83,67,83,49,83,83,84,24,84,49,84,52,84,3,84,74,84,10,
	       84,81,84,5,84,3,84,6,85,14,85,38,85,43,85,80,85,12,85,26,85,
	       31,85,44,86,53,86,75,86,57,86,48,86,80,86,66,86,86,87,17,87,
	       62,87,56,87,24,87,20,87,65,87,49,88,58,88,83,88,69,88,46,88,
	       53,88,73,88,67,88,88,89,1,89,37,89,25,89,33,89,55,89,45,89,
	       5,90,8,90,23,90,0,90,11,90,50,90,24,90,69,90,28,90,29,91,48,
	       91,66,91,69,91,44,91,86,91,57,91,80,91,91,92,35,92,15,92,86,
	       92,48,92,57,92,61,92,66,92,75,92,0,93,23,93,80,93,16,93,4,
	       93,82,93,91,93,41,93,9,93,34,94,19,94,55,94,79,94,80,94,29,
	       94,30,94,82,94,35,94,70,95,69,95,76,95,62,95,56,95,27,95,17,
	       95,87,95,37,95,48,96,17,96,76,96,27,96,56,96,65,96,20,96,87,
	       96,5,97,86,97,58,97,11,97,59,97,63,97,97,98,77,98,48,98,84,
	       98,40,98,10,98,5,98,52,98,81,98,89,99,34,99,14,99,85,99,54,
	       99,18,99,31,99,61,99,71,99,14,99,99,100,82,100,13,100,2,100,
	       15,100,32,100,64,100,47,100,39,100,6,100,51,101,30,101,94,
	       101,1,101,79,101,58,101,19,101,55,101,35,101,29,101,100,102,
	       74,102,52,102,98,102,72,102,40,102,10,102,3,102,102,103,33,
	       103,45,103,25,103,89,103,37,103,1,103,70,103,72,104,11,104,
	       0,104,93,104,67,104,41,104,16,104,87,104,23,104,4,104,9,104,
	       89,105,103,105,33,105,62,105,37,105,45,105,1,105,80,105,25,
	       105,25,106,56,106,92,106,2,106,13,106,32,106,60,106,6,106,
	       64,106,15,106,39,106,88,107,75,107,98,107,102,107,72,107,40,
	       107,81,107,5,107,10,107,84,107,4,108,9,108,7,108,51,108,77,
	       108,21,108,78,108,22,108,68,108,79,109,30,109,63,109,1,109,
	       33,109,103,109,105,109,45,109,25,109,89,109,37,109,67,110,
	       13,110,24,110,80,110,88,110,49,110,73,110,46,110,83,110,53,
	       110,23,111,64,111,46,111,78,111,8,111,21,111,51,111,7,111,
	       108,111,68,111,77,111,52,112,96,112,97,112,57,112,66,112,63,
	       112,44,112,92,112,75,112,91,112,28,113,20,113,95,113,59,113,
	       70,113,17,113,87,113,76,113,65,113,96,113,83,114,88,114,110,
	       114,53,114,49,114,73,114,46,114,67,114,58,114,15,114,104,114,
	       -1);
  igraph_simplify(&g, /*multiple=*/ 1, /*loops=*/ 1, /*edge_comb=*/ 0);
  igraph_vector_view(&types, football_types, 
		     sizeof(football_types) / sizeof(igraph_real_t));
  igraph_assortativity_nominal(&g, &types, &res, /*directed=*/ 0);
  printf("%.5f\n", res);
  
  igraph_destroy(&g);
  
  return 0;
}


15.3. igraph_assortativity_degree — Assortativity of a graph based on vertex degree

int igraph_assortativity_degree(const igraph_t *graph,
				igraph_real_t *res, 
				igraph_bool_t directed);

Assortativity based on vertex degree, please see the discussion at the documentation of igraph_assortativity() for details.

Arguments: 

graph:

The input graph, it can be directed or undirected.

res:

Pointer to a real variable, the result is stored here.

directed:

Boolean, whether to consider edge directions for directed graphs. This argument is ignored for undirected graphs. Supply 1 (=TRUE) here to do the natural thing, i.e. use directed version of the measure for directed graphs and the undirected version for undirected graphs.

Returns: 

Error code.

Time complexity: O(|E|+|V|), |E| is the number of edges, |V| is the number of vertices.

See also: 

igraph_assortativity() for the general function calculating assortativity for any kind of numeric vertex values.

Example 13.37.  File examples/simple/assortativity.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2009-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.h>
#include <stdio.h>

int main() {

  igraph_t g;
  FILE *karate, *neural;
  igraph_real_t res;
  igraph_vector_t types;
  igraph_vector_t degree, outdegree, indegree;

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

  karate=fopen("karate.gml", "r");
  igraph_read_graph_gml(&g, karate);
  fclose(karate);
  
  igraph_vector_init(&types, 0);
  igraph_degree(&g, &types, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);

  igraph_assortativity_nominal(&g, &types, &res, /*directed=*/ 0);
  printf("%.5f\n", res);
  
  igraph_destroy(&g);

  /*---------------------*/

  neural=fopen("celegansneural.gml", "r");
  igraph_read_graph_gml(&g, neural);
  fclose(neural);
  
  igraph_degree(&g, &types, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);

  igraph_assortativity_nominal(&g, &types, &res, /*directed=*/ 1);
  printf("%.5f\n", res);  
  igraph_assortativity_nominal(&g, &types, &res, /*directed=*/ 0);
  printf("%.5f\n", res);  

  igraph_destroy(&g);
  igraph_vector_destroy(&types);

  /*---------------------*/
  
  karate=fopen("karate.gml", "r");
  igraph_read_graph_gml(&g, karate);
  fclose(karate);
  
  igraph_vector_init(&degree, 0);
  igraph_degree(&g, &degree, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);
  igraph_vector_add_constant(&degree, -1);

  igraph_assortativity(&g, &degree, 0, &res, /*directed=*/ 0);
  printf("%.5f\n", res);
  
  igraph_destroy(&g);

  /*---------------------*/

  neural=fopen("celegansneural.gml", "r");
  igraph_read_graph_gml(&g, neural);
  fclose(neural);
  
  igraph_degree(&g, &degree, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);
  igraph_vector_add_constant(&degree, -1);

  igraph_assortativity(&g, &degree, 0, &res, /*directed=*/ 1);
  printf("%.5f\n", res);  
  igraph_assortativity(&g, &degree, 0, &res, /*directed=*/ 0);
  printf("%.5f\n", res);  

  igraph_vector_destroy(&degree);

  /*---------------------*/
  
  igraph_vector_init(&indegree, 0);
  igraph_vector_init(&outdegree, 0);
  igraph_degree(&g, &indegree, igraph_vss_all(), IGRAPH_IN, /*loops=*/ 1);
  igraph_degree(&g, &outdegree, igraph_vss_all(), IGRAPH_OUT, /*loops=*/ 1);
  igraph_vector_add_constant(&indegree, -1);
  igraph_vector_add_constant(&outdegree, -1);
  
  igraph_assortativity(&g, &outdegree, &indegree, &res, /*directed=*/ 1);
  printf("%.5f\n", res);

  igraph_vector_destroy(&indegree);
  igraph_vector_destroy(&outdegree);

  /*---------------------*/
  
  igraph_assortativity_degree(&g, &res, /*directed=*/ 1);
  printf("%.5f\n", res);

  igraph_destroy(&g);  

  /*---------------------*/

  karate=fopen("karate.gml", "r");
  igraph_read_graph_gml(&g, karate);
  fclose(karate);
  
  igraph_assortativity_degree(&g, &res, /*directed=*/ 1);
  printf("%.5f\n", res);
  
  igraph_destroy(&g);

  /*---------------------*/
  
  igraph_small(&g, sizeof(football_types)/sizeof(igraph_real_t), 
	       IGRAPH_UNDIRECTED,
	       0,1,2,3,0,4,4,5,3,5,2,6,6,7,7,8,8,9,0,9,4,9,5,10,10,11,5,11,
	       3,11,12,13,2,13,2,14,12,14,14,15,13,15,2,15,4,16,9,16,0,16,
	       16,17,12,17,12,18,18,19,17,20,20,21,8,21,7,21,9,22,7,22,21,
	       22,8,22,22,23,9,23,4,23,16,23,0,23,11,24,24,25,1,25,3,26,12,
	       26,14,26,26,27,17,27,1,27,17,27,4,28,11,28,24,28,19,29,29,
	       30,19,30,18,31,31,32,21,32,15,32,13,32,6,32,0,33,1,33,25,33,
	       19,33,31,34,26,34,12,34,18,34,34,35,0,35,29,35,19,35,30,35,
	       18,36,12,36,20,36,19,36,36,37,1,37,25,37,33,37,18,38,16,38,
	       28,38,26,38,14,38,12,38,38,39,6,39,32,39,13,39,15,39,7,40,3,
	       40,40,41,8,41,4,41,23,41,9,41,0,41,16,41,34,42,29,42,18,42,
	       26,42,42,43,36,43,26,43,31,43,38,43,12,43,14,43,19,44,35,44,
	       30,44,44,45,13,45,33,45,1,45,37,45,25,45,21,46,46,47,22,47,
	       6,47,15,47,2,47,39,47,32,47,44,48,48,49,32,49,46,49,30,50,
	       24,50,11,50,28,50,50,51,40,51,8,51,22,51,21,51,3,52,40,52,5,
	       52,52,53,25,53,48,53,49,53,46,53,39,54,31,54,38,54,14,54,34,
	       54,18,54,54,55,31,55,6,55,35,55,29,55,19,55,30,55,27,56,56,
	       57,1,57,42,57,44,57,48,57,3,58,6,58,17,58,36,58,36,59,58,59,
	       59,60,10,60,39,60,6,60,47,60,13,60,15,60,2,60,43,61,47,61,
	       54,61,18,61,26,61,31,61,34,61,61,62,20,62,45,62,17,62,27,62,
	       56,62,27,63,58,63,59,63,42,63,63,64,9,64,32,64,60,64,2,64,6,
	       64,47,64,13,64,0,65,27,65,17,65,63,65,56,65,20,65,65,66,59,
	       66,24,66,44,66,48,66,16,67,41,67,46,67,53,67,49,67,67,68,15,
	       68,50,68,21,68,51,68,7,68,22,68,8,68,4,69,24,69,28,69,50,69,
	       11,69,69,70,43,70,65,70,20,70,56,70,62,70,27,70,60,71,18,71,
	       14,71,34,71,54,71,38,71,61,71,31,71,71,72,2,72,10,72,3,72,
	       40,72,52,72,7,73,49,73,53,73,67,73,46,73,73,74,2,74,72,74,5,
	       74,10,74,52,74,3,74,40,74,20,75,66,75,48,75,57,75,44,75,75,
	       76,27,76,59,76,20,76,70,76,66,76,56,76,62,76,73,77,22,77,7,
	       77,51,77,21,77,8,77,77,78,23,78,50,78,28,78,22,78,8,78,68,
	       78,7,78,51,78,31,79,43,79,30,79,19,79,29,79,35,79,55,79,79,
	       80,37,80,29,80,16,81,5,81,40,81,10,81,72,81,3,81,81,82,74,
	       82,39,82,77,82,80,82,30,82,29,82,7,82,53,83,81,83,69,83,73,
	       83,46,83,67,83,49,83,83,84,24,84,49,84,52,84,3,84,74,84,10,
	       84,81,84,5,84,3,84,6,85,14,85,38,85,43,85,80,85,12,85,26,85,
	       31,85,44,86,53,86,75,86,57,86,48,86,80,86,66,86,86,87,17,87,
	       62,87,56,87,24,87,20,87,65,87,49,88,58,88,83,88,69,88,46,88,
	       53,88,73,88,67,88,88,89,1,89,37,89,25,89,33,89,55,89,45,89,
	       5,90,8,90,23,90,0,90,11,90,50,90,24,90,69,90,28,90,29,91,48,
	       91,66,91,69,91,44,91,86,91,57,91,80,91,91,92,35,92,15,92,86,
	       92,48,92,57,92,61,92,66,92,75,92,0,93,23,93,80,93,16,93,4,
	       93,82,93,91,93,41,93,9,93,34,94,19,94,55,94,79,94,80,94,29,
	       94,30,94,82,94,35,94,70,95,69,95,76,95,62,95,56,95,27,95,17,
	       95,87,95,37,95,48,96,17,96,76,96,27,96,56,96,65,96,20,96,87,
	       96,5,97,86,97,58,97,11,97,59,97,63,97,97,98,77,98,48,98,84,
	       98,40,98,10,98,5,98,52,98,81,98,89,99,34,99,14,99,85,99,54,
	       99,18,99,31,99,61,99,71,99,14,99,99,100,82,100,13,100,2,100,
	       15,100,32,100,64,100,47,100,39,100,6,100,51,101,30,101,94,
	       101,1,101,79,101,58,101,19,101,55,101,35,101,29,101,100,102,
	       74,102,52,102,98,102,72,102,40,102,10,102,3,102,102,103,33,
	       103,45,103,25,103,89,103,37,103,1,103,70,103,72,104,11,104,
	       0,104,93,104,67,104,41,104,16,104,87,104,23,104,4,104,9,104,
	       89,105,103,105,33,105,62,105,37,105,45,105,1,105,80,105,25,
	       105,25,106,56,106,92,106,2,106,13,106,32,106,60,106,6,106,
	       64,106,15,106,39,106,88,107,75,107,98,107,102,107,72,107,40,
	       107,81,107,5,107,10,107,84,107,4,108,9,108,7,108,51,108,77,
	       108,21,108,78,108,22,108,68,108,79,109,30,109,63,109,1,109,
	       33,109,103,109,105,109,45,109,25,109,89,109,37,109,67,110,
	       13,110,24,110,80,110,88,110,49,110,73,110,46,110,83,110,53,
	       110,23,111,64,111,46,111,78,111,8,111,21,111,51,111,7,111,
	       108,111,68,111,77,111,52,112,96,112,97,112,57,112,66,112,63,
	       112,44,112,92,112,75,112,91,112,28,113,20,113,95,113,59,113,
	       70,113,17,113,87,113,76,113,65,113,96,113,83,114,88,114,110,
	       114,53,114,49,114,73,114,46,114,67,114,58,114,15,114,104,114,
	       -1);
  igraph_simplify(&g, /*multiple=*/ 1, /*loops=*/ 1, /*edge_comb=*/ 0);
  igraph_vector_view(&types, football_types, 
		     sizeof(football_types) / sizeof(igraph_real_t));
  igraph_assortativity_nominal(&g, &types, &res, /*directed=*/ 0);
  printf("%.5f\n", res);
  
  igraph_destroy(&g);
  
  return 0;
}


16. K-Cores

16.1. igraph_coreness — Finding the coreness of the vertices in a network.

int igraph_coreness(const igraph_t *graph, igraph_vector_t *cores, 
		    igraph_neimode_t mode);

The k-core of a graph is a maximal subgraph in which each vertex has at least degree k. (Degree here means the degree in the subgraph of course.). The coreness of a vertex is the highest order of a k-core containing the vertex.

This function implements the algorithm presented in Vladimir Batagelj, Matjaz Zaversnik: An O(m) Algorithm for Cores Decomposition of Networks.

Arguments: 

graph:

The input graph.

cores:

Pointer to an initialized vector, the result of the computation will be stored here. It will be resized as needed. For each vertex it contains the highest order of a core containing the vertex.

mode:

For directed graph it specifies whether to calculate in-cores, out-cores or the undirected version. It is ignored for undirected graphs. Possible values: IGRAPH_ALL undirected version, IGRAPH_IN in-cores, IGRAPH_OUT out-cores.

Returns: 

Error code.

Time complexity: O(|E|), the number of edges.

17. Topological sorting, directed acyclic graphs

17.1. igraph_is_dag — Checks whether a graph is a directed acyclic graph (DAG) or not.

int igraph_is_dag(const igraph_t* graph, igraph_bool_t *res);

A directed acyclic graph (DAG) is a directed graph with no cycles.

Arguments: 

graph:

The input graph.

res:

Pointer to a boolean constant, the result is stored here.

Returns: 

Error code.

Time complexity: O(|V|+|E|), where |V| and |E| are the number of vertices and edges in the original input graph.

See also: 

igraph_topological_sorting() to get a possible topological sorting of a DAG.

17.2. igraph_topological_sorting — Calculate a possible topological sorting of the graph.

int igraph_topological_sorting(const igraph_t* graph, igraph_vector_t *res,
			       igraph_neimode_t mode);

A topological sorting of a directed acyclic graph is a linear ordering of its nodes where each node comes before all nodes to which it has edges. Every DAG has at least one topological sort, and may have many. This function returns a possible topological sort among them. If the graph is not acyclic (it has at least one cycle), a partial topological sort is returned and a warning is issued.

Arguments: 

graph:

The input graph.

res:

Pointer to a vector, the result will be stored here. It will be resized if needed.

mode:

Specifies how to use the direction of the edges. For IGRAPH_OUT, the sorting order ensures that each node comes before all nodes to which it has edges, so nodes with no incoming edges go first. For IGRAPH_IN, it is quite the opposite: each node comes before all nodes from which it receives edges. Nodes with no outgoing edges go first.

Returns: 

Error code.

Time complexity: O(|V|+|E|), where |V| and |E| are the number of vertices and edges in the original input graph.

See also: 

igraph_is_dag() if you are only interested in whether a given graph is a DAG or not, or igraph_feedback_arc_set() to find a set of edges whose removal makes the graph a DAG.

Example 13.38.  File examples/simple/igraph_topological_sorting.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

void print_vector(igraph_vector_t *v, FILE *f) {
  long int i;
  for (i=0; i<igraph_vector_size(v); i++) {
    fprintf(f, " %d", (int)VECTOR(*v)[i]);
  }
  fprintf(f, "\n");
}

void igraph_warning_handler_print_stdout(const char *reason, const char *file,
					 int line, int igraph_errno) {
  fprintf(stdout, "Warning: %s\n", reason);
}


int main() {

  igraph_t g;
  igraph_vector_t v, res;
  igraph_bool_t is_dag;
  int ret;

  igraph_set_warning_handler(igraph_warning_handler_print_stdout);

  /* Test graph taken from http://en.wikipedia.org/wiki/Topological_sorting
   * @ 05.03.2006 */
  igraph_small(&g, 8, 1, 0, 3, 0, 4, 1, 3, 2, 4, 2, 7, \
	       3, 5, 3, 6, 3, 7, 4, 6, -1);

  igraph_vector_init(&res, 0);

  igraph_is_dag(&g, &is_dag);
  if (!is_dag)
    return 2;

  igraph_topological_sorting(&g, &res, IGRAPH_OUT);
  print_vector(&res, stdout);
  igraph_topological_sorting(&g, &res, IGRAPH_IN);
  print_vector(&res, stdout);

  /* Add a circle: 5 -> 0 */
  igraph_vector_init_int(&v, 2, 5, 0);
  igraph_add_edges(&g, &v, 0);
  igraph_is_dag(&g, &is_dag);
  if (is_dag)
    return 3;
  igraph_topological_sorting(&g, &res, IGRAPH_OUT);
  print_vector(&res, stdout);
  igraph_vector_destroy(&v);
  igraph_destroy(&g);

  /* Error handling */
  igraph_set_error_handler(igraph_error_handler_ignore);

  /* This graph is the same but undirected */
  igraph_small(&g, 8, 0, 0, 3, 0, 4, 1, 3, 2, 4, 2, 7, \
	       3, 5, 3, 6, 3, 7, 4, 6, -1);
  igraph_is_dag(&g, &is_dag);
  if (is_dag)
    return 4;
  ret=igraph_topological_sorting(&g, &res, IGRAPH_ALL);
  if (ret != IGRAPH_EINVAL) {
    return 1;
  }
  ret=igraph_topological_sorting(&g, &res, IGRAPH_OUT);
  if (ret != IGRAPH_EINVAL) {
    return 1;
  }  
  igraph_destroy(&g);

  igraph_vector_destroy(&res);  
  return 0;
}


17.3. igraph_feedback_arc_set — Calculates a feedback arc set of the graph using different

int igraph_feedback_arc_set(const igraph_t *graph, igraph_vector_t *result,
        const igraph_vector_t *weights, igraph_fas_algorithm_t algo);

algorithms.

A feedback arc set is a set of edges whose removal makes the graph acyclic. We are usually interested in minimum feedback arc sets, i.e. sets of edges whose total weight is minimal among all the feedback arc sets.

For undirected graphs, the problem is simple: one has to find a maximum weight spanning tree and then remove all the edges not in the spanning tree. For directed graphs, this is an NP-hard problem, and various heuristics are usually used to find an approximate solution to the problem. This function implements a few of these heuristics.

Arguments: 

graph:

The graph object.

result:

An initialized vector, the result will be returned here.

weights:

Weight vector or NULL if no weights are specified.

algo:

The algorithm to use to solve the problem if the graph is directed. Possible values:

IGRAPH_FAS_EXACT_IP

Finds a minimum feedback arc set using integer programming (IP). The complexity of this algorithm is exponential of course.

IGRAPH_FAS_APPROX_EADES

Finds a feedback arc set using the heuristic of Eades, Lin and Smyth (1993). This is guaranteed to be smaller than |E|/2 - |V|/6, and it is linear in the number of edges (i.e. O(|E|)). For more details, see Eades P, Lin X and Smyth WF: A fast and effective heuristic for the feedback arc set problem. In: Proc Inf Process Lett 319-323, 1993.

Returns: 

Error code: IGRAPH_EINVAL if an unknown method was specified or the weight vector is invalid.

Example 13.39.  File examples/simple/igraph_feedback_arc_set.c

/* -*- mode: C -*-  */
/* vim:set ts=2 sw=2 sts=2 et: */
/* 
   IGraph library.
   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>
#include <string.h>

int main() {
  igraph_t g;
  igraph_vector_t weights, result;
  igraph_bool_t dag;

  igraph_vector_init(&result, 0);

  /***********************************************************************/
  /* Approximation with Eades' method                                    */
  /***********************************************************************/

  /* Simple unweighted graph */
  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,0, 2,3, 2,4, 0,4, 4,3, 5,0, 6,5, -1);
  igraph_feedback_arc_set(&g, &result, 0, IGRAPH_FAS_APPROX_EADES);
  igraph_vector_print(&result);
  igraph_delete_edges(&g, igraph_ess_vector(&result));
  igraph_is_dag(&g, &dag);
  if (!dag)
    return 1;
  igraph_destroy(&g);

  /* Simple weighted graph */
  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,0, 2,3, 2,4, 0,4, 4,3, 5,0, 6,5, -1);
  igraph_vector_init_int_end(&weights, -1, 1, 1, 3, 1, 1, 1, 1, 1, 1, -1);
  igraph_feedback_arc_set(&g, &result, &weights, IGRAPH_FAS_APPROX_EADES);
  igraph_vector_print(&result);
  igraph_delete_edges(&g, igraph_ess_vector(&result));
  igraph_is_dag(&g, &dag);
  if (!dag)
    return 2;
  igraph_vector_destroy(&weights);
  igraph_destroy(&g);

  /* Simple unweighted graph with loops */
  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,0, 2,3, 2,4, 0,4, 4,3, 5,0, 6,5, 1,1, 4,4, -1);
  igraph_feedback_arc_set(&g, &result, 0, IGRAPH_FAS_APPROX_EADES);
  igraph_vector_print(&result);
  igraph_delete_edges(&g, igraph_ess_vector(&result));
  igraph_is_dag(&g, &dag);
  if (!dag)
    return 3;
  igraph_destroy(&g);

  igraph_vector_destroy(&result);

  return 0;
}


Example 13.40.  File examples/simple/igraph_feedback_arc_set_ip.c

/* -*- mode: C -*-  */
/* vim:set ts=2 sw=2 sts=2 et: */
/* 
   IGraph library.
   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>
#include <string.h>

int main() {
  igraph_t g;
  igraph_vector_t weights, result;
  igraph_bool_t dag;
  int retval;

  igraph_vector_init(&result, 0);

  igraph_set_error_handler(&igraph_error_handler_printignore);

  /***********************************************************************/
  /* Exact solution with integer programming                             */
  /***********************************************************************/

  /* Simple unweighted graph */
  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,0, 2,3, 2,4, 0,4, 4,3, 5,0, 6,5, -1);
  retval = igraph_feedback_arc_set(&g, &result, 0, IGRAPH_FAS_EXACT_IP);
  if (retval == IGRAPH_UNIMPLEMENTED)
    return 77;
  igraph_vector_print(&result);
  igraph_delete_edges(&g, igraph_ess_vector(&result));
  igraph_is_dag(&g, &dag);
  if (!dag)
    return 1;
  igraph_destroy(&g);

  /* Simple weighted graph */
  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,0, 2,3, 2,4, 0,4, 4,3, 5,0, 6,5, -1);
  igraph_vector_init_int_end(&weights, -1, 1, 1, 3, 1, 1, 1, 1, 1, 1, -1);
  igraph_feedback_arc_set(&g, &result, &weights, IGRAPH_FAS_EXACT_IP);
  igraph_vector_print(&result);
  igraph_delete_edges(&g, igraph_ess_vector(&result));
  igraph_is_dag(&g, &dag);
  if (!dag)
    return 2;
  igraph_vector_destroy(&weights);
  igraph_destroy(&g);

  /* Simple unweighted graph with loops */
  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,1, 1,2, 2,0, 2,3, 2,4, 0,4, 4,3, 5,0, 6,5, 1,1, 4,4, -1);
  igraph_feedback_arc_set(&g, &result, 0, IGRAPH_FAS_EXACT_IP);
  igraph_vector_print(&result);
  igraph_delete_edges(&g, igraph_ess_vector(&result));
  igraph_is_dag(&g, &dag);
  if (!dag)
    return 3;
  igraph_destroy(&g);

  /* Disjoint union of two almost identical graphs */
  igraph_small(&g, 0, IGRAPH_DIRECTED,
      0,1, 1,2, 2,0, 2,3,  2,4,  0,4,  4,3,    5,0,  6,5, 1,1, 4,4,
      7,8, 8,9, 9,7, 9,10, 9,11, 7,11, 11,10, 12,7, 13,12,
      -1);
  igraph_feedback_arc_set(&g, &result, 0, IGRAPH_FAS_EXACT_IP);
  igraph_vector_print(&result);
  igraph_delete_edges(&g, igraph_ess_vector(&result));
  igraph_is_dag(&g, &dag);
  if (!dag)
    return 4;
  igraph_destroy(&g);

  igraph_vector_destroy(&result);

  return 0;
}


Time complexity: depends on algo, see the time complexities there.

18. Maximum cardinality search, graph decomposition, chordal graphs

18.1. igraph_maximum_cardinality_search — Maximum cardinality search

int igraph_maximum_cardinality_search(const igraph_t *graph,
				      igraph_vector_t *alpha,
				      igraph_vector_t *alpham1);

This function implements the maximum cardinality search algorithm discussed in Robert E Tarjan and Mihalis Yannakakis: Simple linear-time algorithms to test chordality of graphs, test acyclicity of hypergraphs, and selectively reduce acyclic hypergraphs. SIAM Journal of Computation 13, 566--579, 1984.

Arguments: 

graph:

The input graph. Can be directed, but the direction of the edges is ignored.

alpha:

Pointer to an initialized vector, the result is stored here. It will be resized, as needed. Upon return it contains the rank of the each vertex.

alpham1:

Pointer to an initialized vector or a NULL pointer. If not NULL, then the inverse of alpha is stored here.

Returns: 

Error code.

Time complexity: O(|V|+|E|), linear in terms of the number of vertices and edges.

See also: 

18.2. igraph_is_chordal — Decides whether a graph is chordal

int igraph_is_chordal(const igraph_t *graph,
		      const igraph_vector_t *alpha,
		      const igraph_vector_t *alpham1,
		      igraph_bool_t *chordal,
		      igraph_vector_t *fill_in,
		      igraph_t *newgraph);

A graph is chordal if each of its cycles of four or more nodes has a chord, which is an edge joining two nodes that are not adjacent in the cycle. An equivalent definition is that any chordless cycles have at most three nodes. If either alpha or alpha1 is given, then the other is calculated by taking simply the inverse. If neither are given, then igraph_maximum_cardinality_search() is called to calculate them.

Arguments: 

graph:

The input graph, it might be directed, but edge direction is ignored.

alpha:

Either an alpha vector coming from igraph_maximum_cardinality_search() (on the same graph), or a null pointer.

alpham1:

Either an inverse alpha vector coming from igraph_maximum_cardinality_search() (on the same graph) or a null pointer.

chordal:

Pointer to a boolean, the result is stored here.

fill_in:

Pointer to an initialized vector, or a null pointer. If not a null pointer, then the fill-in of the graph is stored here. The fill-in is the set of edges that are needed to make the graph chordal. The vector is resized as needed.

newgraph:

Pointer to an uninitialized graph, or a null pointer. If not a null pointer, then a new triangulated graph is created here. This essentially means adding the fill-in edges to the original graph.

Returns: 

Error code.

Time complexity: O(n).

See also: 

19. Matchings

19.1. igraph_is_matching — Checks whether the given matching is valid for the given graph.

int igraph_is_matching(const igraph_t* graph,
    const igraph_vector_bool_t* types, const igraph_vector_long_t* matching,
    igraph_bool_t* result);

This function checks a matching vector and verifies whether its length matches the number of vertices in the given graph, its values are between -1 (inclusive) and the number of vertices (exclusive), and whether there exists a corresponding edge in the graph for every matched vertex pair. For bipartite graphs, it also verifies whether the matched vertices are in different parts of the graph.

Arguments: 

graph:

The input graph. It can be directed but the edge directions will be ignored.

types:

If the graph is bipartite and you are interested in bipartite matchings only, pass the vertex types here. If the graph is non-bipartite, simply pass NULL.

matching:

The matching itself. It must be a vector where element i contains the ID of the vertex that vertex i is matched to, or -1 if vertex i is unmatched.

result:

Pointer to a boolean variable, the result will be returned here.

See also: 

igraph_is_maximal_matching() if you are also interested in whether the matching is maximal (i.e. non-extendable).

Time complexity: O(|V|+|E|) where |V| is the number of vertices and |E| is the number of edges.

Example 13.41.  File examples/simple/igraph_maximum_bipartite_matching.c

/* -*- mode: C -*-  */
/* vim:set ts=2 sw=2 sts=2 et: */
/* 
   IGraph library.
   Copyright (C) 2012  Tamas Nepusz <ntamas@gmail.com>
   
   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.h>
#include <stdio.h>

int test_graph_from_leda_tutorial() {
  /* Test graph from the LEDA tutorial:
   * http://www.leda-tutorial.org/en/unofficial/ch05s03s05.html
   */
  igraph_t graph;
  igraph_vector_bool_t types;
  igraph_vector_long_t matching;
  igraph_integer_t matching_size;
  igraph_real_t matching_weight;
  igraph_bool_t is_matching;
  int i;

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

  igraph_maximum_bipartite_matching(&graph, &types, &matching_size,
      &matching_weight, &matching, 0, 0);
  if (matching_size != 6) {
    printf("matching_size is %ld, expected: 6\n", (long)matching_size);
    return 1;
  }
  if (matching_weight != 6) {
    printf("matching_weight is %ld, expected: 6\n", (long)matching_weight);
    return 2;
  }
  igraph_is_maximal_matching(&graph, &types, &matching, &is_matching);
  if (!is_matching) {
    printf("not a matching: ");
    igraph_vector_long_print(&matching);
    return 3;
  }

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

  return 0;
}

int test_weighted_graph_from_mit_notes() {
  /* Test graph from the following lecture notes:
   * http://math.mit.edu/~goemans/18433S07/matching-notes.pdf
   */
  igraph_t graph;
  igraph_vector_bool_t types;
  igraph_vector_long_t matching;
  igraph_vector_t weights;
  igraph_integer_t matching_size;
  igraph_real_t matching_weight;
  igraph_bool_t is_matching;
  igraph_real_t weight_array[] = { 2, 7, 2, 3,
      1, 3, 9, 3, 3,
      1, 3, 3, 1, 2,
      4, 1, 2,
      3 };
  int i;

  igraph_small(&graph, 0, 0,
      0, 6, 0, 7, 0, 8, 0, 9,
      1, 5, 1, 6, 1, 7, 1, 8, 1, 9,
      2, 5, 2, 6, 2, 7, 2, 8, 2, 9,
      3, 5, 3, 7, 3, 9,
      4, 7, -1);
  igraph_vector_bool_init(&types, 10);
  for (i = 0; i < 10; i++)
    VECTOR(types)[i] = (i >= 5);
  igraph_vector_long_init(&matching, 0);
  igraph_vector_init_copy(&weights, weight_array,
      sizeof(weight_array) / sizeof(weight_array[0]));

  igraph_maximum_bipartite_matching(&graph, &types, &matching_size,
      &matching_weight, &matching, &weights, 0);
  if (matching_size != 4) {
    printf("matching_size is %ld, expected: 4\n", (long)matching_size);
    return 1;
  }
  if (matching_weight != 19) {
    printf("matching_weight is %ld, expected: 19\n", (long)matching_weight);
    return 2;
  }
  igraph_is_maximal_matching(&graph, &types, &matching, &is_matching);
  if (!is_matching) {
    printf("not a matching: ");
    igraph_vector_long_print(&matching);
    return 3;
  }
  
  igraph_vector_destroy(&weights);
  igraph_vector_long_destroy(&matching);
  igraph_vector_bool_destroy(&types);
  igraph_destroy(&graph);

  return 0;
}

int test_weighted_graph_generated() {
  /* Several randomly generated small test graphs */
  igraph_t graph;
  igraph_vector_bool_t types;
  igraph_vector_long_t matching;
  igraph_vector_t weights;
  igraph_integer_t matching_size;
  igraph_real_t matching_weight;
  igraph_real_t weight_array_1[] = { 8, 5, 9, 18, 20, 13 };
  igraph_real_t weight_array_2[] = { 20, 4, 20, 3, 13, 1 };
  int i;

  igraph_vector_bool_init(&types, 10);
  for (i = 0; i < 10; i++)
    VECTOR(types)[i] = (i >= 5);
  igraph_vector_long_init(&matching, 0);

  /* Case 1 */

  igraph_small(&graph, 0, 0, 0, 8, 2, 7, 3, 7, 3, 8, 4, 5, 4, 9, -1);
  igraph_vector_init_copy(&weights, weight_array_1,
      sizeof(weight_array_1) / sizeof(weight_array_1[0]));
  igraph_maximum_bipartite_matching(&graph, &types, &matching_size,
      &matching_weight, &matching, &weights, 0);
  if (matching_weight != 43) {
    printf("matching_weight is %ld, expected: 43\n", (long)matching_weight);
    return 2;
  }
  igraph_vector_destroy(&weights);
  igraph_destroy(&graph);

  /* Case 2 */

  igraph_small(&graph, 0, 0, 0, 5, 0, 6, 1, 7, 2, 5, 3, 5, 3, 9, -1);
  igraph_vector_init_copy(&weights, weight_array_2,
      sizeof(weight_array_2) / sizeof(weight_array_2[0]));
  igraph_maximum_bipartite_matching(&graph, &types, &matching_size,
      &matching_weight, &matching, &weights, 0);
  if (matching_weight != 41) {
    printf("matching_weight is %ld, expected: 41\n", (long)matching_weight);
    return 2;
  }
  igraph_vector_destroy(&weights);
  igraph_destroy(&graph);

  igraph_vector_long_destroy(&matching);
  igraph_vector_bool_destroy(&types);

  return 0;
}

int test_weighted_graph_from_file(const char* fname, int type1_count, long exp_weight) {
  igraph_t graph;
  igraph_vector_bool_t types;
  igraph_vector_long_t matching;
  igraph_vector_t weights;
  igraph_real_t matching_weight;
  FILE* f;
  int i, n;

  f = fopen(fname, "r");
  if (!f) {
    fprintf(stderr, "No such file: %s\n", fname);
    return 1;
  }
  igraph_read_graph_ncol(&graph, f, 0, 1, 1, 0);
  fclose(f);

  n = igraph_vcount(&graph);
  igraph_vector_bool_init(&types, n);
  for (i = 0; i < n; i++) {
    VECTOR(types)[i] = (i >= type1_count);
  }

  igraph_vector_long_init(&matching, 0);

  igraph_vector_init(&weights, 0);
  EANV(&graph, "weight", &weights);
  igraph_maximum_bipartite_matching(&graph, &types, 0, &matching_weight,
      &matching, &weights, 0);
  igraph_vector_destroy(&weights);

  igraph_vector_long_print(&matching);
  if (matching_weight != exp_weight) {
    printf("matching_weight is %ld, expected: %ld\n", (long)matching_weight,
        (long)exp_weight);
    return 2;
  }

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

int main() {
  igraph_i_set_attribute_table(&igraph_cattribute_table);

  if (test_graph_from_leda_tutorial())
    return 1;

  if (test_weighted_graph_from_mit_notes())
    return 2;

  if (test_weighted_graph_generated())
    return 3;

  if (!IGRAPH_FINALLY_STACK_EMPTY) {
    printf("Finally stack still has %d elements.\n", IGRAPH_FINALLY_STACK_SIZE());
    return 4;
  }

  return 0;
}


19.2. igraph_is_maximal_matching — Checks whether a matching in a graph is maximal.

int igraph_is_maximal_matching(const igraph_t* graph,
    const igraph_vector_bool_t* types, const igraph_vector_long_t* matching,
    igraph_bool_t* result);

A matching is maximal if and only if there exists no unmatched vertex in a graph such that one of its neighbors is also unmatched.

Arguments: 

graph:

The input graph. It can be directed but the edge directions will be ignored.

types:

If the graph is bipartite and you are interested in bipartite matchings only, pass the vertex types here. If the graph is non-bipartite, simply pass NULL.

matching:

The matching itself. It must be a vector where element i contains the ID of the vertex that vertex i is matched to, or -1 if vertex i is unmatched.

result:

Pointer to a boolean variable, the result will be returned here.

See also: 

igraph_is_matching() if you are only interested in whether a matching vector is valid for a given graph.

Time complexity: O(|V|+|E|) where |V| is the number of vertices and |E| is the number of edges.

Example 13.42.  File examples/simple/igraph_maximum_bipartite_matching.c

/* -*- mode: C -*-  */
/* vim:set ts=2 sw=2 sts=2 et: */
/* 
   IGraph library.
   Copyright (C) 2012  Tamas Nepusz <ntamas@gmail.com>
   
   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.h>
#include <stdio.h>

int test_graph_from_leda_tutorial() {
  /* Test graph from the LEDA tutorial:
   * http://www.leda-tutorial.org/en/unofficial/ch05s03s05.html
   */
  igraph_t graph;
  igraph_vector_bool_t types;
  igraph_vector_long_t matching;
  igraph_integer_t matching_size;
  igraph_real_t matching_weight;
  igraph_bool_t is_matching;
  int i;

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

  igraph_maximum_bipartite_matching(&graph, &types, &matching_size,
      &matching_weight, &matching, 0, 0);
  if (matching_size != 6) {
    printf("matching_size is %ld, expected: 6\n", (long)matching_size);
    return 1;
  }
  if (matching_weight != 6) {
    printf("matching_weight is %ld, expected: 6\n", (long)matching_weight);
    return 2;
  }
  igraph_is_maximal_matching(&graph, &types, &matching, &is_matching);
  if (!is_matching) {
    printf("not a matching: ");
    igraph_vector_long_print(&matching);
    return 3;
  }

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

  return 0;
}

int test_weighted_graph_from_mit_notes() {
  /* Test graph from the following lecture notes:
   * http://math.mit.edu/~goemans/18433S07/matching-notes.pdf
   */
  igraph_t graph;
  igraph_vector_bool_t types;
  igraph_vector_long_t matching;
  igraph_vector_t weights;
  igraph_integer_t matching_size;
  igraph_real_t matching_weight;
  igraph_bool_t is_matching;
  igraph_real_t weight_array[] = { 2, 7, 2, 3,
      1, 3, 9, 3, 3,
      1, 3, 3, 1, 2,
      4, 1, 2,
      3 };
  int i;

  igraph_small(&graph, 0, 0,
      0, 6, 0, 7, 0, 8, 0, 9,
      1, 5, 1, 6, 1, 7, 1, 8, 1, 9,
      2, 5, 2, 6, 2, 7, 2, 8, 2, 9,
      3, 5, 3, 7, 3, 9,
      4, 7, -1);
  igraph_vector_bool_init(&types, 10);
  for (i = 0; i < 10; i++)
    VECTOR(types)[i] = (i >= 5);
  igraph_vector_long_init(&matching, 0);
  igraph_vector_init_copy(&weights, weight_array,
      sizeof(weight_array) / sizeof(weight_array[0]));

  igraph_maximum_bipartite_matching(&graph, &types, &matching_size,
      &matching_weight, &matching, &weights, 0);
  if (matching_size != 4) {
    printf("matching_size is %ld, expected: 4\n", (long)matching_size);
    return 1;
  }
  if (matching_weight != 19) {
    printf("matching_weight is %ld, expected: 19\n", (long)matching_weight);
    return 2;
  }
  igraph_is_maximal_matching(&graph, &types, &matching, &is_matching);
  if (!is_matching) {
    printf("not a matching: ");
    igraph_vector_long_print(&matching);
    return 3;
  }
  
  igraph_vector_destroy(&weights);
  igraph_vector_long_destroy(&matching);
  igraph_vector_bool_destroy(&types);
  igraph_destroy(&graph);

  return 0;
}

int test_weighted_graph_generated() {
  /* Several randomly generated small test graphs */
  igraph_t graph;
  igraph_vector_bool_t types;
  igraph_vector_long_t matching;
  igraph_vector_t weights;
  igraph_integer_t matching_size;
  igraph_real_t matching_weight;
  igraph_real_t weight_array_1[] = { 8, 5, 9, 18, 20, 13 };
  igraph_real_t weight_array_2[] = { 20, 4, 20, 3, 13, 1 };
  int i;

  igraph_vector_bool_init(&types, 10);
  for (i = 0; i < 10; i++)
    VECTOR(types)[i] = (i >= 5);
  igraph_vector_long_init(&matching, 0);

  /* Case 1 */

  igraph_small(&graph, 0, 0, 0, 8, 2, 7, 3, 7, 3, 8, 4, 5, 4, 9, -1);
  igraph_vector_init_copy(&weights, weight_array_1,
      sizeof(weight_array_1) / sizeof(weight_array_1[0]));
  igraph_maximum_bipartite_matching(&graph, &types, &matching_size,
      &matching_weight, &matching, &weights, 0);
  if (matching_weight != 43) {
    printf("matching_weight is %ld, expected: 43\n", (long)matching_weight);
    return 2;
  }
  igraph_vector_destroy(&weights);
  igraph_destroy(&graph);

  /* Case 2 */

  igraph_small(&graph, 0, 0, 0, 5, 0, 6, 1, 7, 2, 5, 3, 5, 3, 9, -1);
  igraph_vector_init_copy(&weights, weight_array_2,
      sizeof(weight_array_2) / sizeof(weight_array_2[0]));
  igraph_maximum_bipartite_matching(&graph, &types, &matching_size,
      &matching_weight, &matching, &weights, 0);
  if (matching_weight != 41) {
    printf("matching_weight is %ld, expected: 41\n", (long)matching_weight);
    return 2;
  }
  igraph_vector_destroy(&weights);
  igraph_destroy(&graph);

  igraph_vector_long_destroy(&matching);
  igraph_vector_bool_destroy(&types);

  return 0;
}

int test_weighted_graph_from_file(const char* fname, int type1_count, long exp_weight) {
  igraph_t graph;
  igraph_vector_bool_t types;
  igraph_vector_long_t matching;
  igraph_vector_t weights;
  igraph_real_t matching_weight;
  FILE* f;
  int i, n;

  f = fopen(fname, "r");
  if (!f) {
    fprintf(stderr, "No such file: %s\n", fname);
    return 1;
  }
  igraph_read_graph_ncol(&graph, f, 0, 1, 1, 0);
  fclose(f);

  n = igraph_vcount(&graph);
  igraph_vector_bool_init(&types, n);
  for (i = 0; i < n; i++) {
    VECTOR(types)[i] = (i >= type1_count);
  }

  igraph_vector_long_init(&matching, 0);

  igraph_vector_init(&weights, 0);
  EANV(&graph, "weight", &weights);
  igraph_maximum_bipartite_matching(&graph, &types, 0, &matching_weight,
      &matching, &weights, 0);
  igraph_vector_destroy(&weights);

  igraph_vector_long_print(&matching);
  if (matching_weight != exp_weight) {
    printf("matching_weight is %ld, expected: %ld\n", (long)matching_weight,
        (long)exp_weight);
    return 2;
  }

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

int main() {
  igraph_i_set_attribute_table(&igraph_cattribute_table);

  if (test_graph_from_leda_tutorial())
    return 1;

  if (test_weighted_graph_from_mit_notes())
    return 2;

  if (test_weighted_graph_generated())
    return 3;

  if (!IGRAPH_FINALLY_STACK_EMPTY) {
    printf("Finally stack still has %d elements.\n", IGRAPH_FINALLY_STACK_SIZE());
    return 4;
  }

  return 0;
}


19.3. igraph_maximum_bipartite_matching — Calculates a maximum matching in a bipartite graph.

int igraph_maximum_bipartite_matching(const igraph_t* graph,
    const igraph_vector_bool_t* types, igraph_integer_t* matching_size,
    igraph_real_t* matching_weight, igraph_vector_long_t* matching,
    const igraph_vector_t* weights, igraph_real_t eps);

A matching in a bipartite graph is a partial assignment of vertices of the first kind to vertices of the second kind such that each vertex of the first kind is matched to at most one vertex of the second kind and vice versa, and matched vertices must be connected by an edge in the graph. The size (or cardinality) of a matching is the number of edges. A matching is a maximum matching if there exists no other matching with larger cardinality. For weighted graphs, a maximum matching is a matching whose edges have the largest possible total weight among all possible matchings.

Maximum matchings in bipartite graphs are found by the push-relabel algorithm with greedy initialization and a global relabeling after every n/2 steps where n is the number of vertices in the graph.

References: Cherkassky BV, Goldberg AV, Martin P, Setubal JC and Stolfi J: Augment or push: A computational study of bipartite matching and unit-capacity flow algorithms. ACM Journal of Experimental Algorithmics 3, 1998.

Kaya K, Langguth J, Manne F and Ucar B: Experiments on push-relabel-based maximum cardinality matching algorithms for bipartite graphs. Technical Report TR/PA/11/33 of the Centre Europeen de Recherche et de Formation Avancee en Calcul Scientifique, 2011.

Arguments: 

graph:

The input graph. It can be directed but the edge directions will be ignored.

types:

Boolean vector giving the vertex types of the graph.

matching_size:

The size of the matching (i.e. the number of matched vertex pairs will be returned here). It may be NULL if you don't need this.

matching_weight:

The weight of the matching if the edges are weighted, or the size of the matching again if the edges are unweighted. It may be NULL if you don't need this.

matching:

The matching itself. It must be a vector where element i contains the ID of the vertex that vertex i is matched to, or -1 if vertex i is unmatched.

weights:

A null pointer (=no edge weights), or a vector giving the weights of the edges. Note that the algorithm is stable only for integer weights.

eps:

A small real number used in equality tests in the weighted bipartite matching algorithm. Two real numbers are considered equal in the algorithm if their difference is smaller than eps. This is required to avoid the accumulation of numerical errors. It is advised to pass a value derived from the DBL_EPSILON constant in float.h here. If you are running the algorithm with no weights vector, this argument is ignored.

Returns: 

Error code.

Time complexity: O(sqrt(|V|) |E|) for unweighted graphs (according to the technical report referenced above), O(|V||E|) for weighted graphs.

Example 13.43.  File examples/simple/igraph_maximum_bipartite_matching.c

/* -*- mode: C -*-  */
/* vim:set ts=2 sw=2 sts=2 et: */
/* 
   IGraph library.
   Copyright (C) 2012  Tamas Nepusz <ntamas@gmail.com>
   
   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.h>
#include <stdio.h>

int test_graph_from_leda_tutorial() {
  /* Test graph from the LEDA tutorial:
   * http://www.leda-tutorial.org/en/unofficial/ch05s03s05.html
   */
  igraph_t graph;
  igraph_vector_bool_t types;
  igraph_vector_long_t matching;
  igraph_integer_t matching_size;
  igraph_real_t matching_weight;
  igraph_bool_t is_matching;
  int i;

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

  igraph_maximum_bipartite_matching(&graph, &types, &matching_size,
      &matching_weight, &matching, 0, 0);
  if (matching_size != 6) {
    printf("matching_size is %ld, expected: 6\n", (long)matching_size);
    return 1;
  }
  if (matching_weight != 6) {
    printf("matching_weight is %ld, expected: 6\n", (long)matching_weight);
    return 2;
  }
  igraph_is_maximal_matching(&graph, &types, &matching, &is_matching);
  if (!is_matching) {
    printf("not a matching: ");
    igraph_vector_long_print(&matching);
    return 3;
  }

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

  return 0;
}

int test_weighted_graph_from_mit_notes() {
  /* Test graph from the following lecture notes:
   * http://math.mit.edu/~goemans/18433S07/matching-notes.pdf
   */
  igraph_t graph;
  igraph_vector_bool_t types;
  igraph_vector_long_t matching;
  igraph_vector_t weights;
  igraph_integer_t matching_size;
  igraph_real_t matching_weight;
  igraph_bool_t is_matching;
  igraph_real_t weight_array[] = { 2, 7, 2, 3,
      1, 3, 9, 3, 3,
      1, 3, 3, 1, 2,
      4, 1, 2,
      3 };
  int i;

  igraph_small(&graph, 0, 0,
      0, 6, 0, 7, 0, 8, 0, 9,
      1, 5, 1, 6, 1, 7, 1, 8, 1, 9,
      2, 5, 2, 6, 2, 7, 2, 8, 2, 9,
      3, 5, 3, 7, 3, 9,
      4, 7, -1);
  igraph_vector_bool_init(&types, 10);
  for (i = 0; i < 10; i++)
    VECTOR(types)[i] = (i >= 5);
  igraph_vector_long_init(&matching, 0);
  igraph_vector_init_copy(&weights, weight_array,
      sizeof(weight_array) / sizeof(weight_array[0]));

  igraph_maximum_bipartite_matching(&graph, &types, &matching_size,
      &matching_weight, &matching, &weights, 0);
  if (matching_size != 4) {
    printf("matching_size is %ld, expected: 4\n", (long)matching_size);
    return 1;
  }
  if (matching_weight != 19) {
    printf("matching_weight is %ld, expected: 19\n", (long)matching_weight);
    return 2;
  }
  igraph_is_maximal_matching(&graph, &types, &matching, &is_matching);
  if (!is_matching) {
    printf("not a matching: ");
    igraph_vector_long_print(&matching);
    return 3;
  }
  
  igraph_vector_destroy(&weights);
  igraph_vector_long_destroy(&matching);
  igraph_vector_bool_destroy(&types);
  igraph_destroy(&graph);

  return 0;
}

int test_weighted_graph_generated() {
  /* Several randomly generated small test graphs */
  igraph_t graph;
  igraph_vector_bool_t types;
  igraph_vector_long_t matching;
  igraph_vector_t weights;
  igraph_integer_t matching_size;
  igraph_real_t matching_weight;
  igraph_real_t weight_array_1[] = { 8, 5, 9, 18, 20, 13 };
  igraph_real_t weight_array_2[] = { 20, 4, 20, 3, 13, 1 };
  int i;

  igraph_vector_bool_init(&types, 10);
  for (i = 0; i < 10; i++)
    VECTOR(types)[i] = (i >= 5);
  igraph_vector_long_init(&matching, 0);

  /* Case 1 */

  igraph_small(&graph, 0, 0, 0, 8, 2, 7, 3, 7, 3, 8, 4, 5, 4, 9, -1);
  igraph_vector_init_copy(&weights, weight_array_1,
      sizeof(weight_array_1) / sizeof(weight_array_1[0]));
  igraph_maximum_bipartite_matching(&graph, &types, &matching_size,
      &matching_weight, &matching, &weights, 0);
  if (matching_weight != 43) {
    printf("matching_weight is %ld, expected: 43\n", (long)matching_weight);
    return 2;
  }
  igraph_vector_destroy(&weights);
  igraph_destroy(&graph);

  /* Case 2 */

  igraph_small(&graph, 0, 0, 0, 5, 0, 6, 1, 7, 2, 5, 3, 5, 3, 9, -1);
  igraph_vector_init_copy(&weights, weight_array_2,
      sizeof(weight_array_2) / sizeof(weight_array_2[0]));
  igraph_maximum_bipartite_matching(&graph, &types, &matching_size,
      &matching_weight, &matching, &weights, 0);
  if (matching_weight != 41) {
    printf("matching_weight is %ld, expected: 41\n", (long)matching_weight);
    return 2;
  }
  igraph_vector_destroy(&weights);
  igraph_destroy(&graph);

  igraph_vector_long_destroy(&matching);
  igraph_vector_bool_destroy(&types);

  return 0;
}

int test_weighted_graph_from_file(const char* fname, int type1_count, long exp_weight) {
  igraph_t graph;
  igraph_vector_bool_t types;
  igraph_vector_long_t matching;
  igraph_vector_t weights;
  igraph_real_t matching_weight;
  FILE* f;
  int i, n;

  f = fopen(fname, "r");
  if (!f) {
    fprintf(stderr, "No such file: %s\n", fname);
    return 1;
  }
  igraph_read_graph_ncol(&graph, f, 0, 1, 1, 0);
  fclose(f);

  n = igraph_vcount(&graph);
  igraph_vector_bool_init(&types, n);
  for (i = 0; i < n; i++) {
    VECTOR(types)[i] = (i >= type1_count);
  }

  igraph_vector_long_init(&matching, 0);

  igraph_vector_init(&weights, 0);
  EANV(&graph, "weight", &weights);
  igraph_maximum_bipartite_matching(&graph, &types, 0, &matching_weight,
      &matching, &weights, 0);
  igraph_vector_destroy(&weights);

  igraph_vector_long_print(&matching);
  if (matching_weight != exp_weight) {
    printf("matching_weight is %ld, expected: %ld\n", (long)matching_weight,
        (long)exp_weight);
    return 2;
  }

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

int main() {
  igraph_i_set_attribute_table(&igraph_cattribute_table);

  if (test_graph_from_leda_tutorial())
    return 1;

  if (test_weighted_graph_from_mit_notes())
    return 2;

  if (test_weighted_graph_generated())
    return 3;

  if (!IGRAPH_FINALLY_STACK_EMPTY) {
    printf("Finally stack still has %d elements.\n", IGRAPH_FINALLY_STACK_SIZE());
    return 4;
  }

  return 0;
}


20. Line graphs

20.1. igraph_linegraph — Create the line graph of a graph.

int igraph_linegraph(const igraph_t *graph, igraph_t *linegraph);

The line graph L(G) of a G undirected graph is defined as follows. L(G) has one vertex for each edge in G and two vertices in L(G) are connected by an edge if their corresponding edges share an end point.

The line graph L(G) of a G directed graph is slightly different, L(G) has one vertex for each edge in G and two vertices in L(G) are connected by a directed edge if the target of the first vertex's corresponding edge is the same as the source of the second vertex's corresponding edge.

Edge i in the original graph will correspond to vertex i in the line graph.

The first version of this function was contributed by Vincent Matossian, thanks.

Arguments: 

graph:

The input graph, may be directed or undirected.

linegraph:

Pointer to an uninitialized graph object, the result is stored here.

Returns: 

Error code.

Time complexity: O(|V|+|E|), the number of edges plus the number of vertices.

21. Unfolding a graph into a tree

21.1. igraph_unfold_tree — Unfolding a graph into a tree, by possibly multiplicating its vertices.

int igraph_unfold_tree(const igraph_t *graph, igraph_t *tree,
		       igraph_neimode_t mode, const igraph_vector_t *roots,
		       igraph_vector_t *vertex_index);

A graph is converted into a tree (or forest, if it is unconnected), by performing a breadth-first search on it, and replicating vertices that were found a second, third, etc. time.

Arguments: 

graph:

The input graph, it can be either directed or undirected.

tree:

Pointer to an uninitialized graph object, the result is stored here.

mode:

For directed graphs; whether to follow paths along edge directions (IGRAPH_OUT), or the opposite (IGRAPH_IN), or ignore edge directions completely (IGRAPH_ALL). It is ignored for undirected graphs.

roots:

A numeric vector giving the root vertex, or vertices (if the graph is not connected), to start from.

vertex_index:

Pointer to an initialized vector, or a null pointer. If not a null pointer, then a mapping from the vertices in the new graph to the ones in the original is created here.

Returns: 

Error code.

Time complexity: O(n+m), linear in the number vertices and edges.

22. Other Operations

22.1. igraph_density — Calculate the density of a graph.

int igraph_density(const igraph_t *graph, igraph_real_t *res, 
		   igraph_bool_t loops);

The density of a graph is simply the ratio number of edges and the number of possible edges. Note that density is ill-defined for graphs with multiple and/or loop edges, so consider calling igraph_simplify() on the graph if you know that it contains multiple or loop edges.

Arguments: 

graph:

The input graph object.

res:

Pointer to a real number, the result will be stored here.

loops:

Logical constant, whether to include loops in the calculation. If this constant is TRUE then loop edges are thought to be possible in the graph (this does not necessarily mean that the graph really contains any loops). If this is FALSE then the result is only correct if the graph does not contain loops.

Returns: 

Error code.

Time complexity: O(1).

22.2. igraph_reciprocity — Calculates the reciprocity of a directed graph.

int igraph_reciprocity(const igraph_t *graph, igraph_real_t *res, 
		       igraph_bool_t ignore_loops, 
		       igraph_reciprocity_t mode);

The measure of reciprocity defines the proportion of mutual connections, in a directed graph. It is most commonly defined as the probability that the opposite counterpart of a directed edge is also included in the graph. In adjacency matrix notation: sum(i, j, (A.*A')ij) / sum(i, j, Aij) , where A.*A' is the element-wise product of matrix A and its transpose. This measure is calculated if the mode argument is IGRAPH_RECIPROCITY_DEFAULT.

Prior to igraph version 0.6, another measure was implemented, defined as the probability of mutual connection between a vertex pair if we know that there is a (possibly non-mutual) connection between them. In other words, (unordered) vertex pairs are classified into three groups: (1) disconnected, (2) non-reciprocally connected, (3) reciprocally connected. The result is the size of group (3), divided by the sum of group sizes (2)+(3). This measure is calculated if mode is IGRAPH_RECIPROCITY_RATIO.

Arguments: 

graph:

The graph object.

res:

Pointer to an igraph_real_t which will contain the result.

ignore_loops:

Whether to ignore loop edges.

mode:

Type of reciprocity to calculate, possible values are IGRAPH_RECIPROCITY_DEFAULT and IGRAPH_RECIPROCITY_RATIO, please see their description above.

Returns: 

Error code: IGRAPH_EINVAL: graph has no edges IGRAPH_ENOMEM: not enough memory for temporary data.

Time complexity: O(|V|+|E|), |V| is the number of vertices, |E| is the number of edges.

Example 13.44.  File examples/simple/igraph_reciprocity.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>
#include <math.h>

int main() {
  
  igraph_t g;
  igraph_real_t res;

  /* Trivial cases */

  igraph_ring(&g, 100, IGRAPH_UNDIRECTED, 0, 0);
  igraph_reciprocity(&g, &res, 0, IGRAPH_RECIPROCITY_DEFAULT);
  igraph_destroy(&g);

  if (res != 1) {
    return 1;
  }

  /* Small test graph */

  igraph_small(&g, 0, IGRAPH_DIRECTED, 
	       0,  1,  0,  2,  0,  3,  1,  0,  2,  3,  3,  2, -1);
  
  igraph_reciprocity(&g, &res, 0, IGRAPH_RECIPROCITY_RATIO);
  igraph_destroy(&g);

  if (res != 0.5) {
    fprintf(stderr, "%f != %f\n", res, 0.5);
    return 2;
  }

  igraph_small(&g, 0, IGRAPH_DIRECTED, 0,1,1,2,2,1, -1);
  igraph_reciprocity(&g, &res, 0, IGRAPH_RECIPROCITY_DEFAULT);
  igraph_destroy(&g);
  
  if (fabs(res - 2.0/3.0) > 1e-15) {
    fprintf(stderr, "%f != %f\n", res, 2.0/3.0);
    return 3;
  }

  return 0;
}


22.3. igraph_diversity — Structural diversity index of the vertices

int igraph_diversity(igraph_t *graph, const igraph_vector_t *weights,
		     igraph_vector_t *res, const igraph_vs_t vids);

This measure was defined in Nathan Eagle, Michael Macy and Rob Claxton: Network Diversity and Economic Development, Science 328, 1029--1031, 2010.

It is simply the (normalized) Shannon entropy of the incident edges' weights. D(i)=H(i)/log(k[i]), and H(i) = -sum(p[i,j] log(p[i,j]), j=1..k[i]), where p[i,j]=w[i,j]/sum(w[i,l], l=1..k[i]), k[i] is the (total) degree of vertex i, and w[i,j] is the weight of the edge(s) between vertex i and j.

Arguments: 

graph:

The input graph, edge directions are ignored.

weights:

The edge weights, in the order of the edge ids, must have appropriate length.

res:

An initialized vector, the results are stored here.

vids:

Vector with the vertex ids for which to calculate the measure.

Returns: 

Error code.

Time complexity: O(|V|+|E|), linear.

22.4. igraph_is_mutual — Check whether the edges of a directed graph are mutual.

int igraph_is_mutual(igraph_t *graph, igraph_vector_bool_t *res, igraph_es_t es);

An (A,B) edge is mutual if the graph contains the (B,A) edge, too.

An undirected graph only has mutual edges, by definition.

Edge multiplicity is not considered here, e.g. if there are two (A,B) edges and one (B,A) edge, then all three are considered to be mutual.

Arguments: 

graph:

The input graph.

res:

Pointer to an initialized vector, the result is stored here.

es:

The sequence of edges to check. Supply igraph_ess_all() for all edges, see igraph_ess_all().

Returns: 

Error code.

Time complexity: O(n log(d)), n is the number of edges supplied, d is the maximum in-degree of the vertices that are targets of the supplied edges. An upper limit of the time complexity is O(n log(|E|)), |E| is the number of edges in the graph.

22.5. igraph_avg_nearest_neighbor_degree — Average nearest neighbor degree.

int igraph_avg_nearest_neighbor_degree(const igraph_t *graph,
				       igraph_vs_t vids,
				       igraph_vector_t *knn,
				       igraph_vector_t *knnk, 
				       const igraph_vector_t *weights);

Calculates the average degree of the neighbors for each vertex, and optionally, the same quantity in the function of vertex degree.

For isolate vertices knn is set to IGRAPH_NAN. The same is done in knnk for vertex degrees that don't appear in the graph.

Arguments: 

graph:

The input graph, it can be directed but the directedness of the edges is ignored.

vids:

The vertices for which the calculation is performed.

knn:

Pointer to an initialized vector, the result will be stored here. It will be resized as needed. Supply a NULL pointer here, if you only want to calculate knnk.

knnk:

Pointer to an initialized vector, the average nearest neighbor degree in the function of vertex degree is stored here. The first (zeroth) element is for degree one vertices, etc. Supply a NULL pointer here if you don't want to calculate this.

weights:

Optional edge weights. Supply a null pointer here for the non-weighted version. If this is not a null pointer, then the strength of the vertices is used instead of the normal vertex degree, see igraph_strength().

Returns: 

Error code.

Time complexity: O(|V|+|E|), linear in the number of vertices and edges.

Example 13.45.  File examples/simple/igraph_knn.c

/* -*- mode: C -*-  */
/* 
   IGraph library.
   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>
   334 Harvard st, 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.h>

int main() {
  igraph_